From 3373f66ad19ab821635c72b48032925bf0c876e8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 30 Aug 2018 17:25:20 +0200 Subject: [PATCH 001/236] Version++ --- CHANGES.rst | 27 +++++++++++++++++++++++++++ matrix-sdk/build.gradle | 4 ++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index bfd65f7bc..2278a8ff9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,30 @@ +Changes to Matrix Android SDK in 0.9.10 (2018-XX-XX) +======================================================= + +Features: + - + +Improvements: + - + +Bugfix: + - + +API Change: + - + +Translations: + - + +Others: + - + +Build: + - + +Test: + - + Changes to Matrix Android SDK in 0.9.9 (2018-08-30) ======================================================= diff --git a/matrix-sdk/build.gradle b/matrix-sdk/build.gradle index f4b7ad972..a336199bf 100644 --- a/matrix-sdk/build.gradle +++ b/matrix-sdk/build.gradle @@ -14,8 +14,8 @@ android { defaultConfig { minSdkVersion 16 targetSdkVersion 26 - versionCode 909 - versionName "0.9.9" + versionCode 910 + versionName "0.9.10-dev" resValue "string", "flavor_description", "SDKApp" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } From 14e07dce734d3bc41b64ff68d2f777ae92e52bc8 Mon Sep 17 00:00:00 2001 From: Miguel Branco Date: Sat, 1 Sep 2018 11:24:05 +0000 Subject: [PATCH 002/236] Translated using Weblate (Galician) Currently translated at 100.0% (59 of 59 strings) Translation: Riot Android/matrix-android-sdk Translate-URL: https://translate.riot.im/projects/riot-android/matrix-android-sdk/gl/ --- matrix-sdk/src/main/res/values-gl/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/matrix-sdk/src/main/res/values-gl/strings.xml b/matrix-sdk/src/main/res/values-gl/strings.xml index 4fa8e05e4..5110fb773 100644 --- a/matrix-sdk/src/main/res/values-gl/strings.xml +++ b/matrix-sdk/src/main/res/values-gl/strings.xml @@ -67,4 +67,9 @@ Número de teléfono +Responder a + enviar un vídeo. + enviar un ficheiro de son. + enviar un ficheiro. + From 3903fa0c3391034d07a4f35d76949b3d0f69f724 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 10 Aug 2018 18:15:58 +0200 Subject: [PATCH 003/236] Tests : create commons to manage all integration tests --- .../androidsdk/common/AbsIntegrationTest.java | 113 +++++++++ .../{ => common}/TestApiCallback.java | 9 +- .../{ => common}/TestConstants.java | 13 +- .../TestHelper.java} | 96 ++++--- .../AttachmentEncryptionTest.java | 5 +- .../{ => crypto}/CryptoRestTest.java | 74 ++---- .../androidsdk/{ => crypto}/CryptoTest.java | 236 ++++++++---------- .../{ => crypto}/ExportEncryptionTest.java | 5 +- 8 files changed, 320 insertions(+), 231 deletions(-) create mode 100644 matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/AbsIntegrationTest.java rename matrix-sdk/src/androidTest/java/org/matrix/androidsdk/{ => common}/TestApiCallback.java (91%) rename matrix-sdk/src/androidTest/java/org/matrix/androidsdk/{ => common}/TestConstants.java (64%) rename matrix-sdk/src/androidTest/java/org/matrix/androidsdk/{CryptoTestHelper.java => common/TestHelper.java} (68%) rename matrix-sdk/src/androidTest/java/org/matrix/androidsdk/{ => crypto}/AttachmentEncryptionTest.java (97%) rename matrix-sdk/src/androidTest/java/org/matrix/androidsdk/{ => crypto}/CryptoRestTest.java (76%) rename matrix-sdk/src/androidTest/java/org/matrix/androidsdk/{ => crypto}/CryptoTest.java (95%) rename matrix-sdk/src/androidTest/java/org/matrix/androidsdk/{ => crypto}/ExportEncryptionTest.java (98%) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/AbsIntegrationTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/AbsIntegrationTest.java new file mode 100644 index 000000000..7fae5bbc0 --- /dev/null +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/AbsIntegrationTest.java @@ -0,0 +1,113 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.common; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.test.InstrumentationRegistry; + +import org.junit.Assert; +import org.matrix.androidsdk.HomeServerConnectionConfig; +import org.matrix.androidsdk.MXSession; +import org.matrix.androidsdk.rest.model.login.Credentials; + +import java.util.UUID; + +/** + * This class is the parent class test for integration test cases + * It exposes methods to create and log into Alice, Bob and Sam accounts. + */ +public class AbsIntegrationTest { + + + private TestHelper mTestHelper = new TestHelper(); + + protected HomeServerConnectionConfig createHomeServerConfig(@Nullable Credentials credentials) { + return mTestHelper.createHomeServerConfig(credentials); + } + + protected MXSession createBobAccount(boolean withInitialSync, boolean enableCrypto) { + return createAccount(TestConstants.BOB_USER_ID, TestConstants.BOB_PWD, withInitialSync, enableCrypto); + } + + protected MXSession createAliceAccount(boolean withInitialSync, boolean enableCrypto) { + return createAccount(TestConstants.ALICE_USER_ID, TestConstants.ALICE_PWD, withInitialSync, enableCrypto); + } + + protected MXSession createSamAccount(boolean withInitialSync, boolean enableCrypto) { + return createAccount(TestConstants.SAM_USER_ID, TestConstants.SAM_PWD, withInitialSync, enableCrypto); + } + + protected MXSession logIntoBobAccount(final String bobUserId, final boolean withInitialSync, boolean enableCrypto) { + return logIntoAccount(bobUserId, TestConstants.BOB_PWD, withInitialSync, enableCrypto); + } + + protected MXSession logIntoAliceAccount(final String aliceUserId, final boolean withInitialSync, boolean enableCrypto) { + return logIntoAccount(aliceUserId, TestConstants.ALICE_PWD, withInitialSync, enableCrypto); + } + + protected MXSession logIntoSamAccount(final String samUserId, final boolean withInitialSync, boolean enableCrypto) { + return logIntoAccount(samUserId, TestConstants.SAM_PWD, withInitialSync, enableCrypto); + } + + // PRIVATE METHODS ***************************************************************************** + + /** + * Creates a unique account + * + * @param userId the base userId + * @param password the password + * @param withInitialSync true to perform an initial sync + * @param enableCrypto true to set enableCryptoWhenStarting + * @return the session associated with the newly created account + */ + private MXSession createAccount(@NonNull final String userId, + @NonNull final String password, + final boolean withInitialSync, + final boolean enableCrypto) { + final Context context = InstrumentationRegistry.getContext(); + final MXSession session = mTestHelper.createAccountAndSync( + context, + userId + System.currentTimeMillis() + UUID.randomUUID(), + password, + withInitialSync, + enableCrypto + ); + Assert.assertNotNull(session); + return session; + } + + /** + * Logs into an existing account + * + * @param userId the userId to log in + * @param password the password to log in + * @param withInitialSync true to perform an initial sync + * @param enableCrypto true to set enableCryptoWhenStarting + * @return the session associated with the existing account + */ + private MXSession logIntoAccount(@NonNull final String userId, + @NonNull final String password, + final boolean withInitialSync, + final boolean enableCrypto) { + final Context context = InstrumentationRegistry.getContext(); + final MXSession session = mTestHelper.logAccountAndSync(context, userId, password, withInitialSync, enableCrypto); + Assert.assertNotNull(session); + return session; + } +} diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/TestApiCallback.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestApiCallback.java similarity index 91% rename from matrix-sdk/src/androidTest/java/org/matrix/androidsdk/TestApiCallback.java rename to matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestApiCallback.java index a8a864b45..50022447e 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/TestApiCallback.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestApiCallback.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.androidsdk; +package org.matrix.androidsdk.common; import android.support.annotation.CallSuper; import android.support.annotation.NonNull; @@ -30,12 +30,12 @@ * * @param */ -class TestApiCallback implements ApiCallback { +public class TestApiCallback implements ApiCallback { @NonNull private final CountDownLatch mCountDownLatch; - TestApiCallback(@NonNull CountDownLatch countDownLatch) { + public TestApiCallback(@NonNull CountDownLatch countDownLatch) { mCountDownLatch = countDownLatch; } @@ -49,7 +49,6 @@ public void onSuccess(T info) { @Override public void onNetworkError(Exception e) { Log.e("TestApiCallback", e.getMessage(), e); - mCountDownLatch.countDown(); } @@ -57,7 +56,6 @@ public void onNetworkError(Exception e) { @Override public void onMatrixError(MatrixError e) { Log.e("TestApiCallback", e.getMessage() + " " + e.errcode); - mCountDownLatch.countDown(); } @@ -65,7 +63,6 @@ public void onMatrixError(MatrixError e) { @Override public void onUnexpectedError(Exception e) { Log.e("TestApiCallback", e.getMessage(), e); - mCountDownLatch.countDown(); } } diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/TestConstants.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java similarity index 64% rename from matrix-sdk/src/androidTest/java/org/matrix/androidsdk/TestConstants.java rename to matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java index a6e3a36d1..285e17a8b 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/TestConstants.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java @@ -14,9 +14,18 @@ * limitations under the License. */ -package org.matrix.androidsdk; +package org.matrix.androidsdk.common; -class TestConstants { +public class TestConstants { // Time out to use when waiting for server response public static final int AWAIT_TIME_OUT_MILLIS = 30000; + + public static final String BOB_USER_ID = "mxBob"; + public static final String BOB_PWD = "bobbob"; + + public static final String ALICE_USER_ID = "mxAlice"; + public static final String ALICE_PWD = "alicealice"; + + public static final String SAM_USER_ID = "mxSam"; + public static final String SAM_PWD = "samsam"; } \ No newline at end of file diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/CryptoTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestHelper.java similarity index 68% rename from matrix-sdk/src/androidTest/java/org/matrix/androidsdk/CryptoTestHelper.java rename to matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestHelper.java index ebbcbba9d..c5597fef4 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/CryptoTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestHelper.java @@ -15,13 +15,16 @@ * limitations under the License. */ -package org.matrix.androidsdk; +package org.matrix.androidsdk.common; import android.content.Context; import android.net.Uri; import android.support.annotation.Nullable; import org.junit.Assert; +import org.matrix.androidsdk.HomeServerConnectionConfig; +import org.matrix.androidsdk.MXDataHandler; +import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.data.store.MXFileStore; import org.matrix.androidsdk.listeners.MXEventListener; @@ -37,7 +40,9 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -public class CryptoTestHelper { + +public class TestHelper { + private static final String TESTS_HOME_SERVER_URL = "http://10.0.2.2:8080"; /** @@ -46,13 +51,10 @@ public class CryptoTestHelper { * @param credentials * @return */ - public static HomeServerConnectionConfig createHomeServerConfig(@Nullable Credentials credentials) { - HomeServerConnectionConfig hs = new HomeServerConnectionConfig(Uri.parse(TESTS_HOME_SERVER_URL)); - + HomeServerConnectionConfig createHomeServerConfig(@Nullable Credentials credentials) { + final HomeServerConnectionConfig hs = new HomeServerConnectionConfig(Uri.parse(TESTS_HOME_SERVER_URL)); hs.allowHttpConnection(); - hs.setCredentials(credentials); - return hs; } @@ -63,15 +65,15 @@ public static HomeServerConnectionConfig createHomeServerConfig(@Nullable Creden * @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 + * @param enableCrypto true to set enableCryptoWhenStarting */ - public static MXSession createAccountAndSync(Context context, String userName, String password, boolean startSession) throws Exception { - HomeServerConnectionConfig hs = createHomeServerConfig(null); + MXSession createAccountAndSync(Context context, String userName, String password, boolean startSession, boolean enableCrypto) { + final HomeServerConnectionConfig hs = createHomeServerConfig(null); - LoginRestClient loginRestClient = new LoginRestClient(hs); + final LoginRestClient loginRestClient = new LoginRestClient(hs); final Map params = new HashMap<>(); - RegistrationParams registrationParams = new RegistrationParams(); + final RegistrationParams registrationParams = new RegistrationParams(); CountDownLatch lock = new CountDownLatch(1); @@ -99,9 +101,13 @@ public void onMatrixError(MatrixError e) { } }); - lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + try { + lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { - String session = (String) params.get("session"); + } + + final String session = (String) params.get("session"); Assert.assertNotNull(session); @@ -122,7 +128,11 @@ public void onSuccess(Credentials credentials) { } }); - lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + try { + lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } Credentials credentials = (Credentials) params.get("credentials"); @@ -132,8 +142,11 @@ public void onSuccess(Credentials credentials) { IMXStore store = new MXFileStore(hs, context); - MXSession mxSession = new MXSession.Builder(hs, new MXDataHandler(store, credentials), context) - .build(); + MXSession mxSession = new MXSession(hs, new MXDataHandler(store, credentials), context); + + if (enableCrypto) { + mxSession.enableCryptoWhenStarting(); + } if (!startSession) { return mxSession; @@ -151,7 +164,11 @@ public void onInitialSyncComplete(String toToken) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + try { + lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } Assert.assertTrue(params.containsKey("isInit")); @@ -161,18 +178,16 @@ public void onInitialSyncComplete(String toToken) { /** * Start an account login * - * @param context the context - * @param userName the account username - * @param password the password - * @throws Exception an exception if the account cannot be synced + * @param context the context + * @param userName the account username + * @param password the password + * @param withInitialSync true to perform an initial sync + * @param enableCrypto true to set enableCryptoWhenStarting */ - public static MXSession logAccountAndSync(Context context, String userName, String password) throws Exception { - HomeServerConnectionConfig hs = createHomeServerConfig(null); - + MXSession logAccountAndSync(Context context, String userName, String password, boolean withInitialSync, boolean enableCrypto) { + final HomeServerConnectionConfig hs = createHomeServerConfig(null); LoginRestClient loginRestClient = new LoginRestClient(hs); - final Map params = new HashMap<>(); - CountDownLatch lock = new CountDownLatch(1); // get the registration session id @@ -184,20 +199,29 @@ public void onSuccess(Credentials credentials) { } }); - lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + try { + lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } - Credentials credentials = (Credentials) params.get("credentials"); + final Credentials credentials = (Credentials) params.get("credentials"); Assert.assertNotNull(credentials); hs.setCredentials(credentials); - IMXStore store = new MXFileStore(hs, context); + final IMXStore store = new MXFileStore(hs, context); - MXSession mxSession = new MXSession.Builder(hs, new MXDataHandler(store, credentials), context) - .build(); + final MXSession mxSession = new MXSession(hs, new MXDataHandler(store, credentials), context); - mxSession.enableCryptoWhenStarting(); + if (enableCrypto) { + mxSession.enableCryptoWhenStarting(); + } + + if (!withInitialSync) { + return mxSession; + } final CountDownLatch lock2 = new CountDownLatch(2); mxSession.getDataHandler().addListener(new MXEventListener() { @@ -217,7 +241,11 @@ public void onCryptoSyncComplete() { mxSession.getDataHandler().getStore().open(); mxSession.startEventStream(null); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + try { + lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } Assert.assertTrue(params.containsKey("isInit")); Assert.assertTrue(params.containsKey("onCryptoSyncComplete")); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/AttachmentEncryptionTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/AttachmentEncryptionTest.java similarity index 97% rename from matrix-sdk/src/androidTest/java/org/matrix/androidsdk/AttachmentEncryptionTest.java rename to matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/AttachmentEncryptionTest.java index fa9a88ff7..e90cf4bdf 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/AttachmentEncryptionTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/AttachmentEncryptionTest.java @@ -1,4 +1,4 @@ -package org.matrix.androidsdk; +package org.matrix.androidsdk.crypto; import android.os.MemoryFile; import android.support.test.runner.AndroidJUnit4; @@ -9,6 +9,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; +import org.matrix.androidsdk.common.AbsIntegrationTest; import org.matrix.androidsdk.crypto.MXEncryptedAttachments; import org.matrix.androidsdk.rest.model.crypto.EncryptedFileInfo; import org.matrix.androidsdk.rest.model.crypto.EncryptedFileKey; @@ -24,7 +25,7 @@ */ @RunWith(AndroidJUnit4.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class AttachmentEncryptionTest { +public class AttachmentEncryptionTest extends AbsIntegrationTest { private String checkDecryption(String input, EncryptedFileInfo encryptedFileInfo) throws Exception { byte[] in = Base64.decode(input, Base64.DEFAULT); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/CryptoRestTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java similarity index 76% rename from matrix-sdk/src/androidTest/java/org/matrix/androidsdk/CryptoRestTest.java rename to matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java index 35725bef4..63603bfeb 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/CryptoRestTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.matrix.androidsdk; +package org.matrix.androidsdk.crypto; import android.content.Context; import android.support.test.InstrumentationRegistry; @@ -26,6 +26,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; +import org.matrix.androidsdk.MXSession; +import org.matrix.androidsdk.common.AbsIntegrationTest; +import org.matrix.androidsdk.common.TestApiCallback; +import org.matrix.androidsdk.common.TestConstants; +import org.matrix.androidsdk.common.TestHelper; import org.matrix.androidsdk.crypto.MXCryptoAlgorithms; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXKey; @@ -44,44 +49,18 @@ @RunWith(AndroidJUnit4.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class CryptoRestTest { - - private static final String MXTESTS_BOB = "mxBob"; - private static final String MXTESTS_BOB_PWD = "bobbob"; - - private static final String MXTESTS_ALICE = "mxAlice"; - private static final String MXTESTS_ALICE_PWD = "alicealice"; - - private MXSession mBobSession; - private MXSession mAliceSession; - - private void createBobAccount() throws Exception { - Context context = InstrumentationRegistry.getContext(); - mBobSession = null; - mBobSession = CryptoTestHelper.createAccountAndSync(context, - MXTESTS_BOB + System.currentTimeMillis() + UUID.randomUUID().toString(), MXTESTS_BOB_PWD, true); - Assert.assertNotNull(mBobSession); - } - - public void createAliceAccount() throws Exception { - Context context = InstrumentationRegistry.getContext(); - mAliceSession = null; - mAliceSession = CryptoTestHelper.createAccountAndSync(context, - MXTESTS_ALICE + System.currentTimeMillis() + UUID.randomUUID().toString(), MXTESTS_ALICE_PWD, true); - Assert.assertNotNull(mAliceSession); - } +public class CryptoRestTest extends AbsIntegrationTest { @Test public void test01_testDeviceKeys() throws Exception { Context context = InstrumentationRegistry.getContext(); - - createBobAccount(); + final MXSession bobSession = createBobAccount(true, false); final Map results = new HashMap<>(); String ed25519key = "wV5E3EUSHpHuoZLljNzojlabjGdXT3Mz7rugG9zgbkI"; MXDeviceInfo bobDevice = new MXDeviceInfo("dev1"); - bobDevice.userId = mBobSession.getMyUserId(); + bobDevice.userId = bobSession.getMyUserId(); bobDevice.algorithms = Arrays.asList(MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_OLM); Map keysMap = new HashMap(); @@ -89,7 +68,7 @@ public void test01_testDeviceKeys() throws Exception { bobDevice.keys = keysMap; CountDownLatch lock0 = new CountDownLatch(1); - mBobSession.getCryptoRestClient().uploadKeys(bobDevice.JSONDictionary(), null, "dev1", new TestApiCallback(lock0) { + bobSession.getCryptoRestClient().uploadKeys(bobDevice.JSONDictionary(), null, "dev1", new TestApiCallback(lock0) { @Override public void onSuccess(KeysUploadResponse keysUploadResponse) { results.put("keysUploadResponse", keysUploadResponse); @@ -107,7 +86,7 @@ public void onSuccess(KeysUploadResponse keysUploadResponse) { Assert.assertEquals(0, keysUploadResponse.oneTimeKeyCountsForAlgorithm("deded")); CountDownLatch lock1 = new CountDownLatch(1); - mBobSession.getCryptoRestClient().downloadKeysForUsers(Arrays.asList(mBobSession.getMyUserId()), null, new TestApiCallback(lock1) { + bobSession.getCryptoRestClient().downloadKeysForUsers(Arrays.asList(bobSession.getMyUserId()), null, new TestApiCallback(lock1) { @Override public void onSuccess(KeysQueryResponse keysQueryResponse) { results.put("keysQueryResponse", keysQueryResponse); @@ -126,23 +105,22 @@ public void onSuccess(KeysQueryResponse keysQueryResponse) { Assert.assertNotNull(deviceInfos.getUserIds()); Assert.assertEquals(1, deviceInfos.getUserIds().size()); - List deviceIds = deviceInfos.getUserDeviceIds(mBobSession.getMyUserId()); + List deviceIds = deviceInfos.getUserDeviceIds(bobSession.getMyUserId()); Assert.assertNotNull(deviceIds); Assert.assertEquals(1, deviceIds.size()); - MXDeviceInfo bobDevice2 = deviceInfos.getObject("dev1", mBobSession.getMyUserId()); + MXDeviceInfo bobDevice2 = deviceInfos.getObject("dev1", bobSession.getMyUserId()); Assert.assertNotNull(bobDevice2); Assert.assertEquals("dev1", bobDevice2.deviceId); - Assert.assertEquals(bobDevice2.userId, mBobSession.getMyUserId()); - - mBobSession.clear(context); + Assert.assertEquals(bobDevice2.userId, bobSession.getMyUserId()); + bobSession.clear(context); } @Test public void test02_testOneTimeKeys() throws Exception { Context context = InstrumentationRegistry.getContext(); - createBobAccount(); + final MXSession bobSession = createBobAccount(true, false); final Map results = new HashMap<>(); final Map otks = new HashMap<>(); @@ -151,7 +129,7 @@ public void test02_testOneTimeKeys() throws Exception { otks.put("curve25519:AAAABA", "PmyaaB68Any+za9CuZXzFsQZW31s/TW6XbAB9akEpQs"); CountDownLatch lock1 = new CountDownLatch(1); - mBobSession.getCryptoRestClient().uploadKeys(null, otks, "dev1", new TestApiCallback(lock1) { + bobSession.getCryptoRestClient().uploadKeys(null, otks, "dev1", new TestApiCallback(lock1) { @Override public void onSuccess(KeysUploadResponse keysUploadResponse) { results.put("keysUploadResponse", keysUploadResponse); @@ -168,15 +146,15 @@ public void onSuccess(KeysUploadResponse keysUploadResponse) { Assert.assertEquals(2, keysUploadResponse.oneTimeKeyCountsForAlgorithm("curve25519")); Assert.assertEquals(0, keysUploadResponse.oneTimeKeyCountsForAlgorithm("deded")); - mBobSession.clear(context); + bobSession.clear(context); } @Test public void test03_testClaimOneTimeKeysForUsersDevices() throws Exception { Context context = InstrumentationRegistry.getContext(); - createBobAccount(); - createAliceAccount(); + final MXSession bobSession = createBobAccount(true, false); + final MXSession aliceSession = createAliceAccount(true, false); final Map results = new HashMap<>(); final Map otks = new HashMap<>(); @@ -208,7 +186,7 @@ public void test03_testClaimOneTimeKeysForUsersDevices() throws Exception { } CountDownLatch lock1 = new CountDownLatch(1); - mBobSession.getCryptoRestClient().uploadKeys(null, otks, "dev1", new TestApiCallback(lock1) { + bobSession.getCryptoRestClient().uploadKeys(null, otks, "dev1", new TestApiCallback(lock1) { @Override public void onSuccess(KeysUploadResponse keysUploadResponse) { results.put("keysUploadResponse", keysUploadResponse); @@ -222,10 +200,10 @@ public void onSuccess(KeysUploadResponse keysUploadResponse) { Assert.assertNotNull(bobKeysUploadResponse); MXUsersDevicesMap usersDevicesKeyTypesMap = new MXUsersDevicesMap<>(); - usersDevicesKeyTypesMap.setObject("curve25519", mBobSession.getMyUserId(), "dev1"); + usersDevicesKeyTypesMap.setObject("curve25519", bobSession.getMyUserId(), "dev1"); CountDownLatch lock2 = new CountDownLatch(1); - mAliceSession.getCryptoRestClient().claimOneTimeKeysForUsersDevices(usersDevicesKeyTypesMap, new TestApiCallback>(lock2) { + aliceSession.getCryptoRestClient().claimOneTimeKeysForUsersDevices(usersDevicesKeyTypesMap, new TestApiCallback>(lock2) { @Override public void onSuccess(MXUsersDevicesMap usersDevicesMap) { results.put("usersDevicesMap", usersDevicesMap); @@ -240,7 +218,7 @@ public void onSuccess(MXUsersDevicesMap usersDevicesMap) { Assert.assertNotNull(oneTimeKeys.getMap()); Assert.assertEquals(1, oneTimeKeys.getMap().size()); - MXKey bobOtk = oneTimeKeys.getObject("dev1", mBobSession.getMyUserId()); + MXKey bobOtk = oneTimeKeys.getObject("dev1", bobSession.getMyUserId()); Assert.assertNotNull(bobOtk); Assert.assertEquals(MXKey.KEY_CURVE_25519_TYPE, bobOtk.type); @@ -252,7 +230,7 @@ public void onSuccess(MXUsersDevicesMap usersDevicesMap) { List keys = new ArrayList<>(bobOtk.signatures.keySet()); Assert.assertEquals(1, keys.size()); - mBobSession.clear(context); - mAliceSession.clear(context); + bobSession.clear(context); + aliceSession.clear(context); } } diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java similarity index 95% rename from matrix-sdk/src/androidTest/java/org/matrix/androidsdk/CryptoTest.java rename to matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index f39e15d18..d201c1422 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -17,7 +17,7 @@ */ -package org.matrix.androidsdk; +package org.matrix.androidsdk.crypto; import android.content.Context; import android.os.SystemClock; @@ -33,10 +33,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; -import org.matrix.androidsdk.crypto.MXCrypto; -import org.matrix.androidsdk.crypto.MXCryptoAlgorithms; -import org.matrix.androidsdk.crypto.MXCryptoError; -import org.matrix.androidsdk.crypto.MXDeviceList; +import org.matrix.androidsdk.HomeServerConnectionConfig; +import org.matrix.androidsdk.MXDataHandler; +import org.matrix.androidsdk.MXSession; +import org.matrix.androidsdk.common.AbsIntegrationTest; +import org.matrix.androidsdk.common.TestApiCallback; +import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXOlmSessionResult; import org.matrix.androidsdk.crypto.data.MXUsersDevicesMap; @@ -63,27 +65,26 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class CryptoTest { +public class CryptoTest extends AbsIntegrationTest { private static final String LOG_TAG = "CryptoTest"; private static final List messagesFromAlice = Arrays.asList("0 - Hello I'm Alice!", "4 - Go!"); private static final List messagesFromBob = Arrays.asList("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera."); - private static final String MXTESTS_BOB = "mxBob"; - private static final String MXTESTS_BOB_PWD = "bobbob"; - - private static final String MXTESTS_ALICE = "mxAlice"; - private static final String MXTESTS_ALICE_PWD = "alicealice"; + private MXSession mBobSession; + private MXSession mAliceSession; + private MXSession mSamSession; - private static final String MXTESTS_SAM = "mxSam"; - private static final String MXTESTS_SAM_PWD = "samsam"; + private String mRoomId; + private int mMessagesCount; + private int mReceivedMessagesFromAlice; + private int mReceivedMessagesFromBob; @Test public void test01_testCryptoNoDeviceId() throws Exception { @@ -91,7 +92,7 @@ public void test01_testCryptoNoDeviceId() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - createBobAccount(); + mBobSession = createBobAccount(true, false); Assert.assertNull(mBobSession.getCrypto()); mBobSession.getCredentials().deviceId = null; @@ -119,7 +120,7 @@ public void test02_testCryptoPersistenceInStore() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - createBobAccount(); + mBobSession = createBobAccount(true, false); mBobSession.getCredentials().deviceId = "BobDevice"; Assert.assertNull(mBobSession.getCrypto()); @@ -149,12 +150,12 @@ public void onSuccess(Void info) { final Credentials bobCredentials = mBobSession.getCredentials(); - HomeServerConnectionConfig hs = CryptoTestHelper.createHomeServerConfig(bobCredentials); + HomeServerConnectionConfig hs = createHomeServerConfig(bobCredentials); IMXStore store = new MXFileStore(hs, context); - MXSession bobSession2 = new MXSession.Builder(hs, new MXDataHandler(store, bobCredentials), context) - .build(); + MXSession bobSession2 = new MXSession(hs, new MXDataHandler(store, bobCredentials), context); + final CountDownLatch lock1 = new CountDownLatch(1); MXStoreListener listener = new MXStoreListener() { @@ -229,7 +230,7 @@ public void test03_testKeysUploadAndDownload() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - createAliceAccount(); + mAliceSession = createAliceAccount(true, false); mAliceSession.getCredentials().deviceId = "AliceDevice"; CountDownLatch lock0 = new CountDownLatch(1); @@ -243,7 +244,7 @@ public void onSuccess(Void info) { lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("enableCrypto")); - createBobAccount(); + mBobSession = createBobAccount(true, false); CountDownLatch lock2 = new CountDownLatch(1); mBobSession.getCredentials().deviceId = "BobDevice"; mBobSession.enableCrypto(true, new TestApiCallback(lock2) { @@ -317,12 +318,11 @@ public void onSuccess(Void info) { Credentials bobCredentials = mBobSession.getCredentials(); - HomeServerConnectionConfig hs = CryptoTestHelper.createHomeServerConfig(bobCredentials); + HomeServerConnectionConfig hs = createHomeServerConfig(bobCredentials); IMXStore store = new MXFileStore(hs, context); - MXSession bobSession2 = new MXSession.Builder(hs, new MXDataHandler(store, bobCredentials), context) - .build(); + MXSession bobSession2 = new MXSession(hs, new MXDataHandler(store, bobCredentials), context); final CountDownLatch lock4 = new CountDownLatch(1); @@ -416,7 +416,7 @@ public void test04_testEnsureOlmSessionsForUsers() throws Exception { Context context = InstrumentationRegistry.getContext(); - createAliceAccount(); + mAliceSession = createAliceAccount(true, false); final Map results = new HashMap<>(); mAliceSession.getCredentials().deviceId = "AliceDevice"; @@ -434,7 +434,7 @@ public void onSuccess(Void info) { lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("enableCryptoAlice")); - createBobAccount(); + mBobSession = createBobAccount(true, false); CountDownLatch lock2 = new CountDownLatch(1); mBobSession.enableCrypto(true, new TestApiCallback(lock2) { @@ -486,12 +486,11 @@ public void onSuccess(MXUsersDevicesMap info) { Credentials bobCredentials = mBobSession.getCredentials(); - HomeServerConnectionConfig hs = CryptoTestHelper.createHomeServerConfig(bobCredentials); + HomeServerConnectionConfig hs = createHomeServerConfig(bobCredentials); IMXStore store = new MXFileStore(hs, context); - MXSession bobSession2 = new MXSession.Builder(hs, new MXDataHandler(store, bobCredentials), context) - .build(); + MXSession bobSession2 = new MXSession(hs, new MXDataHandler(store, bobCredentials), context); final CountDownLatch lock5 = new CountDownLatch(1); @@ -581,7 +580,7 @@ public void test05_testRoomIsEncrypted() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - createBobAccount(); + mBobSession = createBobAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); mBobSession.enableCrypto(true, new TestApiCallback(lock0) { @@ -784,7 +783,7 @@ public void onLiveEvent(Event event, RoomState roomState) { } }; - ApiCallback callback = new VoidApiCallback(); + ApiCallback callback = new SimpleApiCallback<>(); roomFromBobPOV.addEventListener(bobEventListener); roomFromAlicePOV.addEventListener(aliceEventListener); @@ -843,14 +842,13 @@ public void test09_testAliceInAEncryptedRoomAfterInitialSync() throws Exception mAliceSession.clear(context); - HomeServerConnectionConfig hs = CryptoTestHelper.createHomeServerConfig(aliceCredentials); + HomeServerConnectionConfig hs = createHomeServerConfig(aliceCredentials); IMXStore store = new MXFileStore(hs, context); final CountDownLatch lock1 = new CountDownLatch(1); - final MXSession aliceSession2 = new MXSession.Builder(hs, new MXDataHandler(store, aliceCredentials), context) - .build(); + final MXSession mAliceSession2 = new MXSession(hs, new MXDataHandler(store, aliceCredentials), context); MXStoreListener listener = new MXStoreListener() { @Override @@ -874,8 +872,8 @@ public void onStoreOOM(String accountId, String description) { } }; - aliceSession2.getDataHandler().getStore().addMXStoreListener(listener); - aliceSession2.getDataHandler().getStore().open(); + mAliceSession2.getDataHandler().getStore().addMXStoreListener(listener); + mAliceSession2.getDataHandler().getStore().open(); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onStoreReady")); @@ -894,13 +892,13 @@ public void onCryptoSyncComplete() { } }; - aliceSession2.getDataHandler().addListener(eventListener); - aliceSession2.startEventStream(null); + mAliceSession2.getDataHandler().addListener(eventListener); + mAliceSession2.startEventStream(null); lock1b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); - Room roomFromAlicePOV2 = aliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV2 = mAliceSession2.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromAlicePOV2.isEncrypted()); @@ -912,7 +910,7 @@ public void onCryptoSyncComplete() { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, message, aliceSession2); + checkEncryptedEvent(event, mRoomId, message, mAliceSession2); lock2.countDown(); } @@ -924,7 +922,7 @@ public void onLiveEvent(Event event, RoomState roomState) { // the IOS client echoes the message // the android client does not - roomFromAlicePOV2.sendEvent(buildTextEvent(message, aliceSession2), new TestApiCallback(lock2) { + roomFromAlicePOV2.sendEvent(buildTextEvent(message, mAliceSession2), new TestApiCallback(lock2) { @Override public void onSuccess(Void info) { results.put("sendEvent", "sendEvent"); @@ -935,7 +933,7 @@ public void onSuccess(Void info) { lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("sendEvent")); - aliceSession2.clear(context); + mAliceSession2.clear(context); } @Test @@ -976,14 +974,13 @@ public void onSuccess(Void info) { aliceCredentials2.refreshToken = aliceCredentials.refreshToken; aliceCredentials2.deviceId = "AliceNewDevice"; - HomeServerConnectionConfig hs = CryptoTestHelper.createHomeServerConfig(aliceCredentials2); + HomeServerConnectionConfig hs = createHomeServerConfig(aliceCredentials2); IMXStore store = new MXFileStore(hs, context); - MXSession aliceSession2 = new MXSession.Builder(hs, new MXDataHandler(store, aliceCredentials2), context) - .build(); + MXSession mAliceSession2 = new MXSession(hs, new MXDataHandler(store, aliceCredentials2), context); - aliceSession2.enableCryptoWhenStarting(); + mAliceSession2.enableCryptoWhenStarting(); final CountDownLatch lock1b = new CountDownLatch(1); MXStoreListener listener = new MXStoreListener() { @@ -1008,8 +1005,8 @@ public void onStoreOOM(String accountId, String description) { } }; - aliceSession2.getDataHandler().getStore().addMXStoreListener(listener); - aliceSession2.getDataHandler().getStore().open(); + mAliceSession2.getDataHandler().getStore().addMXStoreListener(listener); + mAliceSession2.getDataHandler().getStore().open(); lock1b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onStoreReady")); @@ -1028,15 +1025,15 @@ public void onCryptoSyncComplete() { } }; - aliceSession2.getDataHandler().addListener(eventListener); - aliceSession2.startEventStream(null); + mAliceSession2.getDataHandler().addListener(eventListener); + mAliceSession2.startEventStream(null); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); - Room roomFromAlicePOV2 = aliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV2 = mAliceSession2.getDataHandler().getRoom(mRoomId); Assert.assertNotNull(roomFromAlicePOV2); Assert.assertTrue(roomFromAlicePOV2.getState().isEncrypted()); @@ -1047,7 +1044,7 @@ public void onCryptoSyncComplete() { Assert.assertNull(event.getClearEvent()); Assert.assertNotNull(event.getCryptoError()); Assert.assertEquals(MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE, event.getCryptoError().errcode); - aliceSession2.clear(context); + mAliceSession2.clear(context); } @Test @@ -1062,14 +1059,13 @@ public void test11_testAliceAndBobInAEncryptedRoomBackPaginationFromMemoryStore( Credentials bobCredentials = mBobSession.getCredentials(); mBobSession.clear(context); - HomeServerConnectionConfig hs = CryptoTestHelper.createHomeServerConfig(bobCredentials); + HomeServerConnectionConfig hs = createHomeServerConfig(bobCredentials); IMXStore store = new MXFileStore(hs, context); final CountDownLatch lock1 = new CountDownLatch(2); - MXSession bobSession2 = new MXSession.Builder(hs, new MXDataHandler(store, bobCredentials), context) - .build(); + MXSession bobSession2 = new MXSession(hs, new MXDataHandler(store, bobCredentials), context); MXEventListener eventListener = new MXEventListener() { @Override @@ -1222,7 +1218,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromBobPOV.addEventListener(bobEventListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new VoidApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("bobEcho")); @@ -1250,7 +1246,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromAlicePOV.addEventListener(aliceEventListener); - roomFromBobPOV.sendEvent(buildTextEvent("Hello I'm Bob!", mBobSession), new VoidApiCallback()); + roomFromBobPOV.sendEvent(buildTextEvent("Hello I'm Bob!", mBobSession), new SimpleApiCallback()); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("aliceEcho")); @@ -1504,7 +1500,7 @@ public void onToDeviceEvent(Event event) { } }); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new VoidApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); @@ -1566,7 +1562,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new VoidApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); @@ -1639,7 +1635,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new VoidApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); @@ -1736,7 +1732,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage1 = "Hello I'm Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, mAliceSession), new VoidApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, mAliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); @@ -1772,7 +1768,7 @@ public void onToDeviceEvent(Event event) { mAliceSession.getDataHandler().addListener(aliceEventListener); // login with a new device id - MXSession bobSession2 = CryptoTestHelper.logAccountAndSync(context, bobId, MXTESTS_BOB_PWD); + MXSession bobSession2 = logIntoBobAccount(mBobSession.getMyUserId(), true, true); String bobDeviceId2 = bobSession2.getCredentials().deviceId; Assert.assertNotEquals(bobDeviceId2, bobDeviceId1); @@ -1804,7 +1800,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener4); String aliceMessage2 = "Hello I'm still Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, mAliceSession), new VoidApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, mAliceSession), new SimpleApiCallback()); lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals("received event of type " + results.get("event4"), 1, receivedEvents4.size()); @@ -1860,7 +1856,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage1 = "Hello I'm Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, mAliceSession), new VoidApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, mAliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); @@ -1892,16 +1888,16 @@ public void onSuccess(Void info) { lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("alicelogout")); - MXSession bobSession2 = CryptoTestHelper.logAccountAndSync(context, bobUserId1, MXTESTS_BOB_PWD); + MXSession bobSession2 = logIntoBobAccount(mBobSession.getMyUserId(), true, true); Assert.assertNotNull(bobSession2); bobSession2.getCrypto().setWarnOnUnknownDevices(false); - MXSession aliceSession2 = CryptoTestHelper.logAccountAndSync(context, aliceUserId1, MXTESTS_ALICE_PWD); - Assert.assertNotNull(aliceSession2); - aliceSession2.getCrypto().setWarnOnUnknownDevices(false); + MXSession mAliceSession2 = logIntoAliceAccount(mAliceSession.getMyUserId(), true, true); + Assert.assertNotNull(mAliceSession2); + mAliceSession2.getCrypto().setWarnOnUnknownDevices(false); Room roomFromBob2POV = bobSession2.getDataHandler().getRoom(mRoomId); - Room roomFromAlice2POV = aliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlice2POV = mAliceSession2.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromBob2POV.isEncrypted()); event = bobSession2.getDataHandler().getStore().getLatestEvent(mRoomId); @@ -1924,13 +1920,13 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBob2POV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); String messageFromAlice2 = "Hello I'm still Alice!"; - roomFromAlice2POV.sendEvent(buildTextEvent(messageFromAlice2, aliceSession2), new VoidApiCallback()); + roomFromAlice2POV.sendEvent(buildTextEvent(messageFromAlice2, mAliceSession2), new SimpleApiCallback()); lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); event = receivedEvents2.get(0); - checkEncryptedEvent(event, mRoomId, messageFromAlice2, aliceSession2); + checkEncryptedEvent(event, mRoomId, messageFromAlice2, mAliceSession2); } @Test @@ -1965,7 +1961,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage1 = "Hello I'm Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, mAliceSession), new VoidApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, mAliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents.size()); @@ -2004,7 +2000,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage2 = "Hello I'm still Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, mAliceSession), new VoidApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, mAliceSession), new SimpleApiCallback()); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); @@ -2044,7 +2040,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage3 = "Hello I'm still Alice and you can read this!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage3, mAliceSession), new VoidApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage3, mAliceSession), new SimpleApiCallback()); lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents3.size()); @@ -2258,14 +2254,13 @@ public void onSuccess(byte[] info) { aliceCredentials2.refreshToken = aliceCredentials.refreshToken; aliceCredentials2.deviceId = "AliceNewDevice"; - HomeServerConnectionConfig hs = CryptoTestHelper.createHomeServerConfig(aliceCredentials2); + HomeServerConnectionConfig hs = createHomeServerConfig(aliceCredentials2); IMXStore store = new MXFileStore(hs, context); - MXSession aliceSession2 = new MXSession.Builder(hs, new MXDataHandler(store, aliceCredentials2), context) - .build(); + MXSession mAliceSession2 = new MXSession(hs, new MXDataHandler(store, aliceCredentials2), context); - aliceSession2.enableCryptoWhenStarting(); + mAliceSession2.enableCryptoWhenStarting(); final CountDownLatch lock1b = new CountDownLatch(1); MXStoreListener listener = new MXStoreListener() { @@ -2290,8 +2285,8 @@ public void onStoreOOM(String accountId, String description) { } }; - aliceSession2.getDataHandler().getStore().addMXStoreListener(listener); - aliceSession2.getDataHandler().getStore().open(); + mAliceSession2.getDataHandler().getStore().addMXStoreListener(listener); + mAliceSession2.getDataHandler().getStore().open(); lock1b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onStoreReady")); @@ -2310,15 +2305,15 @@ public void onCryptoSyncComplete() { } }; - aliceSession2.getDataHandler().addListener(eventListener); - aliceSession2.startEventStream(null); + mAliceSession2.getDataHandler().addListener(eventListener); + mAliceSession2.startEventStream(null); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); - Room roomFromAlicePOV2 = aliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV2 = mAliceSession2.getDataHandler().getRoom(mRoomId); Assert.assertNotNull(roomFromAlicePOV2); Assert.assertTrue(roomFromAlicePOV2.getState().isEncrypted()); @@ -2333,7 +2328,7 @@ public void onCryptoSyncComplete() { // import the e2e keys // test with a wrong password CountDownLatch lock3 = new CountDownLatch(1); - aliceSession2.getCrypto().importRoomKeys((byte[]) results.get("exportRoomKeys"), "wrong password", new TestApiCallback(lock3) { + mAliceSession2.getCrypto().importRoomKeys((byte[]) results.get("exportRoomKeys"), "wrong password", new TestApiCallback(lock3) { @Override public void onSuccess(Void info) { results.put("importRoomKeys", "importRoomKeys"); @@ -2371,7 +2366,7 @@ public void onUnexpectedError(Exception e) { Assert.assertEquals(MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE, event.getCryptoError().errcode); CountDownLatch lock4 = new CountDownLatch(1); - aliceSession2.getCrypto().importRoomKeys((byte[]) results.get("exportRoomKeys"), password, new TestApiCallback(lock4) { + mAliceSession2.getCrypto().importRoomKeys((byte[]) results.get("exportRoomKeys"), password, new TestApiCallback(lock4) { @Override public void onSuccess(Void info) { results.put("importRoomKeys", "importRoomKeys"); @@ -2389,7 +2384,7 @@ public void onSuccess(Void info) { Assert.assertNull(event.getCryptoError()); checkEncryptedEvent(event, mRoomId, message, mAliceSession); - aliceSession2.clear(context); + mAliceSession2.clear(context); } @Test @@ -2403,8 +2398,8 @@ public void test25_testLeftAndJoinedBob() throws Exception { final Map results = new HashMap<>(); - createAliceAccount(); - createBobAccount(); + mAliceSession = createAliceAccount(true, false); + mBobSession = createBobAccount(true, false); CountDownLatch lock_1 = new CountDownLatch(2); @@ -2469,7 +2464,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }; roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new VoidApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new SimpleApiCallback()); lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents.size()); @@ -2492,7 +2487,7 @@ public void onSuccess(Void info) { Credentials bobCredentials = mBobSession.getCredentials(); mBobSession.clear(context); - MXSession bobSession2 = CryptoTestHelper.logAccountAndSync(context, bobCredentials.userId, MXTESTS_BOB_PWD); + MXSession bobSession2 = logIntoBobAccount(mBobSession.getMyUserId(), true, true); Assert.assertNotNull(bobSession2); Assert.assertTrue(bobSession2.isCryptoEnabled()); Assert.assertNotEquals(bobSession2.getCrypto().getMyDevice().deviceId, bobCredentials.deviceId); @@ -2523,7 +2518,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }; roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); - roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, mAliceSession), new VoidApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, mAliceSession), new SimpleApiCallback()); lock6.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); @@ -2854,8 +2849,8 @@ public void test27_testEnableEncryptionAfterNonEncryptedMessages() throws Except final String messageFromAlice = "Hello I'm Alice!"; final String message2FromAlice = "I'm still Alice!"; - createAliceAccount(); - createBobAccount(); + mAliceSession = createAliceAccount(true, false); + mBobSession = createBobAccount(true, false); CountDownLatch lock00b = new CountDownLatch(2); mAliceSession.enableCrypto(true, new TestApiCallback(lock00b) { @@ -2921,7 +2916,7 @@ public void onSuccess(Void info) { Credentials bobCredentials = mBobSession.getCredentials(); mBobSession.clear(context); - MXSession bobSession2 = CryptoTestHelper.logAccountAndSync(context, bobCredentials.userId, MXTESTS_BOB_PWD); + MXSession bobSession2 = logIntoBobAccount(mBobSession.getMyUserId(), true, true); Assert.assertNotNull(bobSession2); Assert.assertTrue(bobSession2.isCryptoEnabled()); Assert.assertNotEquals(bobSession2.getCrypto().getMyDevice().deviceId, bobCredentials.deviceId); @@ -2954,7 +2949,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }; roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); - roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, mAliceSession), new VoidApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, mAliceSession), new SimpleApiCallback()); lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); @@ -2996,12 +2991,12 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("lock1")); // - Alice adds a new device - final MXSession aliceSession2 = CryptoTestHelper.logAccountAndSync(context, mAliceSession.getMyUserId(), MXTESTS_ALICE_PWD); - Assert.assertNotNull(aliceSession2); + final MXSession mAliceSession2 = logIntoAliceAccount(mAliceSession.getMyUserId(), true, true); + Assert.assertNotNull(mAliceSession2); // - Alice and Bob start sharing a room again CountDownLatch lock3 = new CountDownLatch(1); - aliceSession2.createRoom(null, null, RoomState.DIRECTORY_VISIBILITY_PUBLIC, + mAliceSession2.createRoom(null, null, RoomState.DIRECTORY_VISIBILITY_PUBLIC, null, RoomState.GUEST_ACCESS_CAN_JOIN, null, new TestApiCallback(lock3) { @Override @@ -3013,7 +3008,7 @@ public void onSuccess(String info) { lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertNotNull(mRoomId); - Room roomFromAlicePOV = aliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = mAliceSession2.getDataHandler().getRoom(mRoomId); CountDownLatch lock4 = new CountDownLatch(1); roomFromAlicePOV.enableEncryptionWithAlgorithm(MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_MEGOLM, new TestApiCallback(lock4) { @Override @@ -3061,7 +3056,7 @@ public void onLiveEvent(Event event, RoomState roomState) { mBobSession.clear(context); mAliceSession.clear(context); - aliceSession2.clear(context); + mAliceSession2.clear(context); } /** @@ -3132,7 +3127,7 @@ public void onLiveEvent(Event event, RoomState roomState) { } }; - ApiCallback callback = new VoidApiCallback(); + ApiCallback callback = new SimpleApiCallback<>(); roomFromBobPOV.addEventListener(bobEventListener); roomFromAlicePOV.addEventListener(aliceEventListener); @@ -3185,43 +3180,10 @@ public void onToDeviceEvent(Event event) { // private test routines //============================================================================================================== - private MXSession mBobSession; - private MXSession mAliceSession; - private MXSession mSamSession; - private String mRoomId; - private int mMessagesCount; - private int mReceivedMessagesFromAlice; - private int mReceivedMessagesFromBob; - - public void createBobAccount() throws Exception { - Context context = InstrumentationRegistry.getContext(); - mBobSession = null; - mBobSession = CryptoTestHelper.createAccountAndSync(context, - MXTESTS_BOB + System.currentTimeMillis() + UUID.randomUUID().toString(), MXTESTS_BOB_PWD, true); - Assert.assertNotNull(mBobSession); - } - - public void createAliceAccount() throws Exception { - Context context = InstrumentationRegistry.getContext(); - mAliceSession = null; - mAliceSession = CryptoTestHelper.createAccountAndSync(context, - MXTESTS_ALICE + System.currentTimeMillis() + UUID.randomUUID().toString(), MXTESTS_ALICE_PWD, true); - Assert.assertNotNull(mAliceSession); - } - - public void createSamAccount() throws Exception { - Context context = InstrumentationRegistry.getContext(); - mSamSession = null; - mSamSession = CryptoTestHelper.createAccountAndSync(context, - MXTESTS_SAM + System.currentTimeMillis() + UUID.randomUUID().toString(), MXTESTS_SAM_PWD, true); - Assert.assertNotNull(mSamSession); - } private void doE2ETestWithAliceInARoom() throws Exception { final Map results = new HashMap<>(); - - createAliceAccount(); - + mAliceSession = createAliceAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); mAliceSession.enableCrypto(true, new TestApiCallback(lock0) { @@ -3269,7 +3231,7 @@ private void doE2ETestWithAliceAndBobInARoom(boolean cryptedBob) throws Exceptio Room room = mAliceSession.getDataHandler().getRoom(mRoomId); - createBobAccount(); + mBobSession = createBobAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); mBobSession.enableCrypto(cryptedBob, new TestApiCallback(lock0) { @@ -3368,7 +3330,7 @@ private void doE2ETestWithAliceAndBobAndSamInARoom() throws Exception { Room room = mAliceSession.getDataHandler().getRoom(mRoomId); - createSamAccount(); + mSamSession = createSamAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); mSamSession.enableCrypto(true, new TestApiCallback(lock0) { diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/ExportEncryptionTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/ExportEncryptionTest.java similarity index 98% rename from matrix-sdk/src/androidTest/java/org/matrix/androidsdk/ExportEncryptionTest.java rename to matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/ExportEncryptionTest.java index 5c6d170e1..f40145453 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/ExportEncryptionTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/ExportEncryptionTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.androidsdk; +package org.matrix.androidsdk.crypto; import android.support.test.runner.AndroidJUnit4; @@ -23,6 +23,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; +import org.matrix.androidsdk.common.AbsIntegrationTest; import org.matrix.androidsdk.crypto.MXMegolmExportEncryption; /** @@ -30,7 +31,7 @@ */ @RunWith(AndroidJUnit4.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class ExportEncryptionTest { +public class ExportEncryptionTest extends AbsIntegrationTest { @Test public void checkExportError1() throws Exception { From 77e99b5d0940e5390a939f7a74fa4f4565eb1abe Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 20 Aug 2018 11:45:32 +0200 Subject: [PATCH 004/236] Testing : favor composition over inheritance --- .../androidsdk/common/AbsIntegrationTest.java | 113 --------- ...{TestHelper.java => CommonTestHelper.java} | 228 ++++++++++++------ .../androidsdk/common/TestConstants.java | 3 + .../crypto/AttachmentEncryptionTest.java | 6 +- .../androidsdk/crypto/CryptoRestTest.java | 18 +- .../matrix/androidsdk/crypto/CryptoTest.java | 61 ++--- .../crypto/ExportEncryptionTest.java | 24 +- 7 files changed, 217 insertions(+), 236 deletions(-) delete mode 100644 matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/AbsIntegrationTest.java rename matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/{TestHelper.java => CommonTestHelper.java} (52%) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/AbsIntegrationTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/AbsIntegrationTest.java deleted file mode 100644 index 7fae5bbc0..000000000 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/AbsIntegrationTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2018 New Vector Ltd - * - * 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 org.matrix.androidsdk.common; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.test.InstrumentationRegistry; - -import org.junit.Assert; -import org.matrix.androidsdk.HomeServerConnectionConfig; -import org.matrix.androidsdk.MXSession; -import org.matrix.androidsdk.rest.model.login.Credentials; - -import java.util.UUID; - -/** - * This class is the parent class test for integration test cases - * It exposes methods to create and log into Alice, Bob and Sam accounts. - */ -public class AbsIntegrationTest { - - - private TestHelper mTestHelper = new TestHelper(); - - protected HomeServerConnectionConfig createHomeServerConfig(@Nullable Credentials credentials) { - return mTestHelper.createHomeServerConfig(credentials); - } - - protected MXSession createBobAccount(boolean withInitialSync, boolean enableCrypto) { - return createAccount(TestConstants.BOB_USER_ID, TestConstants.BOB_PWD, withInitialSync, enableCrypto); - } - - protected MXSession createAliceAccount(boolean withInitialSync, boolean enableCrypto) { - return createAccount(TestConstants.ALICE_USER_ID, TestConstants.ALICE_PWD, withInitialSync, enableCrypto); - } - - protected MXSession createSamAccount(boolean withInitialSync, boolean enableCrypto) { - return createAccount(TestConstants.SAM_USER_ID, TestConstants.SAM_PWD, withInitialSync, enableCrypto); - } - - protected MXSession logIntoBobAccount(final String bobUserId, final boolean withInitialSync, boolean enableCrypto) { - return logIntoAccount(bobUserId, TestConstants.BOB_PWD, withInitialSync, enableCrypto); - } - - protected MXSession logIntoAliceAccount(final String aliceUserId, final boolean withInitialSync, boolean enableCrypto) { - return logIntoAccount(aliceUserId, TestConstants.ALICE_PWD, withInitialSync, enableCrypto); - } - - protected MXSession logIntoSamAccount(final String samUserId, final boolean withInitialSync, boolean enableCrypto) { - return logIntoAccount(samUserId, TestConstants.SAM_PWD, withInitialSync, enableCrypto); - } - - // PRIVATE METHODS ***************************************************************************** - - /** - * Creates a unique account - * - * @param userId the base userId - * @param password the password - * @param withInitialSync true to perform an initial sync - * @param enableCrypto true to set enableCryptoWhenStarting - * @return the session associated with the newly created account - */ - private MXSession createAccount(@NonNull final String userId, - @NonNull final String password, - final boolean withInitialSync, - final boolean enableCrypto) { - final Context context = InstrumentationRegistry.getContext(); - final MXSession session = mTestHelper.createAccountAndSync( - context, - userId + System.currentTimeMillis() + UUID.randomUUID(), - password, - withInitialSync, - enableCrypto - ); - Assert.assertNotNull(session); - return session; - } - - /** - * Logs into an existing account - * - * @param userId the userId to log in - * @param password the password to log in - * @param withInitialSync true to perform an initial sync - * @param enableCrypto true to set enableCryptoWhenStarting - * @return the session associated with the existing account - */ - private MXSession logIntoAccount(@NonNull final String userId, - @NonNull final String password, - final boolean withInitialSync, - final boolean enableCrypto) { - final Context context = InstrumentationRegistry.getContext(); - final MXSession session = mTestHelper.logAccountAndSync(context, userId, password, withInitialSync, enableCrypto); - Assert.assertNotNull(session); - return session; - } -} diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java similarity index 52% rename from matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestHelper.java rename to matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index c5597fef4..c8531e069 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -19,16 +19,20 @@ import android.content.Context; import android.net.Uri; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.test.InstrumentationRegistry; import org.junit.Assert; import org.matrix.androidsdk.HomeServerConnectionConfig; import org.matrix.androidsdk.MXDataHandler; import org.matrix.androidsdk.MXSession; +import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.data.store.MXFileStore; import org.matrix.androidsdk.listeners.MXEventListener; import org.matrix.androidsdk.rest.client.LoginRestClient; +import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.MatrixError; import org.matrix.androidsdk.rest.model.login.Credentials; import org.matrix.androidsdk.rest.model.login.RegistrationFlowResponse; @@ -37,13 +41,45 @@ import java.util.HashMap; import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import javax.annotation.Nonnull; -public class TestHelper { +import static org.matrix.androidsdk.rest.model.message.Message.FORMAT_MATRIX_HTML; - private static final String TESTS_HOME_SERVER_URL = "http://10.0.2.2:8080"; + +/** + * This class exposes methods to be used in common cases + * Registration, login, Sync, Sending messages... + */ +public class CommonTestHelper { + + public MXSession createBobAccount(boolean withInitialSync, boolean enableCrypto) { + return createAccount(TestConstants.BOB_USER_ID, TestConstants.BOB_PWD, withInitialSync, enableCrypto); + } + + public MXSession createAliceAccount(boolean withInitialSync, boolean enableCrypto) { + return createAccount(TestConstants.ALICE_USER_ID, TestConstants.ALICE_PWD, withInitialSync, enableCrypto); + } + + public MXSession createSamAccount(boolean withInitialSync, boolean enableCrypto) { + return createAccount(TestConstants.SAM_USER_ID, TestConstants.SAM_PWD, withInitialSync, enableCrypto); + } + + public MXSession logIntoBobAccount(final String bobUserId, final boolean withInitialSync, boolean enableCrypto) { + return logIntoAccount(bobUserId, TestConstants.BOB_PWD, withInitialSync, enableCrypto); + } + + public MXSession logIntoAliceAccount(final String aliceUserId, final boolean withInitialSync, boolean enableCrypto) { + return logIntoAccount(aliceUserId, TestConstants.ALICE_PWD, withInitialSync, enableCrypto); + } + + public MXSession logIntoSamAccount(final String samUserId, final boolean withInitialSync, boolean enableCrypto) { + return logIntoAccount(samUserId, TestConstants.SAM_PWD, withInitialSync, enableCrypto); + } /** * Create a Home server configuration, with Http connection allowed for test @@ -51,23 +87,131 @@ public class TestHelper { * @param credentials * @return */ - HomeServerConnectionConfig createHomeServerConfig(@Nullable Credentials credentials) { - final HomeServerConnectionConfig hs = new HomeServerConnectionConfig(Uri.parse(TESTS_HOME_SERVER_URL)); + public HomeServerConnectionConfig createHomeServerConfig(@Nullable Credentials credentials) { + final HomeServerConnectionConfig hs = new HomeServerConnectionConfig(Uri.parse(TestConstants.TESTS_HOME_SERVER_URL)); hs.allowHttpConnection(); hs.setCredentials(credentials); return hs; } + /** + * This methods init the event stream and check for initial sync + * + * @param session the session to sync + * @param withCrypto true if crypto is enabled and should be checked + */ + public void syncSession(@Nonnull final MXSession session, final boolean withCrypto) { + final Map params = new HashMap<>(); + final int sizeOfLock = withCrypto ? 2 : 1; + final CountDownLatch lock2 = new CountDownLatch(sizeOfLock); + session.getDataHandler().addListener(new MXEventListener() { + @Override + public void onInitialSyncComplete(String toToken) { + params.put("isInit", true); + lock2.countDown(); + } + + @Override + public void onCryptoSyncComplete() { + params.put("onCryptoSyncComplete", true); + lock2.countDown(); + } + }); + session.getDataHandler().getStore().open(); + session.startEventStream(null); + try { + lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Assert.assertTrue(params.containsKey("isInit")); + if (withCrypto) { + Assert.assertTrue(params.containsKey("onCryptoSyncComplete")); + } + } + + /** + * Sends text messages in a room + * + * @param room the room where to send the messages + * @param message the message to send + * @param nbOfMessages the number of time the message will be sent + * @throws Exception + */ + public void sendTextMessage(@Nonnull final Room room, @Nonnull final String message, final int nbOfMessages) throws Exception { + final CountDownLatch latch = new CountDownLatch(nbOfMessages); + final MXEventListener onEventsentListener = new MXEventListener() { + @Override + public void onEventSent(Event event, String prevEventId) { + super.onEventSent(event, prevEventId); + latch.countDown(); + } + }; + room.addEventListener(onEventsentListener); + for (int i = 0; i < nbOfMessages; i++) { + room.sendTextMessage(message, null, FORMAT_MATRIX_HTML, null); + } + latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + room.removeEventListener(onEventsentListener); + } + + + // PRIVATE METHODS ***************************************************************************** + + /** + * Creates a unique account + * + * @param userId the base userId + * @param password the password + * @param withInitialSync true to perform an initial sync + * @param enableCrypto true to set enableCryptoWhenStarting + * @return the session associated with the newly created account + */ + private MXSession createAccount(@NonNull final String userId, + @NonNull final String password, + final boolean withInitialSync, + final boolean enableCrypto) { + final Context context = InstrumentationRegistry.getContext(); + final MXSession session = createAccountAndSync( + context, + userId + System.currentTimeMillis() + UUID.randomUUID(), + password, + withInitialSync, + enableCrypto + ); + Assert.assertNotNull(session); + return session; + } + + /** + * Logs into an existing account + * + * @param userId the userId to log in + * @param password the password to log in + * @param withInitialSync true to perform an initial sync + * @param enableCrypto true to set enableCryptoWhenStarting + * @return the session associated with the existing account + */ + private MXSession logIntoAccount(@NonNull final String userId, + @NonNull final String password, + final boolean withInitialSync, + final boolean enableCrypto) { + final Context context = InstrumentationRegistry.getContext(); + final MXSession session = logAccountAndSync(context, userId, password, withInitialSync, enableCrypto); + Assert.assertNotNull(session); + return session; + } + /** * 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 - * @param enableCrypto true to set enableCryptoWhenStarting + * @param context the context + * @param userName the account username + * @param password the password + * @param withInitialSync true to perform an initial sync + * @param enableCrypto true to set enableCryptoWhenStarting */ - MXSession createAccountAndSync(Context context, String userName, String password, boolean startSession, boolean enableCrypto) { + private MXSession createAccountAndSync(Context context, String userName, String password, boolean withInitialSync, boolean enableCrypto) { final HomeServerConnectionConfig hs = createHomeServerConfig(null); final LoginRestClient loginRestClient = new LoginRestClient(hs); @@ -147,31 +291,9 @@ public void onSuccess(Credentials credentials) { if (enableCrypto) { mxSession.enableCryptoWhenStarting(); } - - if (!startSession) { - return mxSession; + if (withInitialSync) { + syncSession(mxSession, enableCrypto); } - - mxSession.getDataHandler().getStore().open(); - mxSession.startEventStream(null); - - final CountDownLatch lock2 = new CountDownLatch(1); - mxSession.getDataHandler().addListener(new MXEventListener() { - @Override - public void onInitialSyncComplete(String toToken) { - params.put("isInit", true); - lock2.countDown(); - } - }); - - try { - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - Assert.assertTrue(params.containsKey("isInit")); - return mxSession; } @@ -184,7 +306,7 @@ public void onInitialSyncComplete(String toToken) { * @param withInitialSync true to perform an initial sync * @param enableCrypto true to set enableCryptoWhenStarting */ - MXSession logAccountAndSync(Context context, String userName, String password, boolean withInitialSync, boolean enableCrypto) { + private MXSession logAccountAndSync(Context context, String userName, String password, boolean withInitialSync, boolean enableCrypto) { final HomeServerConnectionConfig hs = createHomeServerConfig(null); LoginRestClient loginRestClient = new LoginRestClient(hs); final Map params = new HashMap<>(); @@ -212,44 +334,14 @@ public void onSuccess(Credentials credentials) { hs.setCredentials(credentials); final IMXStore store = new MXFileStore(hs, context); - final MXSession mxSession = new MXSession(hs, new MXDataHandler(store, credentials), context); - if (enableCrypto) { mxSession.enableCryptoWhenStarting(); } - - if (!withInitialSync) { - return mxSession; - } - - final CountDownLatch lock2 = new CountDownLatch(2); - mxSession.getDataHandler().addListener(new MXEventListener() { - @Override - public void onInitialSyncComplete(String toToken) { - params.put("isInit", true); - lock2.countDown(); - } - - @Override - public void onCryptoSyncComplete() { - params.put("onCryptoSyncComplete", true); - lock2.countDown(); - } - }); - - mxSession.getDataHandler().getStore().open(); - mxSession.startEventStream(null); - - try { - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); + if (withInitialSync) { + syncSession(mxSession, enableCrypto); } - - Assert.assertTrue(params.containsKey("isInit")); - Assert.assertTrue(params.containsKey("onCryptoSyncComplete")); - return mxSession; } + } diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java index 285e17a8b..87e6d7ad5 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java @@ -17,6 +17,9 @@ package org.matrix.androidsdk.common; public class TestConstants { + + public static final String TESTS_HOME_SERVER_URL = "http://10.0.2.2:8080"; + // Time out to use when waiting for server response public static final int AWAIT_TIME_OUT_MILLIS = 30000; diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/AttachmentEncryptionTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/AttachmentEncryptionTest.java index e90cf4bdf..b48f047ae 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/AttachmentEncryptionTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/AttachmentEncryptionTest.java @@ -9,8 +9,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; -import org.matrix.androidsdk.common.AbsIntegrationTest; -import org.matrix.androidsdk.crypto.MXEncryptedAttachments; import org.matrix.androidsdk.rest.model.crypto.EncryptedFileInfo; import org.matrix.androidsdk.rest.model.crypto.EncryptedFileKey; @@ -25,7 +23,7 @@ */ @RunWith(AndroidJUnit4.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class AttachmentEncryptionTest extends AbsIntegrationTest { +public class AttachmentEncryptionTest { private String checkDecryption(String input, EncryptedFileInfo encryptedFileInfo) throws Exception { byte[] in = Base64.decode(input, Base64.DEFAULT); @@ -128,6 +126,6 @@ public void checkDecrypt4() throws Exception { Assert.assertNotEquals("YWxwaGFudW1lcmljYWxseWFscGhhbnVtZXJpY2FsbHlhbHBoYW51bWVyaWNhbGx5YWxwaGFudW1lcmljYWxseQ", checkDecryption("tJVNBVJ/vl36UQt4Y5e5m84bRUrQHhcdLPvS/7EkDvlkDLZXamBB6k8THbiawiKZ5Mnq9PZMSSbgOCvmnUBOMA", - encryptedFileInfo)); + encryptedFileInfo)); } } diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java index 63603bfeb..1d0e0c30e 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java @@ -27,11 +27,9 @@ import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; import org.matrix.androidsdk.MXSession; -import org.matrix.androidsdk.common.AbsIntegrationTest; +import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.common.TestApiCallback; import org.matrix.androidsdk.common.TestConstants; -import org.matrix.androidsdk.common.TestHelper; -import org.matrix.androidsdk.crypto.MXCryptoAlgorithms; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXKey; import org.matrix.androidsdk.crypto.data.MXUsersDevicesMap; @@ -43,18 +41,20 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class CryptoRestTest extends AbsIntegrationTest { +public class CryptoRestTest { + + private CommonTestHelper mTestHelper = new CommonTestHelper(); + @Test public void test01_testDeviceKeys() throws Exception { Context context = InstrumentationRegistry.getContext(); - final MXSession bobSession = createBobAccount(true, false); + final MXSession bobSession = mTestHelper.createBobAccount(true, false); final Map results = new HashMap<>(); String ed25519key = "wV5E3EUSHpHuoZLljNzojlabjGdXT3Mz7rugG9zgbkI"; @@ -120,7 +120,7 @@ public void onSuccess(KeysQueryResponse keysQueryResponse) { public void test02_testOneTimeKeys() throws Exception { Context context = InstrumentationRegistry.getContext(); - final MXSession bobSession = createBobAccount(true, false); + final MXSession bobSession = mTestHelper.createBobAccount(true, false); final Map results = new HashMap<>(); final Map otks = new HashMap<>(); @@ -153,8 +153,8 @@ public void onSuccess(KeysUploadResponse keysUploadResponse) { public void test03_testClaimOneTimeKeysForUsersDevices() throws Exception { Context context = InstrumentationRegistry.getContext(); - final MXSession bobSession = createBobAccount(true, false); - final MXSession aliceSession = createAliceAccount(true, false); + final MXSession bobSession = mTestHelper.createBobAccount(true, false); + final MXSession aliceSession = mTestHelper.createAliceAccount(true, false); final Map results = new HashMap<>(); final Map otks = new HashMap<>(); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index d201c1422..bf3ff6ab8 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -36,7 +36,7 @@ import org.matrix.androidsdk.HomeServerConnectionConfig; import org.matrix.androidsdk.MXDataHandler; import org.matrix.androidsdk.MXSession; -import org.matrix.androidsdk.common.AbsIntegrationTest; +import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.common.TestApiCallback; import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; @@ -70,7 +70,10 @@ @RunWith(AndroidJUnit4.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class CryptoTest extends AbsIntegrationTest { +public class CryptoTest { + + private CommonTestHelper mTestHelper = new CommonTestHelper(); + private static final String LOG_TAG = "CryptoTest"; @@ -92,7 +95,7 @@ public void test01_testCryptoNoDeviceId() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - mBobSession = createBobAccount(true, false); + mBobSession = mTestHelper.createBobAccount(true, false); Assert.assertNull(mBobSession.getCrypto()); mBobSession.getCredentials().deviceId = null; @@ -120,7 +123,7 @@ public void test02_testCryptoPersistenceInStore() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - mBobSession = createBobAccount(true, false); + mBobSession = mTestHelper.createBobAccount(true, false); mBobSession.getCredentials().deviceId = "BobDevice"; Assert.assertNull(mBobSession.getCrypto()); @@ -150,7 +153,7 @@ public void onSuccess(Void info) { final Credentials bobCredentials = mBobSession.getCredentials(); - HomeServerConnectionConfig hs = createHomeServerConfig(bobCredentials); + HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(bobCredentials); IMXStore store = new MXFileStore(hs, context); @@ -230,7 +233,7 @@ public void test03_testKeysUploadAndDownload() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - mAliceSession = createAliceAccount(true, false); + mAliceSession = mTestHelper.createAliceAccount(true, false); mAliceSession.getCredentials().deviceId = "AliceDevice"; CountDownLatch lock0 = new CountDownLatch(1); @@ -244,7 +247,7 @@ public void onSuccess(Void info) { lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("enableCrypto")); - mBobSession = createBobAccount(true, false); + mBobSession = mTestHelper.createBobAccount(true, false); CountDownLatch lock2 = new CountDownLatch(1); mBobSession.getCredentials().deviceId = "BobDevice"; mBobSession.enableCrypto(true, new TestApiCallback(lock2) { @@ -318,7 +321,7 @@ public void onSuccess(Void info) { Credentials bobCredentials = mBobSession.getCredentials(); - HomeServerConnectionConfig hs = createHomeServerConfig(bobCredentials); + HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(bobCredentials); IMXStore store = new MXFileStore(hs, context); @@ -416,7 +419,7 @@ public void test04_testEnsureOlmSessionsForUsers() throws Exception { Context context = InstrumentationRegistry.getContext(); - mAliceSession = createAliceAccount(true, false); + mAliceSession = mTestHelper.createAliceAccount(true, false); final Map results = new HashMap<>(); mAliceSession.getCredentials().deviceId = "AliceDevice"; @@ -434,7 +437,7 @@ public void onSuccess(Void info) { lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("enableCryptoAlice")); - mBobSession = createBobAccount(true, false); + mBobSession = mTestHelper.createBobAccount(true, false); CountDownLatch lock2 = new CountDownLatch(1); mBobSession.enableCrypto(true, new TestApiCallback(lock2) { @@ -486,7 +489,7 @@ public void onSuccess(MXUsersDevicesMap info) { Credentials bobCredentials = mBobSession.getCredentials(); - HomeServerConnectionConfig hs = createHomeServerConfig(bobCredentials); + HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(bobCredentials); IMXStore store = new MXFileStore(hs, context); @@ -580,7 +583,7 @@ public void test05_testRoomIsEncrypted() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - mBobSession = createBobAccount(true, false); + mBobSession = mTestHelper.createBobAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); mBobSession.enableCrypto(true, new TestApiCallback(lock0) { @@ -842,7 +845,7 @@ public void test09_testAliceInAEncryptedRoomAfterInitialSync() throws Exception mAliceSession.clear(context); - HomeServerConnectionConfig hs = createHomeServerConfig(aliceCredentials); + HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(aliceCredentials); IMXStore store = new MXFileStore(hs, context); @@ -974,7 +977,7 @@ public void onSuccess(Void info) { aliceCredentials2.refreshToken = aliceCredentials.refreshToken; aliceCredentials2.deviceId = "AliceNewDevice"; - HomeServerConnectionConfig hs = createHomeServerConfig(aliceCredentials2); + HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(aliceCredentials2); IMXStore store = new MXFileStore(hs, context); @@ -1059,7 +1062,7 @@ public void test11_testAliceAndBobInAEncryptedRoomBackPaginationFromMemoryStore( Credentials bobCredentials = mBobSession.getCredentials(); mBobSession.clear(context); - HomeServerConnectionConfig hs = createHomeServerConfig(bobCredentials); + HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(bobCredentials); IMXStore store = new MXFileStore(hs, context); @@ -1768,7 +1771,7 @@ public void onToDeviceEvent(Event event) { mAliceSession.getDataHandler().addListener(aliceEventListener); // login with a new device id - MXSession bobSession2 = logIntoBobAccount(mBobSession.getMyUserId(), true, true); + MXSession bobSession2 = mTestHelper.logIntoBobAccount(mBobSession.getMyUserId(), true, true); String bobDeviceId2 = bobSession2.getCredentials().deviceId; Assert.assertNotEquals(bobDeviceId2, bobDeviceId1); @@ -1888,11 +1891,11 @@ public void onSuccess(Void info) { lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("alicelogout")); - MXSession bobSession2 = logIntoBobAccount(mBobSession.getMyUserId(), true, true); + MXSession bobSession2 = mTestHelper.logIntoBobAccount(mBobSession.getMyUserId(), true, true); Assert.assertNotNull(bobSession2); bobSession2.getCrypto().setWarnOnUnknownDevices(false); - MXSession mAliceSession2 = logIntoAliceAccount(mAliceSession.getMyUserId(), true, true); + MXSession mAliceSession2 = mTestHelper.logIntoAliceAccount(mAliceSession.getMyUserId(), true, true); Assert.assertNotNull(mAliceSession2); mAliceSession2.getCrypto().setWarnOnUnknownDevices(false); @@ -2254,7 +2257,7 @@ public void onSuccess(byte[] info) { aliceCredentials2.refreshToken = aliceCredentials.refreshToken; aliceCredentials2.deviceId = "AliceNewDevice"; - HomeServerConnectionConfig hs = createHomeServerConfig(aliceCredentials2); + HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(aliceCredentials2); IMXStore store = new MXFileStore(hs, context); @@ -2398,8 +2401,8 @@ public void test25_testLeftAndJoinedBob() throws Exception { final Map results = new HashMap<>(); - mAliceSession = createAliceAccount(true, false); - mBobSession = createBobAccount(true, false); + mAliceSession = mTestHelper.createAliceAccount(true, false); + mBobSession = mTestHelper.createBobAccount(true, false); CountDownLatch lock_1 = new CountDownLatch(2); @@ -2487,7 +2490,7 @@ public void onSuccess(Void info) { Credentials bobCredentials = mBobSession.getCredentials(); mBobSession.clear(context); - MXSession bobSession2 = logIntoBobAccount(mBobSession.getMyUserId(), true, true); + MXSession bobSession2 = mTestHelper.logIntoBobAccount(mBobSession.getMyUserId(), true, true); Assert.assertNotNull(bobSession2); Assert.assertTrue(bobSession2.isCryptoEnabled()); Assert.assertNotEquals(bobSession2.getCrypto().getMyDevice().deviceId, bobCredentials.deviceId); @@ -2849,8 +2852,8 @@ public void test27_testEnableEncryptionAfterNonEncryptedMessages() throws Except final String messageFromAlice = "Hello I'm Alice!"; final String message2FromAlice = "I'm still Alice!"; - mAliceSession = createAliceAccount(true, false); - mBobSession = createBobAccount(true, false); + mAliceSession = mTestHelper.createAliceAccount(true, false); + mBobSession = mTestHelper.createBobAccount(true, false); CountDownLatch lock00b = new CountDownLatch(2); mAliceSession.enableCrypto(true, new TestApiCallback(lock00b) { @@ -2916,7 +2919,7 @@ public void onSuccess(Void info) { Credentials bobCredentials = mBobSession.getCredentials(); mBobSession.clear(context); - MXSession bobSession2 = logIntoBobAccount(mBobSession.getMyUserId(), true, true); + MXSession bobSession2 = mTestHelper.logIntoBobAccount(mBobSession.getMyUserId(), true, true); Assert.assertNotNull(bobSession2); Assert.assertTrue(bobSession2.isCryptoEnabled()); Assert.assertNotEquals(bobSession2.getCrypto().getMyDevice().deviceId, bobCredentials.deviceId); @@ -2991,7 +2994,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("lock1")); // - Alice adds a new device - final MXSession mAliceSession2 = logIntoAliceAccount(mAliceSession.getMyUserId(), true, true); + final MXSession mAliceSession2 = mTestHelper.logIntoAliceAccount(mAliceSession.getMyUserId(), true, true); Assert.assertNotNull(mAliceSession2); // - Alice and Bob start sharing a room again @@ -3183,7 +3186,7 @@ public void onToDeviceEvent(Event event) { private void doE2ETestWithAliceInARoom() throws Exception { final Map results = new HashMap<>(); - mAliceSession = createAliceAccount(true, false); + mAliceSession = mTestHelper.createAliceAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); mAliceSession.enableCrypto(true, new TestApiCallback(lock0) { @@ -3231,7 +3234,7 @@ private void doE2ETestWithAliceAndBobInARoom(boolean cryptedBob) throws Exceptio Room room = mAliceSession.getDataHandler().getRoom(mRoomId); - mBobSession = createBobAccount(true, false); + mBobSession = mTestHelper.createBobAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); mBobSession.enableCrypto(cryptedBob, new TestApiCallback(lock0) { @@ -3330,7 +3333,7 @@ private void doE2ETestWithAliceAndBobAndSamInARoom() throws Exception { Room room = mAliceSession.getDataHandler().getRoom(mRoomId); - mSamSession = createSamAccount(true, false); + mSamSession = mTestHelper.createSamAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); mSamSession.enableCrypto(true, new TestApiCallback(lock0) { diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/ExportEncryptionTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/ExportEncryptionTest.java index f40145453..98706998e 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/ExportEncryptionTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/ExportEncryptionTest.java @@ -23,18 +23,16 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; -import org.matrix.androidsdk.common.AbsIntegrationTest; -import org.matrix.androidsdk.crypto.MXMegolmExportEncryption; /** * Unit tests ExportEncryptionTest. */ @RunWith(AndroidJUnit4.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class ExportEncryptionTest extends AbsIntegrationTest { +public class ExportEncryptionTest { @Test - public void checkExportError1() throws Exception { + public void checkExportError1() { String password = "password"; String input = "-----"; boolean failed = false; @@ -49,7 +47,7 @@ public void checkExportError1() throws Exception { } @Test - public void checkExportError2() throws Exception { + public void checkExportError2() { String password = "password"; String input = "-----BEGIN MEGOLM SESSION DATA-----\n" + "-----"; boolean failed = false; @@ -64,7 +62,7 @@ public void checkExportError2() throws Exception { } @Test - public void checkExportError3() throws Exception { + public void checkExportError3() { String password = "password"; String input = "-----BEGIN MEGOLM SESSION DATA-----\n" + " AXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" + @@ -82,7 +80,7 @@ public void checkExportError3() throws Exception { } @Test - public void checkExportDecrypt1() throws Exception { + public void checkExportDecrypt1() { String password = "password"; String input = "-----BEGIN MEGOLM SESSION DATA-----\nAXNhbHRzYWx0c2FsdHNhbHSIiIiIiIiIiIiIiIiIiIiIAAAACmIRUW2OjZ3L2l6j9h0lHlV3M2dx\n" + "cissyYBxjsfsAndErh065A8=\n-----END MEGOLM SESSION DATA-----"; @@ -101,7 +99,7 @@ public void checkExportDecrypt1() throws Exception { } @Test - public void checkExportDecrypt2() throws Exception { + public void checkExportDecrypt2() { String password = "betterpassword"; String input = "-----BEGIN MEGOLM SESSION DATA-----\nAW1vcmVzYWx0bW9yZXNhbHT//////////wAAAAAAAAAAAAAD6KyBpe1Niv5M5NPm4ZATsJo5nghk\n" + "KYu63a0YQ5DRhUWEKk7CcMkrKnAUiZny\n-----END MEGOLM SESSION DATA-----"; @@ -120,7 +118,7 @@ public void checkExportDecrypt2() throws Exception { } @Test - public void checkExportDecrypt3() throws Exception { + public void checkExportDecrypt3() { String password = "SWORDFISH"; String input = "-----BEGIN MEGOLM SESSION DATA-----\nAXllc3NhbHR5Z29vZG5lc3P//////////wAAAAAAAAAAAAAD6OIW+Je7gwvjd4kYrb+49gKCfExw\n" + "MgJBMD4mrhLkmgAngwR1pHjbWXaoGybtiAYr0moQ93GrBQsCzPbvl82rZhaXO3iH5uHo/RCEpOqp\nPgg29363BGR+/Ripq/VCLKGNbw==\n-----END MEGOLM SESSION DATA-----"; @@ -139,7 +137,7 @@ public void checkExportDecrypt3() throws Exception { } @Test - public void checkExportEncrypt1() throws Exception { + public void checkExportEncrypt1() { String password = "password"; String expectedString = "plain"; String decodedString = null; @@ -157,7 +155,7 @@ public void checkExportEncrypt1() throws Exception { } @Test - public void checkExportEncrypt2() throws Exception { + public void checkExportEncrypt2() { String password = "betterpassword"; String expectedString = "Hello, World"; String decodedString = null; @@ -175,7 +173,7 @@ public void checkExportEncrypt2() throws Exception { } @Test - public void checkExportEncrypt3() throws Exception { + public void checkExportEncrypt3() { String password = "SWORDFISH"; String expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically"; String decodedString = null; @@ -193,7 +191,7 @@ public void checkExportEncrypt3() throws Exception { } @Test - public void checkExportEncrypt4() throws Exception { + public void checkExportEncrypt4() { String password = "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword" + "passwordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpasswordpassword"; String expectedString = "alphanumericallyalphanumericallyalphanumericallyalphanumerically"; From 4512a52ce916cd4f4d11b61ee986a5adb46bd5fa Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 20 Aug 2018 11:46:28 +0200 Subject: [PATCH 005/236] Testing : remove gradle double dependencie --- matrix-sdk/build.gradle | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/matrix-sdk/build.gradle b/matrix-sdk/build.gradle index a336199bf..91da93097 100644 --- a/matrix-sdk/build.gradle +++ b/matrix-sdk/build.gradle @@ -145,11 +145,9 @@ dependencies { testImplementation 'junit:junit:4.12' testImplementation 'org.hamcrest:hamcrest-library:1.3' testImplementation 'org.apache.maven:maven-ant-tasks:2.1.3' // fixes issue on linux/mac - - // Robolectric testImplementation "org.robolectric:robolectric:3.8" - testImplementation 'junit:junit:4.12' + // Robolectric androidTestImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support:support-annotations:27.1.1' androidTestImplementation 'com.android.support.test:runner:1.0.2' From 8e5f689014eddda2238c0be53e512ec4b96013f1 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 20 Aug 2018 11:57:52 +0200 Subject: [PATCH 006/236] Testing : start introducing lazy loading test scenarii --- .../lazyloading/LazyLoadingScenarioData.java | 37 +++++ .../lazyloading/LazyLoadingTestHelper.java | 124 ++++++++++++++ .../androidsdk/lazyloading/RoomStateTest.java | 156 ++++++++++++++++++ .../matrix/androidsdk/data/EventTimeline.java | 7 +- 4 files changed, 319 insertions(+), 5 deletions(-) create mode 100644 matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingScenarioData.java create mode 100644 matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java create mode 100644 matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingScenarioData.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingScenarioData.java new file mode 100644 index 000000000..98d6a7160 --- /dev/null +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingScenarioData.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.lazyloading; + +import org.matrix.androidsdk.MXSession; + + +/** + * Data holder for lazy loading tests + * The sessions are not synced by default as you want to perform some custom tests + */ +public class LazyLoadingScenarioData { + final MXSession aliceSession; + final MXSession bobSession; + final MXSession samSession; + final String roomId; + + public LazyLoadingScenarioData(MXSession aliceSession, MXSession bobSession, MXSession samSession, String roomId) { + this.aliceSession = aliceSession; + this.bobSession = bobSession; + this.samSession = samSession; + this.roomId = roomId; + } +} \ No newline at end of file diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java new file mode 100644 index 000000000..262aa9aa4 --- /dev/null +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java @@ -0,0 +1,124 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.lazyloading; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; + +import org.matrix.androidsdk.MXSession; +import org.matrix.androidsdk.common.CommonTestHelper; +import org.matrix.androidsdk.common.TestApiCallback; +import org.matrix.androidsdk.common.TestConstants; +import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.data.RoomState; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * + */ +public class LazyLoadingTestHelper { + + private final CommonTestHelper mTestHelper; + + public LazyLoadingTestHelper(CommonTestHelper mCommonTestHelper) { + mTestHelper = mCommonTestHelper; + } + + /** + * Create a base scenario for all lazy loading tests + * Common initial conditions: + * - Alice, Bob in a room + * - Charlie joins the room + * - Dave is invited + * - Alice sends 50 messages + * - Bob sends one message + * - Alice sends 50 messages + * - Alice makes an initial /sync with lazy-loading enabled or not + * + * @return initialized data + */ + public LazyLoadingScenarioData createScenario() throws Exception { + MXSession bobSession = mTestHelper.createBobAccount(true, false); + MXSession aliceSession = mTestHelper.createAliceAccount(true, false); + MXSession samSession = mTestHelper.createSamAccount(true, false); + + final String aliceId = aliceSession.getMyUserId(); + final String bobId = bobSession.getMyUserId(); + final String samId = samSession.getMyUserId(); + + final Map results = new HashMap<>(); + CountDownLatch latch = new CountDownLatch(1); + bobSession.createRoom(new TestApiCallback(latch) { + @Override + public void onSuccess(String info) { + results.put("roomId", info); + super.onSuccess(info); + } + }); + latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + + final String roomId = results.get("roomId"); + final Room bobRoom = bobSession.getDataHandler().getRoom(roomId); + + //update name and join rules + latch = new CountDownLatch(1); + bobRoom.updateName("LazyLoading Test Room", new TestApiCallback(latch)); + latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + + latch = new CountDownLatch(1); + bobRoom.updateJoinRules(RoomState.JOIN_RULE_PUBLIC, new TestApiCallback(latch)); + latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + + // sam join + latch = new CountDownLatch(1); + samSession.joinRoom(roomId, new TestApiCallback(latch)); + latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + + //alice join + latch = new CountDownLatch(1); + aliceSession.joinRoom(roomId, new TestApiCallback(latch)); + latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + + final Room aliceRoom = aliceSession.getDataHandler().getStore().getRoom(roomId); + + //invite dave + latch = new CountDownLatch(1); + bobRoom.invite("@dave:localhost:8480", new TestApiCallback(latch)); + latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + + // Send messages + mTestHelper.sendTextMessage(aliceRoom, "Alice message", 50); + mTestHelper.sendTextMessage(bobRoom, "Bob message", 1); + mTestHelper.sendTextMessage(aliceRoom, "Alice message", 50); + + // Clear Alice session and open new one + final Context context = InstrumentationRegistry.getContext(); + aliceSession.clear(context); + bobSession.clear(context); + samSession.clear(context); + + aliceSession = mTestHelper.logIntoAliceAccount(aliceId, false, false); + bobSession = mTestHelper.logIntoBobAccount(bobId, false, false); + samSession = mTestHelper.logIntoSamAccount(samId, false, false); + return new LazyLoadingScenarioData(aliceSession, bobSession, samSession, roomId); + + } + +} diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java new file mode 100644 index 000000000..ceeb62c78 --- /dev/null +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -0,0 +1,156 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.lazyloading; + +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Assert; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.matrix.androidsdk.common.CommonTestHelper; +import org.matrix.androidsdk.common.TestConstants; +import org.matrix.androidsdk.data.EventTimeline; +import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.rest.callback.SimpleApiCallback; +import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.util.Log; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class RoomStateTest { + + private CommonTestHelper mTestHelper = new CommonTestHelper(); + private LazyLoadingTestHelper mLazyLoadingTestHelper = new LazyLoadingTestHelper(mTestHelper); + + @Test + public void RoomState_InitialSync_ShouldLoadAllMembers() throws Exception { + RoomState_InitialSync(false); + } + + private void RoomState_InitialSync(final boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); + mTestHelper.syncSession(data.aliceSession, false); + final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); + if (withLazyLoading) { + Assert.assertEquals(1, aliceRoom.getMembers().size()); + Assert.assertEquals(1, aliceRoom.getJoinedMembers().size()); + } else { + Assert.assertEquals(4, aliceRoom.getMembers().size()); + Assert.assertEquals(3, aliceRoom.getJoinedMembers().size()); + } + } + + @Test + public void RoomState_IncomingMessage_ShouldLoadAllMembers() throws Exception { + RoomState_IncomingMessage(false); + } + + private void RoomState_IncomingMessage(final boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); + mTestHelper.syncSession(data.aliceSession, false); + mTestHelper.syncSession(data.samSession, false); + final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); + final CountDownLatch lock = new CountDownLatch(1); + aliceRoom.getLiveTimeLine().addEventTimelineListener(new EventTimeline.EventTimelineListener() { + @Override + public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { + lock.countDown(); + } + }); + final Room samRoom = data.samSession.getDataHandler().getRoom(data.roomId); + mTestHelper.sendTextMessage(samRoom, "A message from Sam", 1); + lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + if (withLazyLoading) { + Assert.assertEquals(2, aliceRoom.getMembers().size()); + Assert.assertEquals(2, aliceRoom.getJoinedMembers().size()); + } else { + Assert.assertEquals(4, aliceRoom.getMembers().size()); + Assert.assertEquals(3, aliceRoom.getJoinedMembers().size()); + } + } + + @Test + public void RoomState_BackPaginate_ShouldLoadAllMembers() throws Exception { + RoomState_BackPaginate(false); + } + + public void RoomState_BackPaginate(final boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); + mTestHelper.syncSession(data.aliceSession, false); + final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); + final CountDownLatch lock = new CountDownLatch(1); + final EventTimeline liveTimeline = aliceRoom.getLiveTimeLine(); + liveTimeline.addEventTimelineListener(new EventTimeline.EventTimelineListener() { + int messageCount = 0; + + @Override + public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { + messageCount++; + if (messageCount == 50) { + if (withLazyLoading) { + Assert.assertNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); + Assert.assertNull(liveTimeline.getState().getMember(data.samSession.getMyUserId())); + Assert.assertNull(roomState.getMember(data.bobSession.getMyUserId())); + } + Assert.assertNotNull(liveTimeline.getState().getMember(data.aliceSession.getMyUserId())); + } else if (messageCount == 51) { + if (withLazyLoading) { + Assert.assertNull(roomState.getMember(data.samSession.getMyUserId())); + Assert.assertNull(liveTimeline.getState().getMember(data.samSession.getMyUserId())); + } + Assert.assertNotNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); + } else if (messageCount >= 110) { + Assert.assertNotNull(liveTimeline.getState().getMember(data.aliceSession.getMyUserId())); + Assert.assertNotNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); + Assert.assertNotNull(liveTimeline.getState().getMember(data.samSession.getMyUserId())); + lock.countDown(); + } + } + }); + recursiveBackPaginate(liveTimeline, 0, 30, 120); + boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + Assert.assertEquals(true, handled); + } + + /** + * This method run backPagination until the maxEventCount is reached. + * + * @param liveTimeline the timeline upon which back pagination is launched + * @param currentEventCount the current event count, start at 0 + * @param eventCountStep the step between each method invoke + * @param maxEventCount the max event count to reach before stopping + */ + private void recursiveBackPaginate(final EventTimeline liveTimeline, final int currentEventCount, final int eventCountStep, final int maxEventCount) { + liveTimeline.backPaginate(eventCountStep, new SimpleApiCallback() { + @Override + public void onSuccess(Integer info) { + super.onSuccess(info); + int realStep = Math.min(eventCountStep, info); + int newEventCount = currentEventCount + realStep; + if (newEventCount < maxEventCount) { + recursiveBackPaginate(liveTimeline, newEventCount, eventCountStep, maxEventCount); + } + } + }); + } + +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index 5ea69ed9c..f17831f44 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -1040,7 +1040,7 @@ private void manageBackEvents(int maxEventCount, final ApiCallback call if ((mSnapshotEvents.size() < MAX_EVENT_COUNT_PER_PAGINATION) && mIsLastBackChunk) { mCanBackPaginate = false; } - + mIsBackPaginating = false; if (callback != null) { try { callback.onSuccess(count); @@ -1048,8 +1048,6 @@ private void manageBackEvents(int maxEventCount, final ApiCallback call Log.e(LOG_TAG, "requestHistory exception " + e.getMessage(), e); } } - - mIsBackPaginating = false; } /** @@ -1595,8 +1593,7 @@ public void onSuccess(List stateEvents) { // warn that there was a flush initHistory(); mDataHandler.onRoomFlush(mRoomId); - } - else { + } else { Log.d(LOG_TAG, "checkStateEventRedaction: the redacted event is unknown. Fetch it from the homeserver"); checkStateEventRedactionWithHomeserver(eventId); } From fc76b2cc2dd36b3c3a31a8f12a80d99dfad603a6 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 21 Aug 2018 16:46:40 +0200 Subject: [PATCH 007/236] Testing : room state testing permalink and pagination --- .../androidsdk/common/CommonTestHelper.java | 25 ++- .../lazyloading/LazyLoadingScenarioData.java | 4 +- .../lazyloading/LazyLoadingTestHelper.java | 11 +- .../androidsdk/lazyloading/RoomStateTest.java | 142 +++++++++++++++++- .../matrix/androidsdk/data/EventTimeline.java | 26 +++- 5 files changed, 195 insertions(+), 13 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index c8531e069..45bd62f38 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -28,6 +28,7 @@ import org.matrix.androidsdk.MXDataHandler; import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.data.RoomMediaMessage; import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.data.store.MXFileStore; import org.matrix.androidsdk.listeners.MXEventListener; @@ -39,7 +40,9 @@ import org.matrix.androidsdk.rest.model.login.RegistrationParams; import org.matrix.androidsdk.util.JsonUtils; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.Callable; @@ -138,7 +141,8 @@ public void onCryptoSyncComplete() { * @param nbOfMessages the number of time the message will be sent * @throws Exception */ - public void sendTextMessage(@Nonnull final Room room, @Nonnull final String message, final int nbOfMessages) throws Exception { + public List sendTextMessage(@Nonnull final Room room, @Nonnull final String message, final int nbOfMessages) throws Exception { + final List sentEvents = new ArrayList<>(nbOfMessages); final CountDownLatch latch = new CountDownLatch(nbOfMessages); final MXEventListener onEventsentListener = new MXEventListener() { @Override @@ -149,10 +153,27 @@ public void onEventSent(Event event, String prevEventId) { }; room.addEventListener(onEventsentListener); for (int i = 0; i < nbOfMessages; i++) { - room.sendTextMessage(message, null, FORMAT_MATRIX_HTML, null); + room.sendTextMessage(message, null, FORMAT_MATRIX_HTML, new RoomMediaMessage.EventCreationListener() { + @Override + public void onEventCreated(RoomMediaMessage roomMediaMessage) { + final Event sentEvent = roomMediaMessage.getEvent(); + sentEvents.add(sentEvent); + } + + @Override + public void onEventCreationFailed(RoomMediaMessage roomMediaMessage, String errorMessage) { + + } + + @Override + public void onEncryptionFailed(RoomMediaMessage roomMediaMessage) { + + } + }); } latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); room.removeEventListener(onEventsentListener); + return sentEvents; } diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingScenarioData.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingScenarioData.java index 98d6a7160..9b5903b07 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingScenarioData.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingScenarioData.java @@ -27,11 +27,13 @@ public class LazyLoadingScenarioData { final MXSession bobSession; final MXSession samSession; final String roomId; + final String bobMessageId; - public LazyLoadingScenarioData(MXSession aliceSession, MXSession bobSession, MXSession samSession, String roomId) { + public LazyLoadingScenarioData(MXSession aliceSession, MXSession bobSession, MXSession samSession, String roomId, String bobMessageId) { this.aliceSession = aliceSession; this.bobSession = bobSession; this.samSession = samSession; this.roomId = roomId; + this.bobMessageId = bobMessageId; } } \ No newline at end of file diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java index 262aa9aa4..376e22b18 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java @@ -24,8 +24,10 @@ import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.rest.model.Event; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -104,9 +106,10 @@ public void onSuccess(String info) { latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); // Send messages - mTestHelper.sendTextMessage(aliceRoom, "Alice message", 50); - mTestHelper.sendTextMessage(bobRoom, "Bob message", 1); - mTestHelper.sendTextMessage(aliceRoom, "Alice message", 50); + final List aliceFirstMessages = mTestHelper.sendTextMessage(aliceRoom, "Alice message", 50); + final List bobMessages = mTestHelper.sendTextMessage(bobRoom, "Bob message", 1); + final List aliceLastMessages = mTestHelper.sendTextMessage(aliceRoom, "Alice message", 50); + final String bobMessageId = bobMessages.isEmpty() ? null : bobMessages.get(0).eventId; // Clear Alice session and open new one final Context context = InstrumentationRegistry.getContext(); @@ -117,7 +120,7 @@ public void onSuccess(String info) { aliceSession = mTestHelper.logIntoAliceAccount(aliceId, false, false); bobSession = mTestHelper.logIntoBobAccount(bobId, false, false); samSession = mTestHelper.logIntoSamAccount(samId, false, false); - return new LazyLoadingScenarioData(aliceSession, bobSession, samSession, roomId); + return new LazyLoadingScenarioData(aliceSession, bobSession, samSession, roomId, bobMessageId); } diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index ceeb62c78..cd5e7703a 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -29,7 +29,6 @@ import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.model.Event; -import org.matrix.androidsdk.util.Log; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -131,23 +130,156 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro Assert.assertEquals(true, handled); } + @Test + public void RoomState_Permalink_ShouldLoadAllMembers() throws Exception { + RoomState_Permalink(false); + } + + public void RoomState_Permalink(final boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); + mTestHelper.syncSession(data.aliceSession, false); + final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); + final Event lastEvent = aliceRoom.getDataHandler().getStore().getLatestEvent(data.roomId); + final EventTimeline eventTimeline = new EventTimeline(data.aliceSession.getDataHandler(), lastEvent.roomId, lastEvent.eventId); + final CountDownLatch lock = new CountDownLatch(1); + eventTimeline.resetPaginationAroundInitialEvent(10, new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + super.onSuccess(info); + lock.countDown(); + } + }); + boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + Assert.assertEquals(true, handled); + final RoomState roomState = eventTimeline.getState(); + if (withLazyLoading) { + Assert.assertEquals(1, roomState.getMembers().size()); + Assert.assertEquals(1, aliceRoom.getJoinedMembers().size()); + } else { + Assert.assertEquals(4, roomState.getMembers().size()); + Assert.assertEquals(3, aliceRoom.getJoinedMembers().size()); + } + } + + @Test + public void RoomState_PermalinkWithBackPagination_ShouldLoadAllMembers() throws Exception { + RoomState_PermalinkWithBackPagination(false); + } + + public void RoomState_PermalinkWithBackPagination(final boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); + mTestHelper.syncSession(data.aliceSession, false); + final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); + final CountDownLatch lock = new CountDownLatch(1); + final Event lastEvent = aliceRoom.getDataHandler().getStore().getLatestEvent(data.roomId); + final EventTimeline eventTimeline = new EventTimeline(data.aliceSession.getDataHandler(), lastEvent.roomId, lastEvent.eventId); + eventTimeline.addEventTimelineListener(new EventTimeline.EventTimelineListener() { + int messageCount = 0; + + @Override + public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { + messageCount++; + if (messageCount == 50) { + if (withLazyLoading) { + Assert.assertNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); + Assert.assertNull(eventTimeline.getState().getMember(data.samSession.getMyUserId())); + Assert.assertNull(roomState.getMember(data.bobSession.getMyUserId())); + } + Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); + } else if (messageCount == 51) { + if (withLazyLoading) { + Assert.assertNull(roomState.getMember(data.samSession.getMyUserId())); + Assert.assertNull(eventTimeline.getState().getMember(data.samSession.getMyUserId())); + } + Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); + } else if (messageCount >= 110) { + Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); + Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); + Assert.assertNotNull(eventTimeline.getState().getMember(data.samSession.getMyUserId())); + lock.countDown(); + } + } + }); + eventTimeline.resetPaginationAroundInitialEvent(0, new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + super.onSuccess(info); + recursiveBackPaginate(eventTimeline, 0, 30, 120); + } + }); + boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + Assert.assertEquals(true, handled); + } + + @Test + public void RoomState_PermalinkWithForwardPagination_ShouldLoadAllMembers() throws Exception { + RoomState_PermalinkWithForwardPagination(false); + } + + // Test lazy loaded members sent by the HS when paginating forward + // - Come back to Bob message + // - We should only know Bob membership + // - Paginate forward to get Alice next message + // - We should know Alice membership now + public void RoomState_PermalinkWithForwardPagination(final boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); + mTestHelper.syncSession(data.aliceSession, false); + final CountDownLatch lock = new CountDownLatch(1); + final EventTimeline eventTimeline = new EventTimeline(data.aliceSession.getDataHandler(), data.roomId, data.bobMessageId); + eventTimeline.addEventTimelineListener(new EventTimeline.EventTimelineListener() { + int messageCount = 0; + + @Override + public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { + messageCount++; + if (messageCount == 1) { + Assert.assertEquals(event.sender, data.bobSession.getMyUserId()); + if (withLazyLoading) { + Assert.assertNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); + Assert.assertNull(eventTimeline.getState().getMember(data.samSession.getMyUserId())); + } else { + Assert.assertNotNull(roomState.getMember(data.aliceSession.getMyUserId())); + } + Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); + } else if (messageCount == 2) { + Assert.assertEquals(event.sender, data.aliceSession.getMyUserId()); + if (withLazyLoading) { + Assert.assertNull(eventTimeline.getState().getMember(data.samSession.getMyUserId())); + } + Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); + Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); + lock.countDown(); + } + } + }); + eventTimeline.resetPaginationAroundInitialEvent(0, new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + super.onSuccess(info); + eventTimeline.forwardPaginate(new SimpleApiCallback()); + } + }); + boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + Assert.assertEquals(true, handled); + } + /** * This method run backPagination until the maxEventCount is reached. * - * @param liveTimeline the timeline upon which back pagination is launched + * @param timeline the timeline upon which back pagination is made * @param currentEventCount the current event count, start at 0 * @param eventCountStep the step between each method invoke * @param maxEventCount the max event count to reach before stopping */ - private void recursiveBackPaginate(final EventTimeline liveTimeline, final int currentEventCount, final int eventCountStep, final int maxEventCount) { - liveTimeline.backPaginate(eventCountStep, new SimpleApiCallback() { + private void recursiveBackPaginate(final EventTimeline timeline, final int currentEventCount, final int eventCountStep, final int maxEventCount) { + timeline.backPaginate(eventCountStep, new SimpleApiCallback() { @Override public void onSuccess(Integer info) { super.onSuccess(info); int realStep = Math.min(eventCountStep, info); int newEventCount = currentEventCount + realStep; if (newEventCount < maxEventCount) { - recursiveBackPaginate(liveTimeline, newEventCount, eventCountStep, maxEventCount); + recursiveBackPaginate(timeline, newEventCount, eventCountStep, maxEventCount); } } }); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index f17831f44..a86aa09fe 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -1514,13 +1514,37 @@ public void onUnexpectedError(Exception e) { (new android.os.Handler(Looper.getMainLooper())).post(new Runnable() { @Override public void run() { - if (null != callback) { + if (callback != null) { callback.onUnexpectedError(e); } } }); } } + + @Override + public void onNetworkError(Exception e) { + super.onNetworkError(e); + if (callback != null) { + callback.onNetworkError(e); + } + } + + @Override + public void onMatrixError(MatrixError e) { + super.onMatrixError(e); + if (callback != null) { + callback.onMatrixError(e); + } + } + + @Override + public void onUnexpectedError(Exception e) { + super.onUnexpectedError(e); + if (callback != null) { + callback.onUnexpectedError(e); + } + } }); } From 8832d38d4424db6da641e6318009d1cc8d8b886d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 14:19:08 +0200 Subject: [PATCH 008/236] Avoid using class members for test case --- .../org/matrix/androidsdk/common/Triple.java | 48 + .../matrix/androidsdk/crypto/CryptoTest.java | 926 ++++++++++-------- 2 files changed, 545 insertions(+), 429 deletions(-) create mode 100644 matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/Triple.java diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/Triple.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/Triple.java new file mode 100644 index 000000000..144ea40b0 --- /dev/null +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/Triple.java @@ -0,0 +1,48 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.common; + +import android.util.Pair; + +public class Triple { + public A first; + public B second; + public C third; + + /** + * Constructor for a Pair. + * + * @param first the first object in the Triple + * @param second the second object in the Triple + * @param third the third object in the Triple + */ + public Triple(A first, B second, C third) { + this.first = first; + this.second = second; + this.third = third; + } + + /** + * Constructor from a Pair and another element + * + * @param pair + * @param third + */ + public Triple(Pair pair, C third) { + this(pair.first, pair.second, third); + } +} diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index bf3ff6ab8..406a542fd 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -24,6 +24,7 @@ import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import android.text.TextUtils; +import android.util.Pair; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; @@ -39,6 +40,7 @@ import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.common.TestApiCallback; import org.matrix.androidsdk.common.TestConstants; +import org.matrix.androidsdk.common.Triple; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXOlmSessionResult; import org.matrix.androidsdk.crypto.data.MXUsersDevicesMap; @@ -74,16 +76,11 @@ public class CryptoTest { private CommonTestHelper mTestHelper = new CommonTestHelper(); - private static final String LOG_TAG = "CryptoTest"; private static final List messagesFromAlice = Arrays.asList("0 - Hello I'm Alice!", "4 - Go!"); private static final List messagesFromBob = Arrays.asList("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera."); - private MXSession mBobSession; - private MXSession mAliceSession; - private MXSession mSamSession; - private String mRoomId; private int mMessagesCount; private int mReceivedMessagesFromAlice; @@ -95,13 +92,13 @@ public void test01_testCryptoNoDeviceId() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - mBobSession = mTestHelper.createBobAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(true, false); - Assert.assertNull(mBobSession.getCrypto()); - mBobSession.getCredentials().deviceId = null; + Assert.assertNull(bobSession.getCrypto()); + bobSession.getCredentials().deviceId = null; CountDownLatch lock1 = new CountDownLatch(1); - mBobSession.enableCrypto(true, new TestApiCallback(lock1) { + bobSession.enableCrypto(true, new TestApiCallback(lock1) { @Override public void onSuccess(Void info) { results.put("enableCrypto", "enableCrypto"); @@ -111,10 +108,10 @@ public void onSuccess(Void info) { lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("enableCrypto")); - Assert.assertNotNull(mBobSession.getCrypto()); - Assert.assertNotNull(mBobSession.getCredentials().deviceId); + Assert.assertNotNull(bobSession.getCrypto()); + Assert.assertNotNull(bobSession.getCredentials().deviceId); - mBobSession.clear(context); + bobSession.clear(context); } @Test @@ -123,13 +120,13 @@ public void test02_testCryptoPersistenceInStore() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - mBobSession = mTestHelper.createBobAccount(true, false); - mBobSession.getCredentials().deviceId = "BobDevice"; + MXSession bobSession = mTestHelper.createBobAccount(true, false); + bobSession.getCredentials().deviceId = "BobDevice"; - Assert.assertNull(mBobSession.getCrypto()); + Assert.assertNull(bobSession.getCrypto()); CountDownLatch lock0 = new CountDownLatch(1); - mBobSession.enableCrypto(true, new TestApiCallback(lock0) { + bobSession.enableCrypto(true, new TestApiCallback(lock0) { @Override public void onSuccess(Void info) { results.put("enableCrypto", "enableCrypto"); @@ -139,19 +136,19 @@ public void onSuccess(Void info) { lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("enableCrypto")); - Assert.assertNotNull(mBobSession.getCrypto()); + Assert.assertNotNull(bobSession.getCrypto()); SystemClock.sleep(1000); - final String deviceCurve25519Key = mBobSession.getCrypto().getOlmDevice().getDeviceCurve25519Key(); - final String deviceEd25519Key = mBobSession.getCrypto().getOlmDevice().getDeviceEd25519Key(); + final String deviceCurve25519Key = bobSession.getCrypto().getOlmDevice().getDeviceCurve25519Key(); + final String deviceEd25519Key = bobSession.getCrypto().getOlmDevice().getDeviceEd25519Key(); - final List myUserDevices = mBobSession.getCrypto().getUserDevices(mBobSession.getMyUserId()); + final List myUserDevices = bobSession.getCrypto().getUserDevices(bobSession.getMyUserId()); Assert.assertNotNull(myUserDevices); Assert.assertEquals(1, myUserDevices.size()); - final Credentials bobCredentials = mBobSession.getCredentials(); + final Credentials bobCredentials = bobSession.getCredentials(); HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(bobCredentials); @@ -222,7 +219,7 @@ public void onCryptoSyncComplete() { Assert.assertEquals(1, myUserDevices2.size()); Assert.assertEquals(myUserDevices2.get(0).deviceId, myUserDevices.get(0).deviceId); - mBobSession.clear(context); + bobSession.clear(context); bobSession2.clear(context); } @@ -233,11 +230,11 @@ public void test03_testKeysUploadAndDownload() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - mAliceSession = mTestHelper.createAliceAccount(true, false); - mAliceSession.getCredentials().deviceId = "AliceDevice"; + MXSession aliceSession = mTestHelper.createAliceAccount(true, false); + aliceSession.getCredentials().deviceId = "AliceDevice"; CountDownLatch lock0 = new CountDownLatch(1); - mAliceSession.enableCrypto(true, new TestApiCallback(lock0) { + aliceSession.enableCrypto(true, new TestApiCallback(lock0) { @Override public void onSuccess(Void info) { results.put("enableCrypto", "enableCrypto"); @@ -247,10 +244,10 @@ public void onSuccess(Void info) { lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("enableCrypto")); - mBobSession = mTestHelper.createBobAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(true, false); CountDownLatch lock2 = new CountDownLatch(1); - mBobSession.getCredentials().deviceId = "BobDevice"; - mBobSession.enableCrypto(true, new TestApiCallback(lock2) { + bobSession.getCredentials().deviceId = "BobDevice"; + bobSession.enableCrypto(true, new TestApiCallback(lock2) { @Override public void onSuccess(Void info) { results.put("enableCrypto2", "enableCrypto2"); @@ -261,9 +258,9 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("enableCrypto2")); CountDownLatch lock3 = new CountDownLatch(1); - mBobSession.getCrypto() + bobSession.getCrypto() .getDeviceList() - .downloadKeys(Arrays.asList(mBobSession.getMyUserId(), mAliceSession.getMyUserId()), + .downloadKeys(Arrays.asList(bobSession.getMyUserId(), aliceSession.getMyUserId()), false, new TestApiCallback>(lock3) { @Override public void onSuccess(MXUsersDevicesMap info) { @@ -277,19 +274,19 @@ public void onSuccess(MXUsersDevicesMap info) { MXUsersDevicesMap usersDevicesInfoMap = (MXUsersDevicesMap) results.get("downloadKeys"); Assert.assertEquals(2, usersDevicesInfoMap.getUserIds().size()); - Assert.assertEquals(1, usersDevicesInfoMap.getUserDeviceIds(mAliceSession.getMyUserId()).size()); + Assert.assertEquals(1, usersDevicesInfoMap.getUserDeviceIds(aliceSession.getMyUserId()).size()); - MXDeviceInfo aliceDeviceFromBobPOV = usersDevicesInfoMap.getObject("AliceDevice", mAliceSession.getMyUserId()); + MXDeviceInfo aliceDeviceFromBobPOV = usersDevicesInfoMap.getObject("AliceDevice", aliceSession.getMyUserId()); Assert.assertNotNull(aliceDeviceFromBobPOV); - Assert.assertEquals(aliceDeviceFromBobPOV.fingerprint(), mAliceSession.getCrypto().getOlmDevice().getDeviceEd25519Key()); + Assert.assertEquals(aliceDeviceFromBobPOV.fingerprint(), aliceSession.getCrypto().getOlmDevice().getDeviceEd25519Key()); // Continue testing other methods - Assert.assertNotNull(mBobSession.getCrypto().deviceWithIdentityKey(mAliceSession.getCrypto().getOlmDevice().getDeviceCurve25519Key(), - mAliceSession.getMyUserId(), MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_OLM)); + Assert.assertNotNull(bobSession.getCrypto().deviceWithIdentityKey(aliceSession.getCrypto().getOlmDevice().getDeviceCurve25519Key(), + aliceSession.getMyUserId(), MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_OLM)); Assert.assertTrue(aliceDeviceFromBobPOV.isUnknown()); CountDownLatch lock3a = new CountDownLatch(1); - mBobSession.getCrypto().setDevicesKnown(Arrays.asList(aliceDeviceFromBobPOV), + bobSession.getCrypto().setDevicesKnown(Arrays.asList(aliceDeviceFromBobPOV), new TestApiCallback(lock3a) { @Override public void onSuccess(Void info) { @@ -303,10 +300,10 @@ public void onSuccess(Void info) { Assert.assertTrue(aliceDeviceFromBobPOV.isUnverified()); CountDownLatch lock3b = new CountDownLatch(1); - mBobSession.getCrypto().setDeviceVerification( + bobSession.getCrypto().setDeviceVerification( MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED, aliceDeviceFromBobPOV.deviceId, - mAliceSession.getMyUserId(), + aliceSession.getMyUserId(), new TestApiCallback(lock3b) { @Override public void onSuccess(Void info) { @@ -319,7 +316,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("setDeviceVerification1")); Assert.assertTrue(aliceDeviceFromBobPOV.isBlocked()); - Credentials bobCredentials = mBobSession.getCredentials(); + Credentials bobCredentials = bobSession.getCredentials(); HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(bobCredentials); @@ -380,17 +377,17 @@ public void onCryptoSyncComplete() { Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); MXDeviceInfo aliceDeviceFromBobPOV2 = bobSession2.getCrypto() - .deviceWithIdentityKey(mAliceSession.getCrypto().getOlmDevice().getDeviceCurve25519Key(), - mAliceSession.getMyUserId(), MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_OLM); + .deviceWithIdentityKey(aliceSession.getCrypto().getOlmDevice().getDeviceCurve25519Key(), + aliceSession.getMyUserId(), MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_OLM); Assert.assertNotNull(aliceDeviceFromBobPOV2); - Assert.assertEquals(aliceDeviceFromBobPOV2.fingerprint(), mAliceSession.getCrypto().getOlmDevice().getDeviceEd25519Key()); + Assert.assertEquals(aliceDeviceFromBobPOV2.fingerprint(), aliceSession.getCrypto().getOlmDevice().getDeviceEd25519Key()); Assert.assertTrue(aliceDeviceFromBobPOV2.mVerified + " instead of " + MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED, aliceDeviceFromBobPOV2.mVerified == MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED); // Download again alice device CountDownLatch lock5 = new CountDownLatch(1); - bobSession2.getCrypto().getDeviceList().downloadKeys(Arrays.asList(mAliceSession.getMyUserId()), true, + bobSession2.getCrypto().getDeviceList().downloadKeys(Arrays.asList(aliceSession.getMyUserId()), true, new TestApiCallback>(lock5) { @Override public void onSuccess(MXUsersDevicesMap info) { @@ -401,15 +398,15 @@ public void onSuccess(MXUsersDevicesMap info) { lock5.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("downloadKeys2")); - MXDeviceInfo aliceDeviceFromBobPOV3 = bobSession2.getCrypto().deviceWithIdentityKey(mAliceSession.getCrypto().getOlmDevice().getDeviceCurve25519Key(), - mAliceSession.getMyUserId(), MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_OLM); + MXDeviceInfo aliceDeviceFromBobPOV3 = bobSession2.getCrypto().deviceWithIdentityKey(aliceSession.getCrypto().getOlmDevice().getDeviceCurve25519Key(), + aliceSession.getMyUserId(), MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_OLM); Assert.assertNotNull(aliceDeviceFromBobPOV3); - Assert.assertEquals(aliceDeviceFromBobPOV3.fingerprint(), mAliceSession.getCrypto().getOlmDevice().getDeviceEd25519Key()); + Assert.assertEquals(aliceDeviceFromBobPOV3.fingerprint(), aliceSession.getCrypto().getOlmDevice().getDeviceEd25519Key()); Assert.assertTrue(aliceDeviceFromBobPOV3.isBlocked()); - mAliceSession.clear(context); - mBobSession.clear(context); + aliceSession.clear(context); + bobSession.clear(context); bobSession2.clear(context); } @@ -419,14 +416,14 @@ public void test04_testEnsureOlmSessionsForUsers() throws Exception { Context context = InstrumentationRegistry.getContext(); - mAliceSession = mTestHelper.createAliceAccount(true, false); + MXSession aliceSession = mTestHelper.createAliceAccount(true, false); final Map results = new HashMap<>(); - mAliceSession.getCredentials().deviceId = "AliceDevice"; + aliceSession.getCredentials().deviceId = "AliceDevice"; CountDownLatch lock0 = new CountDownLatch(1); - mAliceSession.enableCrypto(true, new TestApiCallback(lock0) { + aliceSession.enableCrypto(true, new TestApiCallback(lock0) { @Override public void onSuccess(Void info) { results.put("enableCryptoAlice", "enableCryptoAlice"); @@ -437,10 +434,10 @@ public void onSuccess(Void info) { lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("enableCryptoAlice")); - mBobSession = mTestHelper.createBobAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(true, false); CountDownLatch lock2 = new CountDownLatch(1); - mBobSession.enableCrypto(true, new TestApiCallback(lock2) { + bobSession.enableCrypto(true, new TestApiCallback(lock2) { @Override public void onSuccess(Void info) { results.put("enableCryptoBob", "enableCryptoAlice"); @@ -452,7 +449,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("enableCryptoBob")); CountDownLatch lock3 = new CountDownLatch(1); - mBobSession.getCrypto().getDeviceList().downloadKeys(Arrays.asList(mBobSession.getMyUserId(), mAliceSession.getMyUserId()), false, + bobSession.getCrypto().getDeviceList().downloadKeys(Arrays.asList(bobSession.getMyUserId(), aliceSession.getMyUserId()), false, new TestApiCallback>(lock3) { @Override public void onSuccess(MXUsersDevicesMap map) { @@ -465,7 +462,7 @@ public void onSuccess(MXUsersDevicesMap map) { Assert.assertTrue(results.containsKey("downloadKeys")); CountDownLatch lock4 = new CountDownLatch(1); - mBobSession.getCrypto().ensureOlmSessionsForUsers(Arrays.asList(mBobSession.getMyUserId(), mAliceSession.getMyUserId()), + bobSession.getCrypto().ensureOlmSessionsForUsers(Arrays.asList(bobSession.getMyUserId(), aliceSession.getMyUserId()), new TestApiCallback>(lock4) { @Override public void onSuccess(MXUsersDevicesMap info) { @@ -481,13 +478,13 @@ public void onSuccess(MXUsersDevicesMap info) { Assert.assertEquals(1, result.getUserIds().size()); - MXOlmSessionResult sessionWithAliceDevice = result.getObject("AliceDevice", mAliceSession.getMyUserId()); + MXOlmSessionResult sessionWithAliceDevice = result.getObject("AliceDevice", aliceSession.getMyUserId()); Assert.assertNotNull(sessionWithAliceDevice); Assert.assertNotNull(sessionWithAliceDevice.mSessionId); Assert.assertEquals("AliceDevice", sessionWithAliceDevice.mDevice.deviceId); - Credentials bobCredentials = mBobSession.getCredentials(); + Credentials bobCredentials = bobSession.getCredentials(); HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(bobCredentials); @@ -553,7 +550,7 @@ public void onCryptoSyncComplete() { Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); CountDownLatch lock6 = new CountDownLatch(1); - bobSession2.getCrypto().ensureOlmSessionsForUsers(Arrays.asList(bobSession2.getMyUserId(), mAliceSession.getMyUserId()), + bobSession2.getCrypto().ensureOlmSessionsForUsers(Arrays.asList(bobSession2.getMyUserId(), aliceSession.getMyUserId()), new TestApiCallback>(lock6) { @Override public void onSuccess(MXUsersDevicesMap info) { @@ -566,13 +563,13 @@ public void onSuccess(MXUsersDevicesMap info) { MXUsersDevicesMap result2 = (MXUsersDevicesMap) results.get("ensureOlmSessionsForUsers2"); - MXOlmSessionResult sessionWithAliceDevice2 = result2.getObject("AliceDevice", mAliceSession.getMyUserId()); + MXOlmSessionResult sessionWithAliceDevice2 = result2.getObject("AliceDevice", aliceSession.getMyUserId()); Assert.assertNotNull(sessionWithAliceDevice2); Assert.assertNotNull(sessionWithAliceDevice2.mSessionId); Assert.assertEquals("AliceDevice", sessionWithAliceDevice2.mDevice.deviceId); - mBobSession.clear(context); - mAliceSession.clear(context); + bobSession.clear(context); + aliceSession.clear(context); bobSession2.clear(context); } @@ -583,10 +580,10 @@ public void test05_testRoomIsEncrypted() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - mBobSession = mTestHelper.createBobAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); - mBobSession.enableCrypto(true, new TestApiCallback(lock0) { + bobSession.enableCrypto(true, new TestApiCallback(lock0) { @Override public void onSuccess(Void info) { results.put("enableCrypto", "enableCrypto"); @@ -598,7 +595,7 @@ public void onSuccess(Void info) { mRoomId = null; CountDownLatch lock1 = new CountDownLatch(1); - mBobSession.createRoom(new TestApiCallback(lock1) { + bobSession.createRoom(new TestApiCallback(lock1) { @Override public void onSuccess(String info) { mRoomId = info; @@ -609,7 +606,7 @@ public void onSuccess(String info) { lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertNotNull(mRoomId); - Room room = mBobSession.getDataHandler().getRoom(mRoomId); + Room room = bobSession.getDataHandler().getRoom(mRoomId); Assert.assertFalse(room.isEncrypted()); @@ -626,7 +623,7 @@ public void onSuccess(Void info) { Assert.assertTrue(room.isEncrypted()); - mBobSession.clear(context); + bobSession.clear(context); } @Test @@ -635,11 +632,11 @@ public void test06_testAliceInAEncryptedRoom() throws Exception { Context context = InstrumentationRegistry.getContext(); - doE2ETestWithAliceInARoom(); + MXSession aliceSession = doE2ETestWithAliceInARoom(); final String message = "Hello myself!"; - Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -648,11 +645,11 @@ public void test06_testAliceInAEncryptedRoom() throws Exception { // the IOS client echoes the message // the android client does not - roomFromAlicePOV.sendEvent(buildTextEvent(message, mAliceSession), new TestApiCallback(lock1)); + roomFromAlicePOV.sendEvent(buildTextEvent(message, aliceSession), new TestApiCallback(lock1)); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - mAliceSession.clear(context); + aliceSession.clear(context); } @Test @@ -662,19 +659,21 @@ public void test07_testAliceAndBobInAEncryptedRoom() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + final MXSession aliceSession = pair.first; + final MXSession bobSession = pair.second; final String messageFromAlice = "Hello I'm Alice!"; - Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); CountDownLatch lock1 = new CountDownLatch(1); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new TestApiCallback(lock1) { + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new TestApiCallback(lock1) { @Override public void onMatrixError(MatrixError e) { results.put("sendEventError", e); @@ -687,12 +686,12 @@ public void onMatrixError(MatrixError e) { MXCryptoError error = (MXCryptoError) results.get("sendEventError"); Assert.assertEquals(MXCryptoError.UNKNOWN_DEVICES_CODE, error.errcode); MXUsersDevicesMap unknownDevices = (MXUsersDevicesMap) error.mExceptionData; - List deviceInfos = unknownDevices.getUserDeviceIds(mBobSession.getMyUserId()); + List deviceInfos = unknownDevices.getUserDeviceIds(bobSession.getMyUserId()); Assert.assertEquals(1, deviceInfos.size()); - Assert.assertEquals(deviceInfos.get(0), mBobSession.getCrypto().getMyDevice().deviceId); + Assert.assertEquals(deviceInfos.get(0), bobSession.getCrypto().getMyDevice().deviceId); CountDownLatch lock2 = new CountDownLatch(1); - mAliceSession.getCrypto().setDevicesKnown(Arrays.asList(mBobSession.getCrypto().getMyDevice()), new TestApiCallback(lock2) { + aliceSession.getCrypto().setDevicesKnown(Arrays.asList(bobSession.getCrypto().getMyDevice()), new TestApiCallback(lock2) { @Override public void onSuccess(Void info) { results.put("setDevicesKnown", "setDevicesKnown"); @@ -709,7 +708,7 @@ public void onSuccess(Void info) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, messageFromAlice, mAliceSession); + checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); results.put("onLiveEvent", "onLiveEvent"); lock3.countDown(); @@ -717,7 +716,7 @@ public void onLiveEvent(Event event, RoomState roomState) { } }; - mBobSession.getDataHandler().addListener(new MXEventListener() { + bobSession.getDataHandler().addListener(new MXEventListener() { @Override public void onToDeviceEvent(Event event) { results.put("onToDeviceEvent", event); @@ -727,32 +726,34 @@ public void onToDeviceEvent(Event event) { roomFromBobPOV.addEventListener(eventListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new TestApiCallback(lock3)); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new TestApiCallback(lock3)); lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertTrue(results.containsKey("onLiveEvent")); - Assert.assertEquals(MXDeviceList.TRACKING_STATUS_UP_TO_DATE, mBobSession.getCrypto().getDeviceTrackingStatus(mBobSession.getMyUserId())); - Assert.assertEquals(MXDeviceList.TRACKING_STATUS_UP_TO_DATE, mBobSession.getCrypto().getDeviceTrackingStatus(mAliceSession.getMyUserId())); + Assert.assertEquals(MXDeviceList.TRACKING_STATUS_UP_TO_DATE, bobSession.getCrypto().getDeviceTrackingStatus(bobSession.getMyUserId())); + Assert.assertEquals(MXDeviceList.TRACKING_STATUS_UP_TO_DATE, bobSession.getCrypto().getDeviceTrackingStatus(aliceSession.getMyUserId())); - Assert.assertEquals(MXDeviceList.TRACKING_STATUS_UP_TO_DATE, mAliceSession.getCrypto().getDeviceTrackingStatus(mBobSession.getMyUserId())); - Assert.assertEquals(MXDeviceList.TRACKING_STATUS_UP_TO_DATE, mAliceSession.getCrypto().getDeviceTrackingStatus(mAliceSession.getMyUserId())); + Assert.assertEquals(MXDeviceList.TRACKING_STATUS_UP_TO_DATE, aliceSession.getCrypto().getDeviceTrackingStatus(bobSession.getMyUserId())); + Assert.assertEquals(MXDeviceList.TRACKING_STATUS_UP_TO_DATE, aliceSession.getCrypto().getDeviceTrackingStatus(aliceSession.getMyUserId())); - mBobSession.clear(context); + bobSession.clear(context); } @Test public void test08_testAliceAndBobInAEncryptedRoom2() throws Exception { Log.e(LOG_TAG, "test08_testAliceAndBobInAEncryptedRoom2"); - doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + final MXSession aliceSession = pair.first; + final MXSession bobSession = pair.second; - mBobSession.getCrypto().setWarnOnUnknownDevices(false); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + bobSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -765,8 +766,8 @@ public void test08_testAliceAndBobInAEncryptedRoom2() throws Exception { MXEventListener bobEventListener = new MXEventListener() { @Override public void onLiveEvent(Event event, RoomState roomState) { - if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), mBobSession.getMyUserId())) { - checkEncryptedEvent(event, mRoomId, messagesFromAlice.get(mReceivedMessagesFromAlice), mAliceSession); + if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), bobSession.getMyUserId())) { + checkEncryptedEvent(event, mRoomId, messagesFromAlice.get(mReceivedMessagesFromAlice), aliceSession); mReceivedMessagesFromAlice++; list.get(list.size() - 1).countDown(); @@ -777,8 +778,8 @@ public void onLiveEvent(Event event, RoomState roomState) { MXEventListener aliceEventListener = new MXEventListener() { @Override public void onLiveEvent(Event event, RoomState roomState) { - if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), mAliceSession.getMyUserId())) { - checkEncryptedEvent(event, mRoomId, messagesFromBob.get(mReceivedMessagesFromBob), mBobSession); + if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), aliceSession.getMyUserId())) { + checkEncryptedEvent(event, mRoomId, messagesFromBob.get(mReceivedMessagesFromBob), bobSession); mReceivedMessagesFromBob++; list.get(list.size() - 1).countDown(); @@ -794,7 +795,7 @@ public void onLiveEvent(Event event, RoomState roomState) { list.add(new CountDownLatch(2)); final Map results = new HashMap<>(); - mBobSession.getDataHandler().addListener(new MXEventListener() { + bobSession.getDataHandler().addListener(new MXEventListener() { @Override public void onToDeviceEvent(Event event) { results.put("onToDeviceEvent", event); @@ -802,28 +803,28 @@ public void onToDeviceEvent(Event event) { } }); - roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(mReceivedMessagesFromAlice), mAliceSession), callback); + roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(mReceivedMessagesFromAlice), aliceSession), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, mReceivedMessagesFromAlice); list.add(new CountDownLatch(1)); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(mReceivedMessagesFromBob), mBobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(mReceivedMessagesFromBob), bobSession), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, mReceivedMessagesFromBob); list.add(new CountDownLatch(1)); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(mReceivedMessagesFromBob), mBobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(mReceivedMessagesFromBob), bobSession), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(2, mReceivedMessagesFromBob); list.add(new CountDownLatch(1)); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(mReceivedMessagesFromBob), mBobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(mReceivedMessagesFromBob), bobSession), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(3, mReceivedMessagesFromBob); list.add(new CountDownLatch(1)); - roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(mReceivedMessagesFromAlice), mAliceSession), callback); + roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(mReceivedMessagesFromAlice), aliceSession), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(2, mReceivedMessagesFromAlice); } @@ -835,15 +836,15 @@ public void test09_testAliceInAEncryptedRoomAfterInitialSync() throws Exception Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - doE2ETestWithAliceInARoom(); + MXSession aliceSession = doE2ETestWithAliceInARoom(); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); final String message = "Hello myself!"; - Credentials aliceCredentials = mAliceSession.getCredentials(); + Credentials aliceCredentials = aliceSession.getCredentials(); - mAliceSession.clear(context); + aliceSession.clear(context); HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(aliceCredentials); @@ -851,7 +852,7 @@ public void test09_testAliceInAEncryptedRoomAfterInitialSync() throws Exception final CountDownLatch lock1 = new CountDownLatch(1); - final MXSession mAliceSession2 = new MXSession(hs, new MXDataHandler(store, aliceCredentials), context); + final MXSession aliceSession2 = new MXSession(hs, new MXDataHandler(store, aliceCredentials), context); MXStoreListener listener = new MXStoreListener() { @Override @@ -875,8 +876,8 @@ public void onStoreOOM(String accountId, String description) { } }; - mAliceSession2.getDataHandler().getStore().addMXStoreListener(listener); - mAliceSession2.getDataHandler().getStore().open(); + aliceSession2.getDataHandler().getStore().addMXStoreListener(listener); + aliceSession2.getDataHandler().getStore().open(); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onStoreReady")); @@ -895,13 +896,13 @@ public void onCryptoSyncComplete() { } }; - mAliceSession2.getDataHandler().addListener(eventListener); - mAliceSession2.startEventStream(null); + aliceSession2.getDataHandler().addListener(eventListener); + aliceSession2.startEventStream(null); lock1b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); - Room roomFromAlicePOV2 = mAliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV2 = aliceSession2.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromAlicePOV2.isEncrypted()); @@ -913,7 +914,7 @@ public void onCryptoSyncComplete() { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, message, mAliceSession2); + checkEncryptedEvent(event, mRoomId, message, aliceSession2); lock2.countDown(); } @@ -925,7 +926,7 @@ public void onLiveEvent(Event event, RoomState roomState) { // the IOS client echoes the message // the android client does not - roomFromAlicePOV2.sendEvent(buildTextEvent(message, mAliceSession2), new TestApiCallback(lock2) { + roomFromAlicePOV2.sendEvent(buildTextEvent(message, aliceSession2), new TestApiCallback(lock2) { @Override public void onSuccess(Void info) { results.put("sendEvent", "sendEvent"); @@ -936,7 +937,7 @@ public void onSuccess(Void info) { lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("sendEvent")); - mAliceSession2.clear(context); + aliceSession2.clear(context); } @Test @@ -946,16 +947,16 @@ public void test10_testAliceDecryptOldMessageWithANewDeviceInAEncryptedRoom() th Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - doE2ETestWithAliceInARoom(); + MXSession aliceSession = doE2ETestWithAliceInARoom(); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); String message = "Hello myself!"; - Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); CountDownLatch lock1 = new CountDownLatch(1); - roomFromAlicePOV.sendEvent(buildTextEvent(message, mAliceSession), new TestApiCallback(lock1) { + roomFromAlicePOV.sendEvent(buildTextEvent(message, aliceSession), new TestApiCallback(lock1) { @Override public void onSuccess(Void info) { results.put("sendEvent", "sendEvent"); @@ -965,11 +966,11 @@ public void onSuccess(Void info) { lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("sendEvent")); - Credentials aliceCredentials = mAliceSession.getCredentials(); + Credentials aliceCredentials = aliceSession.getCredentials(); Credentials aliceCredentials2 = new Credentials(); // close the session and clear the data - mAliceSession.clear(context); + aliceSession.clear(context); aliceCredentials2.userId = aliceCredentials.userId; aliceCredentials2.homeServer = aliceCredentials.homeServer; @@ -981,9 +982,9 @@ public void onSuccess(Void info) { IMXStore store = new MXFileStore(hs, context); - MXSession mAliceSession2 = new MXSession(hs, new MXDataHandler(store, aliceCredentials2), context); + MXSession aliceSession2 = new MXSession(hs, new MXDataHandler(store, aliceCredentials2), context); - mAliceSession2.enableCryptoWhenStarting(); + aliceSession2.enableCryptoWhenStarting(); final CountDownLatch lock1b = new CountDownLatch(1); MXStoreListener listener = new MXStoreListener() { @@ -1008,8 +1009,8 @@ public void onStoreOOM(String accountId, String description) { } }; - mAliceSession2.getDataHandler().getStore().addMXStoreListener(listener); - mAliceSession2.getDataHandler().getStore().open(); + aliceSession2.getDataHandler().getStore().addMXStoreListener(listener); + aliceSession2.getDataHandler().getStore().open(); lock1b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onStoreReady")); @@ -1028,15 +1029,15 @@ public void onCryptoSyncComplete() { } }; - mAliceSession2.getDataHandler().addListener(eventListener); - mAliceSession2.startEventStream(null); + aliceSession2.getDataHandler().addListener(eventListener); + aliceSession2.startEventStream(null); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); - Room roomFromAlicePOV2 = mAliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV2 = aliceSession2.getDataHandler().getRoom(mRoomId); Assert.assertNotNull(roomFromAlicePOV2); Assert.assertTrue(roomFromAlicePOV2.getState().isEncrypted()); @@ -1047,7 +1048,7 @@ public void onCryptoSyncComplete() { Assert.assertNull(event.getClearEvent()); Assert.assertNotNull(event.getCryptoError()); Assert.assertEquals(MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE, event.getCryptoError().errcode); - mAliceSession2.clear(context); + aliceSession2.clear(context); } @Test @@ -1057,10 +1058,12 @@ public void test11_testAliceAndBobInAEncryptedRoomBackPaginationFromMemoryStore( Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap(); - doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first; + MXSession bobSession = pair.second; - Credentials bobCredentials = mBobSession.getCredentials(); - mBobSession.clear(context); + Credentials bobCredentials = bobSession.getCredentials(); + bobSession.clear(context); HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(bobCredentials); @@ -1123,18 +1126,18 @@ public void onSuccess(Integer info) { Assert.assertTrue(results.containsKey("backPaginate")); Assert.assertEquals(receivedEvents.size() + " instead of 5", 5, receivedEvents.size()); - checkEncryptedEvent(receivedEvents.get(0), mRoomId, messagesFromAlice.get(1), mAliceSession); + checkEncryptedEvent(receivedEvents.get(0), mRoomId, messagesFromAlice.get(1), aliceSession); - checkEncryptedEvent(receivedEvents.get(1), mRoomId, messagesFromBob.get(2), mBobSession); + checkEncryptedEvent(receivedEvents.get(1), mRoomId, messagesFromBob.get(2), bobSession); - checkEncryptedEvent(receivedEvents.get(2), mRoomId, messagesFromBob.get(1), mBobSession); + checkEncryptedEvent(receivedEvents.get(2), mRoomId, messagesFromBob.get(1), bobSession); - checkEncryptedEvent(receivedEvents.get(3), mRoomId, messagesFromBob.get(0), mBobSession); + checkEncryptedEvent(receivedEvents.get(3), mRoomId, messagesFromBob.get(0), bobSession); - checkEncryptedEvent(receivedEvents.get(4), mRoomId, messagesFromAlice.get(0), mAliceSession); + checkEncryptedEvent(receivedEvents.get(4), mRoomId, messagesFromAlice.get(0), aliceSession); bobSession2.clear(context); - mAliceSession.clear(context); + aliceSession.clear(context); } @Test @@ -1144,11 +1147,13 @@ public void test12_testAliceAndBobInAEncryptedRoomBackPaginationFromHomeServer() Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap(); - doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first; + MXSession bobSession = pair.second; - String eventId = mBobSession.getDataHandler().getStore().getLatestEvent(mRoomId).eventId; + String eventId = bobSession.getDataHandler().getStore().getLatestEvent(mRoomId).eventId; - EventTimeline timeline = new EventTimeline(mBobSession.getDataHandler(), mRoomId, eventId); + EventTimeline timeline = new EventTimeline(bobSession.getDataHandler(), mRoomId, eventId); final CountDownLatch lock2 = new CountDownLatch(6); final List receivedEvents = new ArrayList<>(); @@ -1175,18 +1180,18 @@ public void onSuccess(Integer info) { Assert.assertTrue(results.containsKey("backPaginate")); Assert.assertEquals(5, receivedEvents.size()); - checkEncryptedEvent(receivedEvents.get(0), mRoomId, messagesFromAlice.get(1), mAliceSession); + checkEncryptedEvent(receivedEvents.get(0), mRoomId, messagesFromAlice.get(1), aliceSession); - checkEncryptedEvent(receivedEvents.get(1), mRoomId, messagesFromBob.get(2), mBobSession); + checkEncryptedEvent(receivedEvents.get(1), mRoomId, messagesFromBob.get(2), bobSession); - checkEncryptedEvent(receivedEvents.get(2), mRoomId, messagesFromBob.get(1), mBobSession); + checkEncryptedEvent(receivedEvents.get(2), mRoomId, messagesFromBob.get(1), bobSession); - checkEncryptedEvent(receivedEvents.get(3), mRoomId, messagesFromBob.get(0), mBobSession); + checkEncryptedEvent(receivedEvents.get(3), mRoomId, messagesFromBob.get(0), bobSession); - checkEncryptedEvent(receivedEvents.get(4), mRoomId, messagesFromAlice.get(0), mAliceSession); + checkEncryptedEvent(receivedEvents.get(4), mRoomId, messagesFromAlice.get(0), aliceSession); - mBobSession.clear(context); - mAliceSession.clear(context); + bobSession.clear(context); + aliceSession.clear(context); } @Test @@ -1195,12 +1200,14 @@ public void test13_testAliceAndNotEncryptedBobInACryptedRoom() throws Exception final Map results = new HashMap(); - doE2ETestWithAliceAndBobInARoom(false); + Pair pair = doE2ETestWithAliceAndBobInARoom(false); + final MXSession aliceSession = pair.first; + final MXSession bobSession = pair.second; - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); - Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -1212,7 +1219,7 @@ public void test13_testAliceAndNotEncryptedBobInACryptedRoom() throws Exception @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE_ENCRYPTED) - && !TextUtils.equals(event.getSender(), mBobSession.getMyUserId())) { + && !TextUtils.equals(event.getSender(), bobSession.getMyUserId())) { results.put("bobEcho", event); lock1.countDown(); } @@ -1221,7 +1228,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromBobPOV.addEventListener(bobEventListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("bobEcho")); @@ -1240,7 +1247,7 @@ public void onLiveEvent(Event event, RoomState roomState) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) - && !TextUtils.equals(event.getSender(), mAliceSession.getMyUserId())) { + && !TextUtils.equals(event.getSender(), aliceSession.getMyUserId())) { results.put("aliceEcho", event); lock2.countDown(); } @@ -1249,7 +1256,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromAlicePOV.addEventListener(aliceEventListener); - roomFromBobPOV.sendEvent(buildTextEvent("Hello I'm Bob!", mBobSession), new SimpleApiCallback()); + roomFromBobPOV.sendEvent(buildTextEvent("Hello I'm Bob!", bobSession), new SimpleApiCallback()); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("aliceEcho")); @@ -1265,15 +1272,18 @@ public void test14_testCryptoDeviceBlockAndLeave() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - doE2ETestWithAliceAndBobAndSamInARoom(); - - mBobSession.getCrypto().setWarnOnUnknownDevices(false); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); - mSamSession.getCrypto().setWarnOnUnknownDevices(false); + Triple triple = doE2ETestWithAliceAndBobAndSamInARoom(); + MXSession aliceSession = triple.first; + MXSession bobSession = triple.second; + MXSession samSession = triple.third; + + bobSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); + samSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); - final Room roomFromSamPOV = mSamSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromSamPOV = samSession.getDataHandler().getRoom(mRoomId); Assert.assertNotNull(roomFromBobPOV); Assert.assertNotNull(roomFromAlicePOV); @@ -1303,7 +1313,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromSamPOV.addEventListener(samEventsListener0); // even if the device blocked, the message must be decrypted until there is a session id rolling - roomFromBobPOV.sendEvent(buildTextEvent("msg1", mBobSession), new TestApiCallback(lock0) { + roomFromBobPOV.sendEvent(buildTextEvent("msg1", bobSession), new TestApiCallback(lock0) { @Override public void onSuccess(Void info) { results.put("send0", "send0"); @@ -1342,7 +1352,7 @@ public void onLiveEvent(Event event, RoomState roomState) { }; roomFromSamPOV.addEventListener(samEventsListener1); - roomFromAlicePOV.sendEvent(buildTextEvent("msg1", mAliceSession), new TestApiCallback(lock1) { + roomFromAlicePOV.sendEvent(buildTextEvent("msg1", aliceSession), new TestApiCallback(lock1) { @Override public void onSuccess(Void info) { results.put("send1", "send1"); @@ -1352,13 +1362,13 @@ public void onSuccess(Void info) { lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results + "", results.containsKey("send1") && results.containsKey("bob1") && results.containsKey("sam1")); - List list = mBobSession.getCrypto().getUserDevices(mAliceSession.getMyUserId()); + List list = bobSession.getCrypto().getUserDevices(aliceSession.getMyUserId()); Assert.assertNotNull(list); Assert.assertTrue(list.size() > 0); CountDownLatch lock1b = new CountDownLatch(1); - mBobSession.getCrypto().setDeviceVerification(MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED, list.get(0).deviceId, mAliceSession.getMyUserId(), + bobSession.getCrypto().setDeviceVerification(MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED, list.get(0).deviceId, aliceSession.getMyUserId(), new TestApiCallback(lock1b) { @Override public void onSuccess(Void info) { @@ -1393,7 +1403,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromSamPOV.addEventListener(samEventsListener2); // even if the device blocked, the message must be decrypted until there is a session id rolling - roomFromBobPOV.sendEvent(buildTextEvent("msg2", mBobSession), new TestApiCallback(lock2) { + roomFromBobPOV.sendEvent(buildTextEvent("msg2", bobSession), new TestApiCallback(lock2) { @Override public void onSuccess(Void info) { results.put("send2", "send2"); @@ -1442,7 +1452,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromAlicePOV.addEventListener(aliceEventsListener3); // even if the device blocked, the message must be decrypted until there is a session id rolling - roomFromBobPOV.sendEvent(buildTextEvent("msg3", mBobSession), new TestApiCallback(lock4) { + roomFromBobPOV.sendEvent(buildTextEvent("msg3", bobSession), new TestApiCallback(lock4) { @Override public void onSuccess(Void info) { results.put("send3", "send3"); @@ -1453,9 +1463,9 @@ public void onSuccess(Void info) { lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("send3") && results.containsKey("alice3")); - mBobSession.clear(context); - mAliceSession.clear(context); - mSamSession.clear(context); + bobSession.clear(context); + aliceSession.clear(context); + samSession.clear(context); } @Test @@ -1463,15 +1473,17 @@ public void test15_testReplayAttack() throws Exception { Log.e(LOG_TAG, "test15_testReplayAttack"); final Map results = new HashMap<>(); - doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first; + final MXSession bobSession = pair.second; - mBobSession.getCrypto().setWarnOnUnknownDevices(false); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + bobSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); String messageFromAlice = "Hello I'm Alice!"; - final Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -1480,12 +1492,12 @@ public void test15_testReplayAttack() throws Exception { MXEventListener bobEventListener = new MXEventListener() { @Override public void onLiveEvent(Event event, RoomState roomState) { - if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), mBobSession.getMyUserId())) { + if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), bobSession.getMyUserId())) { results.put("bobEcho", event); event.setClearData(null); - mBobSession.getDataHandler().decryptEvent(event, roomFromBobPOV.getLiveTimeLine().getTimelineId()); + bobSession.getDataHandler().decryptEvent(event, roomFromBobPOV.getLiveTimeLine().getTimelineId()); results.put("decrypted", event); lock1.countDown(); @@ -1495,7 +1507,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromBobPOV.addEventListener(bobEventListener); - mBobSession.getDataHandler().addListener(new MXEventListener() { + bobSession.getDataHandler().addListener(new MXEventListener() { @Override public void onToDeviceEvent(Event event) { results.put("onToDeviceEvent", event); @@ -1503,7 +1515,7 @@ public void onToDeviceEvent(Event event) { } }); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); @@ -1516,8 +1528,8 @@ public void onToDeviceEvent(Event event) { Assert.assertEquals(MXCryptoError.DUPLICATED_MESSAGE_INDEX_ERROR_CODE, decryptedEvent.getCryptoError().errcode); // Decrypting it with no replay attack mitigation must still work - mBobSession.getDataHandler().decryptEvent(decryptedEvent, null); - checkEncryptedEvent(decryptedEvent, mRoomId, messageFromAlice, mAliceSession); + bobSession.getDataHandler().decryptEvent(decryptedEvent, null); + checkEncryptedEvent(decryptedEvent, mRoomId, messageFromAlice, aliceSession); } @Test @@ -1526,15 +1538,17 @@ public void test16_testRoomKeyReshare() throws Exception { final Map results = new HashMap<>(); - doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first; + MXSession bobSession = pair.second; - mBobSession.getCrypto().setWarnOnUnknownDevices(false); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + bobSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); String messageFromAlice = "Hello I'm Alice!"; - final Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -1551,7 +1565,7 @@ public void onToDeviceEvent(Event event) { } }; - mBobSession.getDataHandler().addListener(bobEventListener); + bobSession.getDataHandler().addListener(bobEventListener); final List receivedEvents = new ArrayList<>(); EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { @@ -1565,24 +1579,24 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); - checkEncryptedEvent(event, mRoomId, messageFromAlice, mAliceSession); + checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); // Reinject a modified version of the received room_key event from Alice. // From Bob pov, that mimics Alice resharing her keys but with an advanced outbound group session. Event toDeviceEvent = (Event) results.get("onToDeviceEvent"); String sessionId = toDeviceEvent.getContentAsJsonObject().get("session_id").getAsString(); - String newSessionKey = mAliceSession.getCrypto().getOlmDevice().getSessionKey(sessionId); + String newSessionKey = aliceSession.getCrypto().getOlmDevice().getSessionKey(sessionId); JsonObject content = toDeviceEvent.getClearEvent().getContentAsJsonObject(); content.add("session_key", new JsonPrimitive(newSessionKey)); - mBobSession.getDataHandler().onToDeviceEvent(toDeviceEvent); + bobSession.getDataHandler().onToDeviceEvent(toDeviceEvent); // We still must be able to decrypt the event @@ -1590,8 +1604,8 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro // session key event.setClearData(null); - mBobSession.getDataHandler().decryptEvent(event, null); - checkEncryptedEvent(event, mRoomId, messageFromAlice, mAliceSession); + bobSession.getDataHandler().decryptEvent(event, null); + checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); } @Test @@ -1600,15 +1614,17 @@ public void test17_testLateRoomKey() throws Exception { final Map results = new HashMap<>(); - doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first; + MXSession bobSession = pair.second; - mBobSession.getCrypto().setWarnOnUnknownDevices(false); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + bobSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); String messageFromAlice = "Hello I'm Alice!"; - final Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -1624,7 +1640,7 @@ public void onToDeviceEvent(Event event) { } }; - mBobSession.getDataHandler().addListener(bobEventListener); + bobSession.getDataHandler().addListener(bobEventListener); final List receivedEvents = new ArrayList<>(); EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { @@ -1638,14 +1654,14 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); - checkEncryptedEvent(event, mRoomId, messageFromAlice, mAliceSession); + checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); // Reinject a modified version of the received room_key event from Alice. // From Bob pov, that mimics Alice resharing her keys but with an advanced outbound group session. @@ -1654,12 +1670,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String senderKey = toDeviceEvent.senderKey(); // remove the session - mBobSession.getCrypto().getOlmDevice().removeInboundGroupSession(sessionId, senderKey); + bobSession.getCrypto().getOlmDevice().removeInboundGroupSession(sessionId, senderKey); event.setClearData(null); // check that the message cannot be decrypted - Assert.assertFalse(mBobSession.getDataHandler().decryptEvent(event, null)); + Assert.assertFalse(bobSession.getDataHandler().decryptEvent(event, null)); // check the error code Assert.assertEquals(MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE, event.getCryptoError().errcode); @@ -1678,14 +1694,14 @@ public void onEventDecrypted(Event event) { event.setClearData(null); // reinject the session key - mBobSession.getDataHandler().onToDeviceEvent(toDeviceEvent); + bobSession.getDataHandler().onToDeviceEvent(toDeviceEvent); // the message should be decrypted later lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onEventDecrypted")); Assert.assertEquals(1, receivedEvents.size()); - checkEncryptedEvent(receivedEvents.get(0), mRoomId, messageFromAlice, mAliceSession); + checkEncryptedEvent(receivedEvents.get(0), mRoomId, messageFromAlice, aliceSession); Assert.assertNull(receivedEvents.get(0).getCryptoError()); } @@ -1695,15 +1711,17 @@ public void test18_testAliceAndBobWithNewDevice() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first; + MXSession bobSession = pair.second; - mBobSession.getCrypto().setWarnOnUnknownDevices(false); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + bobSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); - String bobDeviceId1 = mBobSession.getCredentials().deviceId; + String bobDeviceId1 = bobSession.getCredentials().deviceId; Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -1719,7 +1737,7 @@ public void onToDeviceEvent(Event event) { } }; - mBobSession.getDataHandler().addListener(bobEventListener); + bobSession.getDataHandler().addListener(bobEventListener); final List receivedEvents = new ArrayList<>(); EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { @@ -1735,19 +1753,19 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage1 = "Hello I'm Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, mAliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); - checkEncryptedEvent(event, mRoomId, aliceMessage1, mAliceSession); + checkEncryptedEvent(event, mRoomId, aliceMessage1, aliceSession); // logout CountDownLatch lock2 = new CountDownLatch(1); - String bobId = mBobSession.getCredentials().userId; - mBobSession.logout(context, new TestApiCallback(lock2) { + String bobId = bobSession.getCredentials().userId; + bobSession.logout(context, new TestApiCallback(lock2) { @Override public void onSuccess(Void info) { results.put("logout", "logout"); @@ -1768,10 +1786,10 @@ public void onToDeviceEvent(Event event) { } }; - mAliceSession.getDataHandler().addListener(aliceEventListener); + aliceSession.getDataHandler().addListener(aliceEventListener); // login with a new device id - MXSession bobSession2 = mTestHelper.logIntoBobAccount(mBobSession.getMyUserId(), true, true); + MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), true, true); String bobDeviceId2 = bobSession2.getCredentials().deviceId; Assert.assertNotEquals(bobDeviceId2, bobDeviceId1); @@ -1803,13 +1821,13 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener4); String aliceMessage2 = "Hello I'm still Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, mAliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, aliceSession), new SimpleApiCallback()); lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals("received event of type " + results.get("event4"), 1, receivedEvents4.size()); event = receivedEvents4.get(0); - checkEncryptedEvent(event, mRoomId, aliceMessage2, mAliceSession); + checkEncryptedEvent(event, mRoomId, aliceMessage2, aliceSession); } @Test @@ -1818,16 +1836,18 @@ public void test19_testAliceWithNewDeviceAndBobWithNewDevice() throws Exception Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first; + MXSession bobSession = pair.second; - mBobSession.getCrypto().setWarnOnUnknownDevices(false); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + bobSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); - String bobUserId1 = mBobSession.getMyUserId(); - String aliceUserId1 = mAliceSession.getMyUserId(); + String bobUserId1 = bobSession.getMyUserId(); + String aliceUserId1 = aliceSession.getMyUserId(); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -1843,7 +1863,7 @@ public void onToDeviceEvent(Event event) { } }; - mBobSession.getDataHandler().addListener(bobEventListener); + bobSession.getDataHandler().addListener(bobEventListener); final List receivedEvents = new ArrayList<>(); EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { @@ -1859,18 +1879,18 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage1 = "Hello I'm Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, mAliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); - checkEncryptedEvent(event, mRoomId, aliceMessage1, mAliceSession); + checkEncryptedEvent(event, mRoomId, aliceMessage1, aliceSession); // logout CountDownLatch lock2 = new CountDownLatch(1); - mBobSession.logout(context, new TestApiCallback(lock2) { + bobSession.logout(context, new TestApiCallback(lock2) { @Override public void onSuccess(Void info) { results.put("boblogout", "boblogout"); @@ -1881,7 +1901,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("boblogout")); CountDownLatch lock3 = new CountDownLatch(1); - mAliceSession.logout(context, new TestApiCallback(lock3) { + aliceSession.logout(context, new TestApiCallback(lock3) { @Override public void onSuccess(Void info) { results.put("alicelogout", "alicelogout"); @@ -1891,16 +1911,16 @@ public void onSuccess(Void info) { lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("alicelogout")); - MXSession bobSession2 = mTestHelper.logIntoBobAccount(mBobSession.getMyUserId(), true, true); + MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), true, true); Assert.assertNotNull(bobSession2); bobSession2.getCrypto().setWarnOnUnknownDevices(false); - MXSession mAliceSession2 = mTestHelper.logIntoAliceAccount(mAliceSession.getMyUserId(), true, true); - Assert.assertNotNull(mAliceSession2); - mAliceSession2.getCrypto().setWarnOnUnknownDevices(false); + MXSession aliceSession2 = mTestHelper.logIntoAliceAccount(aliceSession.getMyUserId(), true, true); + Assert.assertNotNull(aliceSession2); + aliceSession2.getCrypto().setWarnOnUnknownDevices(false); Room roomFromBob2POV = bobSession2.getDataHandler().getRoom(mRoomId); - Room roomFromAlice2POV = mAliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlice2POV = aliceSession2.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromBob2POV.isEncrypted()); event = bobSession2.getDataHandler().getStore().getLatestEvent(mRoomId); @@ -1923,13 +1943,13 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBob2POV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); String messageFromAlice2 = "Hello I'm still Alice!"; - roomFromAlice2POV.sendEvent(buildTextEvent(messageFromAlice2, mAliceSession2), new SimpleApiCallback()); + roomFromAlice2POV.sendEvent(buildTextEvent(messageFromAlice2, aliceSession2), new SimpleApiCallback()); lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); event = receivedEvents2.get(0); - checkEncryptedEvent(event, mRoomId, messageFromAlice2, mAliceSession2); + checkEncryptedEvent(event, mRoomId, messageFromAlice2, aliceSession2); } @Test @@ -1937,13 +1957,15 @@ public void test20_testAliceAndBlockedBob() throws Exception { Log.e(LOG_TAG, "test20_testAliceAndBlockedBob"); final Map results = new HashMap<>(); - doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first; + MXSession bobSession = pair.second; - mBobSession.getCrypto().setWarnOnUnknownDevices(false); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + bobSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -1964,18 +1986,18 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage1 = "Hello I'm Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, mAliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); - checkEncryptedEvent(event, mRoomId, aliceMessage1, mAliceSession); + checkEncryptedEvent(event, mRoomId, aliceMessage1, aliceSession); // block the bob's device CountDownLatch lock1b = new CountDownLatch(1); - mAliceSession.getCrypto() - .setDeviceVerification(MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED, mBobSession.getCredentials().deviceId, mBobSession.getMyUserId(), + aliceSession.getCrypto() + .setDeviceVerification(MXDeviceInfo.DEVICE_VERIFICATION_BLOCKED, bobSession.getCredentials().deviceId, bobSession.getMyUserId(), new TestApiCallback(lock1b) { @Override public void onSuccess(Void info) { @@ -2003,7 +2025,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage2 = "Hello I'm still Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, mAliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, aliceSession), new SimpleApiCallback()); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); @@ -2015,8 +2037,8 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro // unblock the bob's device CountDownLatch lock2b = new CountDownLatch(1); - mAliceSession.getCrypto() - .setDeviceVerification(MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED, mBobSession.getCredentials().deviceId, mBobSession.getMyUserId(), + aliceSession.getCrypto() + .setDeviceVerification(MXDeviceInfo.DEVICE_VERIFICATION_UNVERIFIED, bobSession.getCredentials().deviceId, bobSession.getMyUserId(), new TestApiCallback(lock2b) { @Override public void onSuccess(Void info) { @@ -2043,13 +2065,13 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage3 = "Hello I'm still Alice and you can read this!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage3, mAliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage3, aliceSession), new SimpleApiCallback()); lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents3.size()); event = receivedEvents3.get(0); - checkEncryptedEvent(event, mRoomId, aliceMessage3, mAliceSession); + checkEncryptedEvent(event, mRoomId, aliceMessage3, aliceSession); } @@ -2058,20 +2080,22 @@ public void test21_testDownloadKeysWithUnreachableHS() throws Exception { Log.e(LOG_TAG, "test21_testDownloadKeysWithUnreachableHS"); final Map results = new HashMap<>(); - doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first; + MXSession bobSession = pair.second; - mBobSession.getCrypto().setWarnOnUnknownDevices(false); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + bobSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); CountDownLatch lock1 = new CountDownLatch(1); - mAliceSession.getCrypto().getDeviceList() - .downloadKeys(Arrays.asList(mBobSession.getMyUserId(), "@pppppppppppp:matrix.org"), false, + aliceSession.getCrypto().getDeviceList() + .downloadKeys(Arrays.asList(bobSession.getMyUserId(), "@pppppppppppp:matrix.org"), false, new TestApiCallback>(lock1) { @Override public void onSuccess(MXUsersDevicesMap info) { @@ -2088,7 +2112,7 @@ public void onSuccess(MXUsersDevicesMap info) { // We can get info only get for Bob Assert.assertEquals(1, usersDevicesInfoMap.getMap().size()); - List bobDevices = usersDevicesInfoMap.getUserDeviceIds(mBobSession.getMyUserId()); + List bobDevices = usersDevicesInfoMap.getUserDeviceIds(bobSession.getMyUserId()); Assert.assertNotNull(bobDevices); } @@ -2098,12 +2122,14 @@ public void test22_testDownloadKeysForUserWithNoDevice() throws Exception { Log.e(LOG_TAG, "test22_testDownloadKeysForUserWithNoDevice"); final Map results = new HashMap<>(); - doE2ETestWithAliceAndBobInARoom(false); + Pair pair = doE2ETestWithAliceAndBobInARoom(false); + MXSession aliceSession = pair.first; + MXSession bobSession = pair.second; - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); CountDownLatch lock1 = new CountDownLatch(1); - mAliceSession.getCrypto().getDeviceList().downloadKeys(Arrays.asList(mBobSession.getMyUserId()), false, + aliceSession.getCrypto().getDeviceList().downloadKeys(Arrays.asList(bobSession.getMyUserId()), false, new TestApiCallback>(lock1) { @Override public void onSuccess(MXUsersDevicesMap info) { @@ -2118,14 +2144,14 @@ public void onSuccess(MXUsersDevicesMap info) { MXUsersDevicesMap usersDevicesInfoMap = (MXUsersDevicesMap) results.get("downloadKeys"); // MXCrypto.downloadKeys should return @[] for Bob to distinguish him from an unknown user - List bobDevices = usersDevicesInfoMap.getUserDeviceIds(mBobSession.getMyUserId()); + List bobDevices = usersDevicesInfoMap.getUserDeviceIds(bobSession.getMyUserId()); Assert.assertNotNull(bobDevices); Assert.assertTrue(bobDevices.isEmpty()); // try again // it should not failed CountDownLatch lock2 = new CountDownLatch(1); - mAliceSession.getCrypto().getDeviceList().downloadKeys(Arrays.asList(mBobSession.getMyUserId()), false, + aliceSession.getCrypto().getDeviceList().downloadKeys(Arrays.asList(bobSession.getMyUserId()), false, new TestApiCallback>(lock2) { @Override public void onSuccess(MXUsersDevicesMap info) { @@ -2145,25 +2171,27 @@ public void test23_testFirstMessageSentWhileSessionWasPaused() throws Exception final String messageFromAlice = "Hello I'm Alice!"; final Map results = new HashMap<>(); - doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + final MXSession aliceSession = pair.first; + MXSession bobSession = pair.second; - mBobSession.getCrypto().setWarnOnUnknownDevices(false); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + bobSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); - mBobSession.pauseEventStream(); + bobSession.pauseEventStream(); // wait that the bob session is really suspended SystemClock.sleep(30000); CountDownLatch lock0 = new CountDownLatch(1); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new TestApiCallback(lock0) { + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new TestApiCallback(lock0) { @Override public void onSuccess(Void info) { results.put("sendEvent", "sendEvent"); @@ -2179,7 +2207,7 @@ public void onSuccess(Void info) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, messageFromAlice, mAliceSession); + checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); results.put("onLiveEvent", "onLiveEvent"); lock2.countDown(); @@ -2189,7 +2217,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromBobPOV.addEventListener(eventListener); - mBobSession.getDataHandler().addListener(new MXEventListener() { + bobSession.getDataHandler().addListener(new MXEventListener() { @Override public void onToDeviceEvent(Event event) { results.put("onToDeviceEvent", event); @@ -2197,14 +2225,14 @@ public void onToDeviceEvent(Event event) { } }); - mBobSession.resumeEventStream(); + bobSession.resumeEventStream(); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertTrue(results.containsKey("onLiveEvent")); - mBobSession.clear(context); - mAliceSession.clear(context); + bobSession.clear(context); + aliceSession.clear(context); } @Test @@ -2213,17 +2241,17 @@ public void test24_testExportImport() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - doE2ETestWithAliceInARoom(); + MXSession aliceSession = doE2ETestWithAliceInARoom(); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); String message = "Hello myself!"; String password = "hello"; - Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); CountDownLatch lock1 = new CountDownLatch(1); - roomFromAlicePOV.sendEvent(buildTextEvent(message, mAliceSession), new TestApiCallback(lock1) { + roomFromAlicePOV.sendEvent(buildTextEvent(message, aliceSession), new TestApiCallback(lock1) { @Override public void onSuccess(Void info) { results.put("sendEvent", "sendEvent"); @@ -2233,11 +2261,11 @@ public void onSuccess(Void info) { lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("sendEvent")); - Credentials aliceCredentials = mAliceSession.getCredentials(); + Credentials aliceCredentials = aliceSession.getCredentials(); Credentials aliceCredentials2 = new Credentials(); CountDownLatch lock1a = new CountDownLatch(1); - mAliceSession.getCrypto().exportRoomKeys(password, new TestApiCallback(lock1a) { + aliceSession.getCrypto().exportRoomKeys(password, new TestApiCallback(lock1a) { @Override public void onSuccess(byte[] info) { results.put("exportRoomKeys", info); @@ -2249,7 +2277,7 @@ public void onSuccess(byte[] info) { Assert.assertTrue(results.containsKey("exportRoomKeys")); // close the session and clear the data - mAliceSession.clear(context); + aliceSession.clear(context); aliceCredentials2.userId = aliceCredentials.userId; aliceCredentials2.homeServer = aliceCredentials.homeServer; @@ -2261,9 +2289,9 @@ public void onSuccess(byte[] info) { IMXStore store = new MXFileStore(hs, context); - MXSession mAliceSession2 = new MXSession(hs, new MXDataHandler(store, aliceCredentials2), context); + MXSession aliceSession2 = new MXSession(hs, new MXDataHandler(store, aliceCredentials2), context); - mAliceSession2.enableCryptoWhenStarting(); + aliceSession2.enableCryptoWhenStarting(); final CountDownLatch lock1b = new CountDownLatch(1); MXStoreListener listener = new MXStoreListener() { @@ -2288,8 +2316,8 @@ public void onStoreOOM(String accountId, String description) { } }; - mAliceSession2.getDataHandler().getStore().addMXStoreListener(listener); - mAliceSession2.getDataHandler().getStore().open(); + aliceSession2.getDataHandler().getStore().addMXStoreListener(listener); + aliceSession2.getDataHandler().getStore().open(); lock1b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onStoreReady")); @@ -2308,15 +2336,15 @@ public void onCryptoSyncComplete() { } }; - mAliceSession2.getDataHandler().addListener(eventListener); - mAliceSession2.startEventStream(null); + aliceSession2.getDataHandler().addListener(eventListener); + aliceSession2.startEventStream(null); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); - Room roomFromAlicePOV2 = mAliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV2 = aliceSession2.getDataHandler().getRoom(mRoomId); Assert.assertNotNull(roomFromAlicePOV2); Assert.assertTrue(roomFromAlicePOV2.getState().isEncrypted()); @@ -2331,7 +2359,7 @@ public void onCryptoSyncComplete() { // import the e2e keys // test with a wrong password CountDownLatch lock3 = new CountDownLatch(1); - mAliceSession2.getCrypto().importRoomKeys((byte[]) results.get("exportRoomKeys"), "wrong password", new TestApiCallback(lock3) { + aliceSession2.getCrypto().importRoomKeys((byte[]) results.get("exportRoomKeys"), "wrong password", new TestApiCallback(lock3) { @Override public void onSuccess(Void info) { results.put("importRoomKeys", "importRoomKeys"); @@ -2369,7 +2397,7 @@ public void onUnexpectedError(Exception e) { Assert.assertEquals(MXCryptoError.UNKNOWN_INBOUND_SESSION_ID_ERROR_CODE, event.getCryptoError().errcode); CountDownLatch lock4 = new CountDownLatch(1); - mAliceSession2.getCrypto().importRoomKeys((byte[]) results.get("exportRoomKeys"), password, new TestApiCallback(lock4) { + aliceSession2.getCrypto().importRoomKeys((byte[]) results.get("exportRoomKeys"), password, new TestApiCallback(lock4) { @Override public void onSuccess(Void info) { results.put("importRoomKeys", "importRoomKeys"); @@ -2385,9 +2413,9 @@ public void onSuccess(Void info) { Assert.assertTrue(event.isEncrypted()); Assert.assertNotNull(event.getClearEvent()); Assert.assertNull(event.getCryptoError()); - checkEncryptedEvent(event, mRoomId, message, mAliceSession); + checkEncryptedEvent(event, mRoomId, message, aliceSession); - mAliceSession2.clear(context); + aliceSession2.clear(context); } @Test @@ -2401,23 +2429,23 @@ public void test25_testLeftAndJoinedBob() throws Exception { final Map results = new HashMap<>(); - mAliceSession = mTestHelper.createAliceAccount(true, false); - mBobSession = mTestHelper.createBobAccount(true, false); + MXSession aliceSession = mTestHelper.createAliceAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(true, false); CountDownLatch lock_1 = new CountDownLatch(2); - mAliceSession.enableCrypto(true, new TestApiCallback(lock_1)); - mBobSession.enableCrypto(true, new TestApiCallback(lock_1)); + aliceSession.enableCrypto(true, new TestApiCallback(lock_1)); + bobSession.enableCrypto(true, new TestApiCallback(lock_1)); lock_1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertNotNull(mAliceSession.getCrypto()); - Assert.assertNotNull(mBobSession.getCrypto()); + Assert.assertNotNull(aliceSession.getCrypto()); + Assert.assertNotNull(bobSession.getCrypto()); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); - mBobSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); + bobSession.getCrypto().setWarnOnUnknownDevices(false); CountDownLatch lock0 = new CountDownLatch(1); - mAliceSession.createRoom(null, null, RoomState.DIRECTORY_VISIBILITY_PUBLIC, + aliceSession.createRoom(null, null, RoomState.DIRECTORY_VISIBILITY_PUBLIC, null, RoomState.GUEST_ACCESS_CAN_JOIN, null, new TestApiCallback(lock0) { @Override @@ -2430,7 +2458,7 @@ public void onSuccess(String roomId) { Assert.assertTrue(results.containsKey("roomId")); mRoomId = (String) results.get("roomId"); - Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); CountDownLatch lock1 = new CountDownLatch(1); roomFromAlicePOV.enableEncryptionWithAlgorithm(MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_MEGOLM, new TestApiCallback(lock1) { @@ -2444,7 +2472,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("enableEncryptionWithAlgorithm")); CountDownLatch lock2 = new CountDownLatch(1); - mBobSession.joinRoom(mRoomId, new TestApiCallback(lock2) { + bobSession.joinRoom(mRoomId, new TestApiCallback(lock2) { @Override public void onSuccess(String info) { results.put("joinRoom", "joinRoom"); @@ -2454,7 +2482,7 @@ public void onSuccess(String info) { lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("joinRoom")); - Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); + Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); final CountDownLatch lock3 = new CountDownLatch(1); final List receivedEvents = new ArrayList<>(); EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { @@ -2467,13 +2495,13 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }; roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new SimpleApiCallback()); lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); - checkEncryptedEvent(event, mRoomId, messageFromAlice, mAliceSession); + checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); CountDownLatch lock4 = new CountDownLatch(1); roomFromBobPOV.leave(new TestApiCallback(lock4) { @@ -2487,10 +2515,10 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("leave")); // Make Bob come back to the room with a new device - Credentials bobCredentials = mBobSession.getCredentials(); - mBobSession.clear(context); + Credentials bobCredentials = bobSession.getCredentials(); + bobSession.clear(context); - MXSession bobSession2 = mTestHelper.logIntoBobAccount(mBobSession.getMyUserId(), true, true); + MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), true, true); Assert.assertNotNull(bobSession2); Assert.assertTrue(bobSession2.isCryptoEnabled()); Assert.assertNotEquals(bobSession2.getCrypto().getMyDevice().deviceId, bobCredentials.deviceId); @@ -2521,16 +2549,16 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }; roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); - roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, mAliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, aliceSession), new SimpleApiCallback()); lock6.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); event = receivedEvents2.get(0); - checkEncryptedEvent(event, mRoomId, message2FromAlice, mAliceSession); + checkEncryptedEvent(event, mRoomId, message2FromAlice, aliceSession); bobSession2.clear(context); - mAliceSession.clear(context); + aliceSession.clear(context); } @Test @@ -2558,13 +2586,16 @@ public void test26_testBlackListUnverifiedDevices() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - doE2ETestWithAliceAndBobAndSamInARoom(); + Triple triple = doE2ETestWithAliceAndBobAndSamInARoom(); + final MXSession aliceSession = triple.first; + MXSession bobSession = triple.second; + MXSession samSession = triple.third; final String messageFromAlice = "Hello I'm Alice!"; - Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); - Room roomFromSamPOV = mSamSession.getDataHandler().getRoom(mRoomId); + Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromSamPOV = samSession.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -2572,7 +2603,7 @@ public void test26_testBlackListUnverifiedDevices() throws Exception { CountDownLatch lock1 = new CountDownLatch(1); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new TestApiCallback(lock1) { + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new TestApiCallback(lock1) { @Override public void onMatrixError(MatrixError e) { results.put("sendEventError", e); @@ -2587,17 +2618,17 @@ public void onMatrixError(MatrixError e) { MXUsersDevicesMap unknownDevices = (MXUsersDevicesMap) error.mExceptionData; // only one bob device - List deviceInfos = unknownDevices.getUserDeviceIds(mBobSession.getMyUserId()); + List deviceInfos = unknownDevices.getUserDeviceIds(bobSession.getMyUserId()); Assert.assertEquals(1, deviceInfos.size()); - Assert.assertTrue(deviceInfos.contains(mBobSession.getCrypto().getMyDevice().deviceId)); + Assert.assertTrue(deviceInfos.contains(bobSession.getCrypto().getMyDevice().deviceId)); // only one Sam device - deviceInfos = unknownDevices.getUserDeviceIds(mSamSession.getMyUserId()); + deviceInfos = unknownDevices.getUserDeviceIds(samSession.getMyUserId()); Assert.assertEquals(1, deviceInfos.size()); - Assert.assertTrue(deviceInfos.contains(mSamSession.getCrypto().getMyDevice().deviceId)); + Assert.assertTrue(deviceInfos.contains(samSession.getCrypto().getMyDevice().deviceId)); CountDownLatch lock2 = new CountDownLatch(1); - mAliceSession.getCrypto().setDevicesKnown(Arrays.asList(mBobSession.getCrypto().getMyDevice(), mSamSession.getCrypto().getMyDevice()), + aliceSession.getCrypto().setDevicesKnown(Arrays.asList(bobSession.getCrypto().getMyDevice(), samSession.getCrypto().getMyDevice()), new TestApiCallback(lock2) { @Override public void onSuccess(Void info) { @@ -2615,7 +2646,7 @@ public void onSuccess(Void info) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, messageFromAlice, mAliceSession); + checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); results.put("onLiveEventBob1", "onLiveEvent"); lock3.countDown(); @@ -2627,7 +2658,7 @@ public void onLiveEvent(Event event, RoomState roomState) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, messageFromAlice, mAliceSession); + checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); results.put("onLiveEventSam1", "onLiveEvent"); lock3.countDown(); @@ -2635,7 +2666,7 @@ public void onLiveEvent(Event event, RoomState roomState) { } }; - mBobSession.getDataHandler().addListener(new MXEventListener() { + bobSession.getDataHandler().addListener(new MXEventListener() { @Override public void onToDeviceEvent(Event event) { results.put("onToDeviceEventBob", event); @@ -2643,7 +2674,7 @@ public void onToDeviceEvent(Event event) { } }); - mSamSession.getDataHandler().addListener(new MXEventListener() { + samSession.getDataHandler().addListener(new MXEventListener() { @Override public void onToDeviceEvent(Event event) { results.put("onToDeviceEventSam", event); @@ -2654,7 +2685,7 @@ public void onToDeviceEvent(Event event) { roomFromBobPOV.addEventListener(eventListenerBob1); roomFromSamPOV.addEventListener(eventListenerSam1); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new TestApiCallback(lock3) { + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new TestApiCallback(lock3) { @Override public void onSuccess(Void info) { lock3.countDown(); @@ -2678,7 +2709,7 @@ public void onSuccess(Void info) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, activeMessage.get(0), mAliceSession); + checkEncryptedEvent(event, mRoomId, activeMessage.get(0), aliceSession); results.put("eventListenerBob2", "onLiveEvent"); activeLock.get(0).countDown(); @@ -2693,7 +2724,7 @@ public void onLiveEvent(Event event, RoomState roomState) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, activeMessage.get(0), mAliceSession); + checkEncryptedEvent(event, mRoomId, activeMessage.get(0), aliceSession); results.put("eventListenerSam2", "onLiveEvent"); activeLock.get(0).countDown(); @@ -2708,7 +2739,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromSamPOV.addEventListener(eventListenerSam2); CountDownLatch lock4 = new CountDownLatch(1); - mAliceSession.getCrypto().setGlobalBlacklistUnverifiedDevices(true, new TestApiCallback(lock4) { + aliceSession.getCrypto().setGlobalBlacklistUnverifiedDevices(true, new TestApiCallback(lock4) { @Override public void onSuccess(Void info) { results.put("setGlobalBlacklistUnverifiedDevicesTrue", "setGlobalBlacklistUnverifiedDevices"); @@ -2727,7 +2758,7 @@ public void onSuccess(Void info) { activeMessage.clear(); activeMessage.add("message 1"); - roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), mAliceSession), new TestApiCallback(lock5)); + roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession), new TestApiCallback(lock5)); lock5.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertFalse(results.containsKey("eventListenerBob2")); @@ -2736,7 +2767,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("eventListenerEncyptedSam2")); CountDownLatch lock6 = new CountDownLatch(1); - mAliceSession.getCrypto().setGlobalBlacklistUnverifiedDevices(false, new TestApiCallback(lock6) { + aliceSession.getCrypto().setGlobalBlacklistUnverifiedDevices(false, new TestApiCallback(lock6) { @Override public void onSuccess(Void info) { results.put("setGlobalBlacklistUnverifiedDevicesfalse", "setGlobalBlacklistUnverifiedDevices"); @@ -2755,7 +2786,7 @@ public void onSuccess(Void info) { activeMessage.clear(); activeMessage.add("message 2"); - roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), mAliceSession), new TestApiCallback(lock7)); + roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession), new TestApiCallback(lock7)); lock7.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("eventListenerBob2")); @@ -2765,9 +2796,9 @@ public void onSuccess(Void info) { // verify the bob device CountDownLatch lock8 = new CountDownLatch(3); - mAliceSession.getCrypto().setDeviceVerification(MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED, - mBobSession.getCrypto().getMyDevice().deviceId, - mBobSession.getMyUserId(), new TestApiCallback(lock8) { + aliceSession.getCrypto().setDeviceVerification(MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED, + bobSession.getCrypto().getMyDevice().deviceId, + bobSession.getMyUserId(), new TestApiCallback(lock8) { @Override public void onSuccess(Void info) { results.put("setDeviceVerificationBob", "setDeviceVerificationBob"); @@ -2779,7 +2810,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("setDeviceVerificationBob")); CountDownLatch lock9 = new CountDownLatch(3); - mAliceSession.getCrypto().setRoomBlacklistUnverifiedDevices(roomFromAlicePOV.getRoomId(), new TestApiCallback(lock9) { + aliceSession.getCrypto().setRoomBlacklistUnverifiedDevices(roomFromAlicePOV.getRoomId(), new TestApiCallback(lock9) { @Override public void onSuccess(Void info) { results.put("setRoomBlacklistUnverifiedDevices", "setRoomBlacklistUnverifiedDevices"); @@ -2798,7 +2829,7 @@ public void onSuccess(Void info) { activeMessage.clear(); activeMessage.add("message 3"); - roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), mAliceSession), new TestApiCallback(lock10)); + roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession), new TestApiCallback(lock10)); lock10.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("eventListenerBob2")); @@ -2807,7 +2838,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("eventListenerEncyptedSam2")); CountDownLatch lock11 = new CountDownLatch(3); - mAliceSession.getCrypto().setRoomUnblacklistUnverifiedDevices(roomFromAlicePOV.getRoomId(), new TestApiCallback(lock11) { + aliceSession.getCrypto().setRoomUnblacklistUnverifiedDevices(roomFromAlicePOV.getRoomId(), new TestApiCallback(lock11) { @Override public void onSuccess(Void info) { results.put("setRoomUnblacklistUnverifiedDevices", "setRoomUnblacklistUnverifiedDevices"); @@ -2826,7 +2857,7 @@ public void onSuccess(Void info) { activeMessage.clear(); activeMessage.add("message 3"); - roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), mAliceSession), new TestApiCallback(lock12)); + roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession), new TestApiCallback(lock12)); lock12.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("eventListenerBob2")); @@ -2834,7 +2865,7 @@ public void onSuccess(Void info) { Assert.assertFalse(results.containsKey("eventListenerEncyptedBob2")); Assert.assertFalse(results.containsKey("eventListenerEncyptedSam2")); - mBobSession.clear(context); + bobSession.clear(context); } @Test @@ -2852,11 +2883,11 @@ public void test27_testEnableEncryptionAfterNonEncryptedMessages() throws Except final String messageFromAlice = "Hello I'm Alice!"; final String message2FromAlice = "I'm still Alice!"; - mAliceSession = mTestHelper.createAliceAccount(true, false); - mBobSession = mTestHelper.createBobAccount(true, false); + MXSession aliceSession = mTestHelper.createAliceAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(true, false); CountDownLatch lock00b = new CountDownLatch(2); - mAliceSession.enableCrypto(true, new TestApiCallback(lock00b) { + aliceSession.enableCrypto(true, new TestApiCallback(lock00b) { @Override public void onSuccess(Void info) { results.put("enableCrypto1", "enableCrypto1"); @@ -2864,7 +2895,7 @@ public void onSuccess(Void info) { } }); - mBobSession.enableCrypto(true, new TestApiCallback(lock00b) { + bobSession.enableCrypto(true, new TestApiCallback(lock00b) { @Override public void onSuccess(Void info) { results.put("enableCrypto2", "enableCrypto2"); @@ -2874,11 +2905,11 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("enableCrypto2")); Assert.assertTrue(results.containsKey("enableCrypto1")); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); - mBobSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); + bobSession.getCrypto().setWarnOnUnknownDevices(false); CountDownLatch lock0 = new CountDownLatch(1); - mAliceSession.createRoom(null, null, RoomState.DIRECTORY_VISIBILITY_PUBLIC, + aliceSession.createRoom(null, null, RoomState.DIRECTORY_VISIBILITY_PUBLIC, null, RoomState.GUEST_ACCESS_CAN_JOIN, null, new TestApiCallback(lock0) { @Override @@ -2892,7 +2923,7 @@ public void onSuccess(String roomId) { mRoomId = (String) results.get("roomId"); CountDownLatch lock1 = new CountDownLatch(1); - mBobSession.joinRoom(mRoomId, new TestApiCallback(lock1) { + bobSession.joinRoom(mRoomId, new TestApiCallback(lock1) { @Override public void onSuccess(String info) { results.put("joinRoom", "joinRoom"); @@ -2902,10 +2933,10 @@ public void onSuccess(String info) { lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("joinRoom")); - Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); CountDownLatch lock2 = new CountDownLatch(1); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, mAliceSession), new TestApiCallback(lock2) { + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new TestApiCallback(lock2) { @Override public void onSuccess(Void info) { results.put("sendEvent1", "sendEvent1"); @@ -2916,10 +2947,10 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("sendEvent1")); // Make Bob come back to the room with a new device - Credentials bobCredentials = mBobSession.getCredentials(); - mBobSession.clear(context); + Credentials bobCredentials = bobSession.getCredentials(); + bobSession.clear(context); - MXSession bobSession2 = mTestHelper.logIntoBobAccount(mBobSession.getMyUserId(), true, true); + MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), true, true); Assert.assertNotNull(bobSession2); Assert.assertTrue(bobSession2.isCryptoEnabled()); Assert.assertNotEquals(bobSession2.getCrypto().getMyDevice().deviceId, bobCredentials.deviceId); @@ -2952,16 +2983,16 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }; roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); - roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, mAliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, aliceSession), new SimpleApiCallback()); lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); Event event = receivedEvents2.get(0); - checkEncryptedEvent(event, mRoomId, message2FromAlice, mAliceSession); + checkEncryptedEvent(event, mRoomId, message2FromAlice, aliceSession); bobSession2.clear(context); - mAliceSession.clear(context); + aliceSession.clear(context); } // Test for https://github.com/vector-im/riot-web/issues/4983 @@ -2974,14 +3005,16 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro public void test28_testLeftBobAndAliceWithNewDevice() throws Exception { Log.e(LOG_TAG, "test28_testLeftBobAndAliceWithNewDevice"); Context context = InstrumentationRegistry.getContext(); - final Map results = new HashMap(); - - doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(true); + final Map results = new HashMap<>(); + Pair pair = doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(true); + MXSession aliceSession = pair.first; + final MXSession bobSession = pair.second; + // - Bob leaves the room, so stops getting updates CountDownLatch lock1 = new CountDownLatch(1); - final Room bobLeftRoom = mBobSession.getDataHandler().getRoom(mRoomId); + final Room bobLeftRoom = bobSession.getDataHandler().getRoom(mRoomId); bobLeftRoom.leave(new TestApiCallback(lock1) { @Override public void onSuccess(Void info) { @@ -2994,12 +3027,12 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("lock1")); // - Alice adds a new device - final MXSession mAliceSession2 = mTestHelper.logIntoAliceAccount(mAliceSession.getMyUserId(), true, true); - Assert.assertNotNull(mAliceSession2); + final MXSession aliceSession2 = mTestHelper.logIntoAliceAccount(aliceSession.getMyUserId(), true, true); + Assert.assertNotNull(aliceSession2); // - Alice and Bob start sharing a room again CountDownLatch lock3 = new CountDownLatch(1); - mAliceSession2.createRoom(null, null, RoomState.DIRECTORY_VISIBILITY_PUBLIC, + aliceSession2.createRoom(null, null, RoomState.DIRECTORY_VISIBILITY_PUBLIC, null, RoomState.GUEST_ACCESS_CAN_JOIN, null, new TestApiCallback(lock3) { @Override @@ -3011,7 +3044,7 @@ public void onSuccess(String info) { lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertNotNull(mRoomId); - Room roomFromAlicePOV = mAliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession2.getDataHandler().getRoom(mRoomId); CountDownLatch lock4 = new CountDownLatch(1); roomFromAlicePOV.enableEncryptionWithAlgorithm(MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_MEGOLM, new TestApiCallback(lock4) { @Override @@ -3024,7 +3057,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("lock4")); CountDownLatch lock5 = new CountDownLatch(1); - mBobSession.joinRoom(mRoomId, new TestApiCallback(lock5) { + bobSession.joinRoom(mRoomId, new TestApiCallback(lock5) { @Override public void onSuccess(String info) { results.put("lock5", "lock5"); @@ -3035,14 +3068,14 @@ public void onSuccess(String info) { Assert.assertTrue(results.containsKey("lock5")); // - Bob has an out of date list of Alice's devices - Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); + Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); final String messageFromBob = "Hello Alice with new device!"; final CountDownLatch lock6 = new CountDownLatch(2); MXEventListener eventListener = new MXEventListener() { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, messageFromBob, mBobSession); + checkEncryptedEvent(event, mRoomId, messageFromBob, bobSession); results.put("lock6", "lock6"); lock6.countDown(); @@ -3052,14 +3085,14 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromAlicePOV.addEventListener(eventListener); - roomFromBobPOV.sendEvent(buildTextEvent(messageFromBob, mBobSession), new TestApiCallback(lock6)); + roomFromBobPOV.sendEvent(buildTextEvent(messageFromBob, bobSession), new TestApiCallback(lock6)); lock6.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("lock6")); - mBobSession.clear(context); - mAliceSession.clear(context); - mAliceSession2.clear(context); + bobSession.clear(context); + aliceSession.clear(context); + aliceSession2.clear(context); } /** @@ -3071,13 +3104,15 @@ public void onLiveEvent(Event event, RoomState roomState) { public void test29_testAliceAndBobInAEncryptedRoomWithReplyTo() throws Exception { Log.e(LOG_TAG, "test08_testAliceAndBobInAEncryptedRoom2"); - doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + final MXSession aliceSession = pair.first; + final MXSession bobSession = pair.second; - mBobSession.getCrypto().setWarnOnUnknownDevices(false); - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + bobSession.getCrypto().setWarnOnUnknownDevices(false); + aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -3093,10 +3128,10 @@ public void test29_testAliceAndBobInAEncryptedRoomWithReplyTo() throws Exception MXEventListener bobEventListener = new MXEventListener() { @Override public void onLiveEvent(Event event, RoomState roomState) { - if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), mBobSession.getMyUserId())) { + if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), bobSession.getMyUserId())) { bobReceivedEvents.add(event); - checkEncryptedEvent(event, mRoomId, messagesFromAlice.get(mReceivedMessagesFromAlice), mAliceSession); + checkEncryptedEvent(event, mRoomId, messagesFromAlice.get(mReceivedMessagesFromAlice), aliceSession); mReceivedMessagesFromAlice++; list.get(list.size() - 1).countDown(); @@ -3107,18 +3142,18 @@ public void onLiveEvent(Event event, RoomState roomState) { MXEventListener aliceEventListener = new MXEventListener() { @Override public void onLiveEvent(Event event, RoomState roomState) { - if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), mAliceSession.getMyUserId())) { + if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), aliceSession.getMyUserId())) { aliceReceivedEvents.add(event); try { // "In reply to" format for body - String expectedMessage = "> <" + mAliceSession.getMyUserId() + "> " + String expectedMessage = "> <" + aliceSession.getMyUserId() + "> " + messagesFromAlice.get(mReceivedMessagesFromAlice - 1) + "\n\n" + messagesFromBob.get(mReceivedMessagesFromBob); - checkEncryptedEvent(event, mRoomId, expectedMessage, mBobSession); + checkEncryptedEvent(event, mRoomId, expectedMessage, bobSession); mReceivedMessagesFromBob++; @@ -3138,7 +3173,7 @@ public void onLiveEvent(Event event, RoomState roomState) { list.add(new CountDownLatch(2)); final Map results = new HashMap<>(); - mBobSession.getDataHandler().addListener(new MXEventListener() { + bobSession.getDataHandler().addListener(new MXEventListener() { @Override public void onToDeviceEvent(Event event) { results.put("onToDeviceEvent", event); @@ -3147,7 +3182,7 @@ public void onToDeviceEvent(Event event) { }); // Alice sends a first event - roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(mReceivedMessagesFromAlice), mAliceSession), callback); + roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(mReceivedMessagesFromAlice), aliceSession), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, mReceivedMessagesFromAlice); @@ -3184,12 +3219,17 @@ public void onToDeviceEvent(Event event) { //============================================================================================================== - private void doE2ETestWithAliceInARoom() throws Exception { + /** + * + * @return alice session + * @throws Exception + */ + private MXSession doE2ETestWithAliceInARoom() throws Exception { final Map results = new HashMap<>(); - mAliceSession = mTestHelper.createAliceAccount(true, false); + MXSession aliceSession = mTestHelper.createAliceAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); - mAliceSession.enableCrypto(true, new TestApiCallback(lock0) { + aliceSession.enableCrypto(true, new TestApiCallback(lock0) { @Override public void onSuccess(Void info) { results.put("enableCrypto", "enableCrypto"); @@ -3202,7 +3242,7 @@ public void onSuccess(Void info) { mRoomId = null; CountDownLatch lock1 = new CountDownLatch(1); - mAliceSession.createRoom(new TestApiCallback(lock1) { + aliceSession.createRoom(new TestApiCallback(lock1) { @Override public void onSuccess(String roomId) { mRoomId = roomId; @@ -3213,7 +3253,7 @@ public void onSuccess(String roomId) { lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertNotNull(mRoomId); - Room room = mAliceSession.getDataHandler().getRoom(mRoomId); + Room room = aliceSession.getDataHandler().getRoom(mRoomId); CountDownLatch lock2 = new CountDownLatch(1); room.enableEncryptionWithAlgorithm(MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_MEGOLM, new TestApiCallback(lock2) { @@ -3225,19 +3265,27 @@ public void onSuccess(Void info) { }); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("enableEncryptionWithAlgorithm")); + + return aliceSession; } - private void doE2ETestWithAliceAndBobInARoom(boolean cryptedBob) throws Exception { + /** + * + * @param cryptedBob + * @return alice and bob sessions + * @throws Exception + */ + private Pair doE2ETestWithAliceAndBobInARoom(boolean cryptedBob) throws Exception { final Map statuses = new HashMap<>(); - doE2ETestWithAliceInARoom(); + MXSession aliceSession = doE2ETestWithAliceInARoom(); - Room room = mAliceSession.getDataHandler().getRoom(mRoomId); + Room room = aliceSession.getDataHandler().getRoom(mRoomId); - mBobSession = mTestHelper.createBobAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); - mBobSession.enableCrypto(cryptedBob, new TestApiCallback(lock0) { + bobSession.enableCrypto(cryptedBob, new TestApiCallback(lock0) { @Override public void onSuccess(Void info) { statuses.put("enableCrypto", "enableCrypto"); @@ -3260,9 +3308,9 @@ public void onNewRoom(String roomId) { } }; - mBobSession.getDataHandler().addListener(bobEventListener); + bobSession.getDataHandler().addListener(bobEventListener); - room.invite(mBobSession.getMyUserId(), new TestApiCallback(lock1) { + room.invite(bobSession.getMyUserId(), new TestApiCallback(lock1) { @Override public void onSuccess(Void info) { statuses.put("invite", "invite"); @@ -3274,11 +3322,11 @@ public void onSuccess(Void info) { Assert.assertTrue(statuses.containsKey("invite") && statuses.containsKey("onNewRoom")); - mBobSession.getDataHandler().removeListener(bobEventListener); + bobSession.getDataHandler().removeListener(bobEventListener); final CountDownLatch lock2 = new CountDownLatch(2); - mBobSession.joinRoom(mRoomId, new TestApiCallback(lock2) { + bobSession.joinRoom(mRoomId, new TestApiCallback(lock2) { @Override public void onSuccess(String info) { statuses.put("joinRoom", "joinRoom"); @@ -3323,20 +3371,28 @@ public void onLiveEvent(Event event, RoomState roomState) { Assert.assertTrue(statuses + "", statuses.containsKey("joinRoom")); Assert.assertTrue(statuses + "", statuses.containsKey("AliceJoin")); - mBobSession.getDataHandler().removeListener(bobEventListener); + bobSession.getDataHandler().removeListener(bobEventListener); + + return new Pair<>(aliceSession, bobSession); } - private void doE2ETestWithAliceAndBobAndSamInARoom() throws Exception { + /** + * + * @return Alice, Bob and Sam session + * @throws Exception + */ + private Triple doE2ETestWithAliceAndBobAndSamInARoom() throws Exception { final Map statuses = new HashMap<>(); - doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first; - Room room = mAliceSession.getDataHandler().getRoom(mRoomId); + Room room = aliceSession.getDataHandler().getRoom(mRoomId); - mSamSession = mTestHelper.createSamAccount(true, false); + MXSession samSession = mTestHelper.createSamAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); - mSamSession.enableCrypto(true, new TestApiCallback(lock0) { + samSession.enableCrypto(true, new TestApiCallback(lock0) { @Override public void onSuccess(Void info) { statuses.put("enableCrypto", "enableCrypto"); @@ -3359,9 +3415,9 @@ public void onNewRoom(String roomId) { } }; - mSamSession.getDataHandler().addListener(samEventListener); + samSession.getDataHandler().addListener(samEventListener); - room.invite(mSamSession.getMyUserId(), new TestApiCallback(lock1) { + room.invite(samSession.getMyUserId(), new TestApiCallback(lock1) { @Override public void onSuccess(Void info) { statuses.put("invite", "invite"); @@ -3373,11 +3429,11 @@ public void onSuccess(Void info) { Assert.assertTrue(statuses.containsKey("invite") && statuses.containsKey("onNewRoom")); - mSamSession.getDataHandler().removeListener(samEventListener); + samSession.getDataHandler().removeListener(samEventListener); CountDownLatch lock2 = new CountDownLatch(1); - mSamSession.joinRoom(mRoomId, new TestApiCallback(lock2) { + samSession.joinRoom(mRoomId, new TestApiCallback(lock2) { @Override public void onSuccess(String info) { statuses.put("joinRoom", "joinRoom"); @@ -3391,7 +3447,9 @@ public void onSuccess(String info) { // wait the initial sync SystemClock.sleep(1000); - mSamSession.getDataHandler().removeListener(samEventListener); + samSession.getDataHandler().removeListener(samEventListener); + + return new Triple<>(pair, samSession); } private Event buildTextEvent(String text, MXSession session) { @@ -3402,19 +3460,27 @@ private Event buildTextEvent(String text, MXSession session) { return new Event(message, session.getCredentials().userId, mRoomId); } - private void doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(boolean cryptedBob) throws Exception { - doE2ETestWithAliceAndBobInARoom(cryptedBob); + /** + * + * @param cryptedBob + * @return Alice and Bob sessions + * @throws Exception + */ + private Pair doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(boolean cryptedBob) throws Exception { + Pair pair = doE2ETestWithAliceAndBobInARoom(cryptedBob); + final MXSession aliceSession = pair.first; + final MXSession bobSession = pair.second; - if (null != mBobSession.getCrypto()) { - mBobSession.getCrypto().setWarnOnUnknownDevices(false); + if (null != bobSession.getCrypto()) { + bobSession.getCrypto().setWarnOnUnknownDevices(false); } - if (null != mAliceSession.getCrypto()) { - mAliceSession.getCrypto().setWarnOnUnknownDevices(false); + if (null != aliceSession.getCrypto()) { + aliceSession.getCrypto().setWarnOnUnknownDevices(false); } - final Room roomFromBobPOV = mBobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = mAliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); mMessagesCount = 0; @@ -3423,7 +3489,7 @@ private void doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(boolean crypte MXEventListener bobEventsListener = new MXEventListener() { @Override public void onLiveEvent(Event event, RoomState roomState) { - if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), mBobSession.getMyUserId())) { + if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), bobSession.getMyUserId())) { mMessagesCount++; list.get(0).countDown(); } @@ -3445,7 +3511,7 @@ public void onSuccess(Void info) { list.clear(); list.add(lock); - mBobSession.getDataHandler().addListener(new MXEventListener() { + bobSession.getDataHandler().addListener(new MXEventListener() { @Override public void onToDeviceEvent(Event event) { results.put("onToDeviceEvent", event); @@ -3453,7 +3519,7 @@ public void onToDeviceEvent(Event event) { } }); - roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(0), mAliceSession), callback); + roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(0), aliceSession), callback); lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, mMessagesCount); @@ -3461,7 +3527,7 @@ public void onToDeviceEvent(Event event) { lock = new CountDownLatch(1); list.clear(); list.add(lock); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(0), mBobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(0), bobSession), callback); // android does not echo the messages sent from itself mMessagesCount++; lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); @@ -3470,7 +3536,7 @@ public void onToDeviceEvent(Event event) { lock = new CountDownLatch(1); list.clear(); list.add(lock); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(1), mBobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(1), bobSession), callback); // android does not echo the messages sent from itself mMessagesCount++; lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); @@ -3479,7 +3545,7 @@ public void onToDeviceEvent(Event event) { lock = new CountDownLatch(1); list.clear(); list.add(lock); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(2), mBobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(2), bobSession), callback); // android does not echo the messages sent from itself mMessagesCount++; lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); @@ -3488,9 +3554,11 @@ public void onToDeviceEvent(Event event) { lock = new CountDownLatch(2); list.clear(); list.add(lock); - roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(1), mAliceSession), callback); + roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(1), aliceSession), callback); lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(5, mMessagesCount); + + return pair; } private void checkEncryptedEvent(Event event, String roomId, String clearMessage, MXSession senderSession) { From 7e31b6181b3b2a0a745a197b9134d18ede3ae0d7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 14:24:20 +0200 Subject: [PATCH 009/236] Avoid using class members for test case --- .../matrix/androidsdk/crypto/CryptoTest.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 406a542fd..ff338c362 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -82,7 +82,6 @@ public class CryptoTest { private static final List messagesFromBob = Arrays.asList("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera."); private String mRoomId; - private int mMessagesCount; private int mReceivedMessagesFromAlice; private int mReceivedMessagesFromBob; @@ -3378,7 +3377,7 @@ public void onLiveEvent(Event event, RoomState roomState) { /** * - * @return Alice, Bob and Sam session + * @return Alice, Bbob and sam session * @throws Exception */ private Triple doE2ETestWithAliceAndBobAndSamInARoom() throws Exception { @@ -3482,7 +3481,7 @@ private Pair doE2ETestWithAliceAndBobInARoomWithEncryptedM final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); - mMessagesCount = 0; + final int[] messagesCount = {0}; final List list = new ArrayList<>(); @@ -3490,7 +3489,7 @@ private Pair doE2ETestWithAliceAndBobInARoomWithEncryptedM @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), bobSession.getMyUserId())) { - mMessagesCount++; + messagesCount[0]++; list.get(0).countDown(); } } @@ -3522,41 +3521,41 @@ public void onToDeviceEvent(Event event) { roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(0), aliceSession), callback); lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); - Assert.assertEquals(1, mMessagesCount); + Assert.assertEquals(1, messagesCount[0]); lock = new CountDownLatch(1); list.clear(); list.add(lock); roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(0), bobSession), callback); // android does not echo the messages sent from itself - mMessagesCount++; + messagesCount[0]++; lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertEquals(2, mMessagesCount); + Assert.assertEquals(2, messagesCount[0]); lock = new CountDownLatch(1); list.clear(); list.add(lock); roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(1), bobSession), callback); // android does not echo the messages sent from itself - mMessagesCount++; + messagesCount[0]++; lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertEquals(3, mMessagesCount); + Assert.assertEquals(3, messagesCount[0]); lock = new CountDownLatch(1); list.clear(); list.add(lock); roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(2), bobSession), callback); // android does not echo the messages sent from itself - mMessagesCount++; + messagesCount[0]++; lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertEquals(4, mMessagesCount); + Assert.assertEquals(4, messagesCount[0]); lock = new CountDownLatch(2); list.clear(); list.add(lock); roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(1), aliceSession), callback); lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertEquals(5, mMessagesCount); + Assert.assertEquals(5, messagesCount[0]); return pair; } From 03907ecee894f9a8316674b642cfee563c8a1777 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 14:26:15 +0200 Subject: [PATCH 010/236] Avoid using class members for test case --- .../matrix/androidsdk/crypto/CryptoTest.java | 56 +++++++++---------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index ff338c362..87925880d 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -82,8 +82,6 @@ public class CryptoTest { private static final List messagesFromBob = Arrays.asList("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera."); private String mRoomId; - private int mReceivedMessagesFromAlice; - private int mReceivedMessagesFromBob; @Test public void test01_testCryptoNoDeviceId() throws Exception { @@ -757,8 +755,8 @@ public void test08_testAliceAndBobInAEncryptedRoom2() throws Exception { Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); - mReceivedMessagesFromAlice = 0; - mReceivedMessagesFromBob = 0; + final int[] nbReceivedMessagesFromAlice = {0}; + final int[] nbReceivedMessagesFromBob = {0}; final List list = new ArrayList<>(); @@ -766,9 +764,9 @@ public void test08_testAliceAndBobInAEncryptedRoom2() throws Exception { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), bobSession.getMyUserId())) { - checkEncryptedEvent(event, mRoomId, messagesFromAlice.get(mReceivedMessagesFromAlice), aliceSession); + checkEncryptedEvent(event, mRoomId, messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession); - mReceivedMessagesFromAlice++; + nbReceivedMessagesFromAlice[0]++; list.get(list.size() - 1).countDown(); } } @@ -778,8 +776,8 @@ public void onLiveEvent(Event event, RoomState roomState) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), aliceSession.getMyUserId())) { - checkEncryptedEvent(event, mRoomId, messagesFromBob.get(mReceivedMessagesFromBob), bobSession); - mReceivedMessagesFromBob++; + checkEncryptedEvent(event, mRoomId, messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession); + nbReceivedMessagesFromBob[0]++; list.get(list.size() - 1).countDown(); } @@ -802,30 +800,30 @@ public void onToDeviceEvent(Event event) { } }); - roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(mReceivedMessagesFromAlice), aliceSession), callback); + roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); - Assert.assertEquals(1, mReceivedMessagesFromAlice); + Assert.assertEquals(1, nbReceivedMessagesFromAlice[0]); list.add(new CountDownLatch(1)); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(mReceivedMessagesFromBob), bobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertEquals(1, mReceivedMessagesFromBob); + Assert.assertEquals(1, nbReceivedMessagesFromBob[0]); list.add(new CountDownLatch(1)); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(mReceivedMessagesFromBob), bobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertEquals(2, mReceivedMessagesFromBob); + Assert.assertEquals(2, nbReceivedMessagesFromBob[0]); list.add(new CountDownLatch(1)); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(mReceivedMessagesFromBob), bobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertEquals(3, mReceivedMessagesFromBob); + Assert.assertEquals(3, nbReceivedMessagesFromBob[0]); list.add(new CountDownLatch(1)); - roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(mReceivedMessagesFromAlice), aliceSession), callback); + roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertEquals(2, mReceivedMessagesFromAlice); + Assert.assertEquals(2, nbReceivedMessagesFromAlice[0]); } @Test @@ -3119,8 +3117,8 @@ public void test29_testAliceAndBobInAEncryptedRoomWithReplyTo() throws Exception final List bobReceivedEvents = new ArrayList<>(); final List aliceReceivedEvents = new ArrayList<>(); - mReceivedMessagesFromAlice = 0; - mReceivedMessagesFromBob = 0; + final int[] nbReceivedMessagesFromAlice = {0}; + final int[] nbReceivedMessagesFromBob = {0}; final List list = new ArrayList<>(); @@ -3130,9 +3128,9 @@ public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), bobSession.getMyUserId())) { bobReceivedEvents.add(event); - checkEncryptedEvent(event, mRoomId, messagesFromAlice.get(mReceivedMessagesFromAlice), aliceSession); + checkEncryptedEvent(event, mRoomId, messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession); - mReceivedMessagesFromAlice++; + nbReceivedMessagesFromAlice[0]++; list.get(list.size() - 1).countDown(); } } @@ -3147,14 +3145,14 @@ public void onLiveEvent(Event event, RoomState roomState) { try { // "In reply to" format for body String expectedMessage = "> <" + aliceSession.getMyUserId() + "> " - + messagesFromAlice.get(mReceivedMessagesFromAlice - 1) + + messagesFromAlice.get(nbReceivedMessagesFromAlice[0] - 1) + "\n\n" - + messagesFromBob.get(mReceivedMessagesFromBob); + + messagesFromBob.get(nbReceivedMessagesFromBob[0]); checkEncryptedEvent(event, mRoomId, expectedMessage, bobSession); - mReceivedMessagesFromBob++; + nbReceivedMessagesFromBob[0]++; list.get(list.size() - 1).countDown(); } catch (Exception e) { @@ -3181,18 +3179,18 @@ public void onToDeviceEvent(Event event) { }); // Alice sends a first event - roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(mReceivedMessagesFromAlice), aliceSession), callback); + roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); - Assert.assertEquals(1, mReceivedMessagesFromAlice); + Assert.assertEquals(1, nbReceivedMessagesFromAlice[0]); // Bob reply to Alice event Assert.assertTrue(roomFromBobPOV.canReplyTo(bobReceivedEvents.get(0))); list.add(new CountDownLatch(1)); - roomFromBobPOV.sendTextMessage(messagesFromBob.get(mReceivedMessagesFromBob), null, Message.MSGTYPE_TEXT, bobReceivedEvents.get(0), null); + roomFromBobPOV.sendTextMessage(messagesFromBob.get(nbReceivedMessagesFromBob[0]), null, Message.MSGTYPE_TEXT, bobReceivedEvents.get(0), null); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertEquals(1, mReceivedMessagesFromBob); + Assert.assertEquals(1, nbReceivedMessagesFromBob[0]); Event event = aliceReceivedEvents.get(0); JsonObject json = event.getContentAsJsonObject(); From c23510b50d2b816a3cc85ceab9844c9af56bc487 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 14:55:51 +0200 Subject: [PATCH 011/236] Avoid using class members for test case --- .../androidsdk/common/SessionAndRoomId.java | 33 ++ .../matrix/androidsdk/crypto/CryptoTest.java | 482 +++++++++--------- 2 files changed, 288 insertions(+), 227 deletions(-) create mode 100644 matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/SessionAndRoomId.java diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/SessionAndRoomId.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/SessionAndRoomId.java new file mode 100644 index 000000000..2a833e34f --- /dev/null +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/SessionAndRoomId.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.common; + +import android.util.Pair; + +import org.matrix.androidsdk.MXSession; + +public class SessionAndRoomId extends Pair { + /** + * Constructor for a Pair. + * + * @param first the first object in the Pair + * @param second the second object in the pair + */ + public SessionAndRoomId(MXSession first, String second) { + super(first, second); + } +} diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 87925880d..26b517322 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -38,6 +38,7 @@ import org.matrix.androidsdk.MXDataHandler; import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.common.CommonTestHelper; +import org.matrix.androidsdk.common.SessionAndRoomId; import org.matrix.androidsdk.common.TestApiCallback; import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.common.Triple; @@ -81,8 +82,6 @@ public class CryptoTest { private static final List messagesFromAlice = Arrays.asList("0 - Hello I'm Alice!", "4 - Go!"); private static final List messagesFromBob = Arrays.asList("1 - Hello I'm Bob!", "2 - Isn't life grand?", "3 - Let's go to the opera."); - private String mRoomId; - @Test public void test01_testCryptoNoDeviceId() throws Exception { Log.e(LOG_TAG, "test01_testCryptoNoDeviceId"); @@ -589,21 +588,22 @@ public void onSuccess(Void info) { }); lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("enableCrypto")); - mRoomId = null; + + final String[] roomId = {null}; CountDownLatch lock1 = new CountDownLatch(1); bobSession.createRoom(new TestApiCallback(lock1) { @Override public void onSuccess(String info) { - mRoomId = info; + roomId[0] = info; super.onSuccess(info); } }); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertNotNull(mRoomId); + Assert.assertNotNull(roomId[0]); - Room room = bobSession.getDataHandler().getRoom(mRoomId); + Room room = bobSession.getDataHandler().getRoom(roomId[0]); Assert.assertFalse(room.isEncrypted()); @@ -629,11 +629,13 @@ public void test06_testAliceInAEncryptedRoom() throws Exception { Context context = InstrumentationRegistry.getContext(); - MXSession aliceSession = doE2ETestWithAliceInARoom(); + SessionAndRoomId sessionAndRoomId = doE2ETestWithAliceInARoom(); + MXSession aliceSession = sessionAndRoomId.first; + String aliceRoomId = sessionAndRoomId.second; final String message = "Hello myself!"; - Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -642,7 +644,7 @@ public void test06_testAliceInAEncryptedRoom() throws Exception { // the IOS client echoes the message // the android client does not - roomFromAlicePOV.sendEvent(buildTextEvent(message, aliceSession), new TestApiCallback(lock1)); + roomFromAlicePOV.sendEvent(buildTextEvent(message, aliceSession, aliceRoomId), new TestApiCallback(lock1)); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); @@ -656,21 +658,22 @@ public void test07_testAliceAndBobInAEncryptedRoom() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - final MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + final MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; final MXSession bobSession = pair.second; final String messageFromAlice = "Hello I'm Alice!"; - Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); CountDownLatch lock1 = new CountDownLatch(1); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new TestApiCallback(lock1) { + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new TestApiCallback(lock1) { @Override public void onMatrixError(MatrixError e) { results.put("sendEventError", e); @@ -705,7 +708,7 @@ public void onSuccess(Void info) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); + checkEncryptedEvent(event, aliceRoomId, messageFromAlice, aliceSession); results.put("onLiveEvent", "onLiveEvent"); lock3.countDown(); @@ -723,7 +726,7 @@ public void onToDeviceEvent(Event event) { roomFromBobPOV.addEventListener(eventListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new TestApiCallback(lock3)); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new TestApiCallback(lock3)); lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); @@ -742,15 +745,16 @@ public void onToDeviceEvent(Event event) { public void test08_testAliceAndBobInAEncryptedRoom2() throws Exception { Log.e(LOG_TAG, "test08_testAliceAndBobInAEncryptedRoom2"); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - final MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + final MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; final MXSession bobSession = pair.second; bobSession.getCrypto().setWarnOnUnknownDevices(false); aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -764,7 +768,7 @@ public void test08_testAliceAndBobInAEncryptedRoom2() throws Exception { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), bobSession.getMyUserId())) { - checkEncryptedEvent(event, mRoomId, messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession); + checkEncryptedEvent(event, aliceRoomId, messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession); nbReceivedMessagesFromAlice[0]++; list.get(list.size() - 1).countDown(); @@ -776,7 +780,7 @@ public void onLiveEvent(Event event, RoomState roomState) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), aliceSession.getMyUserId())) { - checkEncryptedEvent(event, mRoomId, messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession); + checkEncryptedEvent(event, aliceRoomId, messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession); nbReceivedMessagesFromBob[0]++; list.get(list.size() - 1).countDown(); @@ -800,28 +804,28 @@ public void onToDeviceEvent(Event event) { } }); - roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession), callback); + roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession, aliceRoomId), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, nbReceivedMessagesFromAlice[0]); list.add(new CountDownLatch(1)); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession, aliceRoomId), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, nbReceivedMessagesFromBob[0]); list.add(new CountDownLatch(1)); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession, aliceRoomId), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(2, nbReceivedMessagesFromBob[0]); list.add(new CountDownLatch(1)); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession, aliceRoomId), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(3, nbReceivedMessagesFromBob[0]); list.add(new CountDownLatch(1)); - roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession), callback); + roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession, aliceRoomId), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(2, nbReceivedMessagesFromAlice[0]); } @@ -833,7 +837,9 @@ public void test09_testAliceInAEncryptedRoomAfterInitialSync() throws Exception Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession aliceSession = doE2ETestWithAliceInARoom(); + SessionAndRoomId sessionAndRoomId = doE2ETestWithAliceInARoom(); + MXSession aliceSession = sessionAndRoomId.first; + final String aliceRoomId = sessionAndRoomId.second; aliceSession.getCrypto().setWarnOnUnknownDevices(false); @@ -899,7 +905,7 @@ public void onCryptoSyncComplete() { Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); - Room roomFromAlicePOV2 = aliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV2 = aliceSession2.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromAlicePOV2.isEncrypted()); @@ -911,7 +917,7 @@ public void onCryptoSyncComplete() { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, message, aliceSession2); + checkEncryptedEvent(event, aliceRoomId, message, aliceSession2); lock2.countDown(); } @@ -923,7 +929,7 @@ public void onLiveEvent(Event event, RoomState roomState) { // the IOS client echoes the message // the android client does not - roomFromAlicePOV2.sendEvent(buildTextEvent(message, aliceSession2), new TestApiCallback(lock2) { + roomFromAlicePOV2.sendEvent(buildTextEvent(message, aliceSession2, aliceRoomId), new TestApiCallback(lock2) { @Override public void onSuccess(Void info) { results.put("sendEvent", "sendEvent"); @@ -944,16 +950,18 @@ public void test10_testAliceDecryptOldMessageWithANewDeviceInAEncryptedRoom() th Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession aliceSession = doE2ETestWithAliceInARoom(); + SessionAndRoomId sessionAndRoomId = doE2ETestWithAliceInARoom(); + MXSession aliceSession = sessionAndRoomId.first; + String aliceRoomId = sessionAndRoomId.second; aliceSession.getCrypto().setWarnOnUnknownDevices(false); String message = "Hello myself!"; - Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); CountDownLatch lock1 = new CountDownLatch(1); - roomFromAlicePOV.sendEvent(buildTextEvent(message, aliceSession), new TestApiCallback(lock1) { + roomFromAlicePOV.sendEvent(buildTextEvent(message, aliceSession, aliceRoomId), new TestApiCallback(lock1) { @Override public void onSuccess(Void info) { results.put("sendEvent", "sendEvent"); @@ -1034,12 +1042,12 @@ public void onCryptoSyncComplete() { Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); - Room roomFromAlicePOV2 = aliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV2 = aliceSession2.getDataHandler().getRoom(aliceRoomId); Assert.assertNotNull(roomFromAlicePOV2); Assert.assertTrue(roomFromAlicePOV2.getState().isEncrypted()); - Event event = roomFromAlicePOV2.getDataHandler().getStore().getLatestEvent(mRoomId); + Event event = roomFromAlicePOV2.getDataHandler().getStore().getLatestEvent(aliceRoomId); Assert.assertNotNull(event); Assert.assertTrue(event.isEncrypted()); Assert.assertNull(event.getClearEvent()); @@ -1055,8 +1063,9 @@ public void test11_testAliceAndBobInAEncryptedRoomBackPaginationFromMemoryStore( Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; MXSession bobSession = pair.second; Credentials bobCredentials = bobSession.getCredentials(); @@ -1095,7 +1104,7 @@ public void onCryptoSyncComplete() { Assert.assertNotNull(bobSession2.getCrypto()); - Room roomFromBobPOV = bobSession2.getDataHandler().getRoom(mRoomId); + Room roomFromBobPOV = bobSession2.getDataHandler().getRoom(aliceRoomId); final CountDownLatch lock2 = new CountDownLatch(6); final List receivedEvents = new ArrayList<>(); @@ -1123,15 +1132,15 @@ public void onSuccess(Integer info) { Assert.assertTrue(results.containsKey("backPaginate")); Assert.assertEquals(receivedEvents.size() + " instead of 5", 5, receivedEvents.size()); - checkEncryptedEvent(receivedEvents.get(0), mRoomId, messagesFromAlice.get(1), aliceSession); + checkEncryptedEvent(receivedEvents.get(0), aliceRoomId, messagesFromAlice.get(1), aliceSession); - checkEncryptedEvent(receivedEvents.get(1), mRoomId, messagesFromBob.get(2), bobSession); + checkEncryptedEvent(receivedEvents.get(1), aliceRoomId, messagesFromBob.get(2), bobSession); - checkEncryptedEvent(receivedEvents.get(2), mRoomId, messagesFromBob.get(1), bobSession); + checkEncryptedEvent(receivedEvents.get(2), aliceRoomId, messagesFromBob.get(1), bobSession); - checkEncryptedEvent(receivedEvents.get(3), mRoomId, messagesFromBob.get(0), bobSession); + checkEncryptedEvent(receivedEvents.get(3), aliceRoomId, messagesFromBob.get(0), bobSession); - checkEncryptedEvent(receivedEvents.get(4), mRoomId, messagesFromAlice.get(0), aliceSession); + checkEncryptedEvent(receivedEvents.get(4), aliceRoomId, messagesFromAlice.get(0), aliceSession); bobSession2.clear(context); aliceSession.clear(context); @@ -1144,13 +1153,14 @@ public void test12_testAliceAndBobInAEncryptedRoomBackPaginationFromHomeServer() Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; MXSession bobSession = pair.second; - String eventId = bobSession.getDataHandler().getStore().getLatestEvent(mRoomId).eventId; + String eventId = bobSession.getDataHandler().getStore().getLatestEvent(aliceRoomId).eventId; - EventTimeline timeline = new EventTimeline(bobSession.getDataHandler(), mRoomId, eventId); + EventTimeline timeline = new EventTimeline(bobSession.getDataHandler(), aliceRoomId, eventId); final CountDownLatch lock2 = new CountDownLatch(6); final List receivedEvents = new ArrayList<>(); @@ -1177,15 +1187,15 @@ public void onSuccess(Integer info) { Assert.assertTrue(results.containsKey("backPaginate")); Assert.assertEquals(5, receivedEvents.size()); - checkEncryptedEvent(receivedEvents.get(0), mRoomId, messagesFromAlice.get(1), aliceSession); + checkEncryptedEvent(receivedEvents.get(0), aliceRoomId, messagesFromAlice.get(1), aliceSession); - checkEncryptedEvent(receivedEvents.get(1), mRoomId, messagesFromBob.get(2), bobSession); + checkEncryptedEvent(receivedEvents.get(1), aliceRoomId, messagesFromBob.get(2), bobSession); - checkEncryptedEvent(receivedEvents.get(2), mRoomId, messagesFromBob.get(1), bobSession); + checkEncryptedEvent(receivedEvents.get(2), aliceRoomId, messagesFromBob.get(1), bobSession); - checkEncryptedEvent(receivedEvents.get(3), mRoomId, messagesFromBob.get(0), bobSession); + checkEncryptedEvent(receivedEvents.get(3), aliceRoomId, messagesFromBob.get(0), bobSession); - checkEncryptedEvent(receivedEvents.get(4), mRoomId, messagesFromAlice.get(0), aliceSession); + checkEncryptedEvent(receivedEvents.get(4), aliceRoomId, messagesFromAlice.get(0), aliceSession); bobSession.clear(context); aliceSession.clear(context); @@ -1197,14 +1207,15 @@ public void test13_testAliceAndNotEncryptedBobInACryptedRoom() throws Exception final Map results = new HashMap(); - Pair pair = doE2ETestWithAliceAndBobInARoom(false); - final MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(false); + final MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; final MXSession bobSession = pair.second; aliceSession.getCrypto().setWarnOnUnknownDevices(false); - Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -1225,7 +1236,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromBobPOV.addEventListener(bobEventListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("bobEcho")); @@ -1253,7 +1264,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromAlicePOV.addEventListener(aliceEventListener); - roomFromBobPOV.sendEvent(buildTextEvent("Hello I'm Bob!", bobSession), new SimpleApiCallback()); + roomFromBobPOV.sendEvent(buildTextEvent("Hello I'm Bob!", bobSession, aliceRoomId), new SimpleApiCallback()); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("aliceEcho")); @@ -1269,18 +1280,19 @@ public void test14_testCryptoDeviceBlockAndLeave() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - Triple triple = doE2ETestWithAliceAndBobAndSamInARoom(); - MXSession aliceSession = triple.first; + Triple triple = doE2ETestWithAliceAndBobAndSamInARoom(); + MXSession aliceSession = triple.first.first; + final String aliceRoomId = triple.first.second; MXSession bobSession = triple.second; MXSession samSession = triple.third; - + bobSession.getCrypto().setWarnOnUnknownDevices(false); aliceSession.getCrypto().setWarnOnUnknownDevices(false); samSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); - final Room roomFromSamPOV = samSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); + final Room roomFromSamPOV = samSession.getDataHandler().getRoom(aliceRoomId); Assert.assertNotNull(roomFromBobPOV); Assert.assertNotNull(roomFromAlicePOV); @@ -1310,7 +1322,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromSamPOV.addEventListener(samEventsListener0); // even if the device blocked, the message must be decrypted until there is a session id rolling - roomFromBobPOV.sendEvent(buildTextEvent("msg1", bobSession), new TestApiCallback(lock0) { + roomFromBobPOV.sendEvent(buildTextEvent("msg1", bobSession, aliceRoomId), new TestApiCallback(lock0) { @Override public void onSuccess(Void info) { results.put("send0", "send0"); @@ -1349,7 +1361,7 @@ public void onLiveEvent(Event event, RoomState roomState) { }; roomFromSamPOV.addEventListener(samEventsListener1); - roomFromAlicePOV.sendEvent(buildTextEvent("msg1", aliceSession), new TestApiCallback(lock1) { + roomFromAlicePOV.sendEvent(buildTextEvent("msg1", aliceSession, aliceRoomId), new TestApiCallback(lock1) { @Override public void onSuccess(Void info) { results.put("send1", "send1"); @@ -1400,7 +1412,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromSamPOV.addEventListener(samEventsListener2); // even if the device blocked, the message must be decrypted until there is a session id rolling - roomFromBobPOV.sendEvent(buildTextEvent("msg2", bobSession), new TestApiCallback(lock2) { + roomFromBobPOV.sendEvent(buildTextEvent("msg2", bobSession, aliceRoomId), new TestApiCallback(lock2) { @Override public void onSuccess(Void info) { results.put("send2", "send2"); @@ -1449,7 +1461,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromAlicePOV.addEventListener(aliceEventsListener3); // even if the device blocked, the message must be decrypted until there is a session id rolling - roomFromBobPOV.sendEvent(buildTextEvent("msg3", bobSession), new TestApiCallback(lock4) { + roomFromBobPOV.sendEvent(buildTextEvent("msg3", bobSession, aliceRoomId), new TestApiCallback(lock4) { @Override public void onSuccess(Void info) { results.put("send3", "send3"); @@ -1470,8 +1482,9 @@ public void test15_testReplayAttack() throws Exception { Log.e(LOG_TAG, "test15_testReplayAttack"); final Map results = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; final MXSession bobSession = pair.second; bobSession.getCrypto().setWarnOnUnknownDevices(false); @@ -1479,8 +1492,8 @@ public void test15_testReplayAttack() throws Exception { String messageFromAlice = "Hello I'm Alice!"; - final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -1512,7 +1525,7 @@ public void onToDeviceEvent(Event event) { } }); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); @@ -1526,7 +1539,7 @@ public void onToDeviceEvent(Event event) { // Decrypting it with no replay attack mitigation must still work bobSession.getDataHandler().decryptEvent(decryptedEvent, null); - checkEncryptedEvent(decryptedEvent, mRoomId, messageFromAlice, aliceSession); + checkEncryptedEvent(decryptedEvent, aliceRoomId, messageFromAlice, aliceSession); } @Test @@ -1535,8 +1548,9 @@ public void test16_testRoomKeyReshare() throws Exception { final Map results = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; MXSession bobSession = pair.second; bobSession.getCrypto().setWarnOnUnknownDevices(false); @@ -1544,8 +1558,8 @@ public void test16_testRoomKeyReshare() throws Exception { String messageFromAlice = "Hello I'm Alice!"; - final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -1576,14 +1590,14 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); - checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); + checkEncryptedEvent(event, aliceRoomId, messageFromAlice, aliceSession); // Reinject a modified version of the received room_key event from Alice. // From Bob pov, that mimics Alice resharing her keys but with an advanced outbound group session. @@ -1602,7 +1616,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro event.setClearData(null); bobSession.getDataHandler().decryptEvent(event, null); - checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); + checkEncryptedEvent(event, aliceRoomId, messageFromAlice, aliceSession); } @Test @@ -1611,8 +1625,9 @@ public void test17_testLateRoomKey() throws Exception { final Map results = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; MXSession bobSession = pair.second; bobSession.getCrypto().setWarnOnUnknownDevices(false); @@ -1620,8 +1635,8 @@ public void test17_testLateRoomKey() throws Exception { String messageFromAlice = "Hello I'm Alice!"; - final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -1651,14 +1666,14 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); - checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); + checkEncryptedEvent(event, aliceRoomId, messageFromAlice, aliceSession); // Reinject a modified version of the received room_key event from Alice. // From Bob pov, that mimics Alice resharing her keys but with an advanced outbound group session. @@ -1698,7 +1713,7 @@ public void onEventDecrypted(Event event) { Assert.assertTrue(results.containsKey("onEventDecrypted")); Assert.assertEquals(1, receivedEvents.size()); - checkEncryptedEvent(receivedEvents.get(0), mRoomId, messageFromAlice, aliceSession); + checkEncryptedEvent(receivedEvents.get(0), aliceRoomId, messageFromAlice, aliceSession); Assert.assertNull(receivedEvents.get(0).getCryptoError()); } @@ -1708,15 +1723,16 @@ public void test18_testAliceAndBobWithNewDevice() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; MXSession bobSession = pair.second; bobSession.getCrypto().setWarnOnUnknownDevices(false); aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); String bobDeviceId1 = bobSession.getCredentials().deviceId; @@ -1750,14 +1766,14 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage1 = "Hello I'm Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession, aliceRoomId), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); - checkEncryptedEvent(event, mRoomId, aliceMessage1, aliceSession); + checkEncryptedEvent(event, aliceRoomId, aliceMessage1, aliceSession); // logout CountDownLatch lock2 = new CountDownLatch(1); @@ -1797,7 +1813,7 @@ public void onToDeviceEvent(Event event) { SystemClock.sleep(1000); - final Room roomFromBobPOV2 = bobSession2.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV2 = bobSession2.getDataHandler().getRoom(aliceRoomId); Assert.assertNotNull(roomFromBobPOV2); final List receivedEvents4 = new ArrayList<>(); @@ -1818,13 +1834,13 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener4); String aliceMessage2 = "Hello I'm still Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, aliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, aliceSession, aliceRoomId), new SimpleApiCallback()); lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals("received event of type " + results.get("event4"), 1, receivedEvents4.size()); event = receivedEvents4.get(0); - checkEncryptedEvent(event, mRoomId, aliceMessage2, aliceSession); + checkEncryptedEvent(event, aliceRoomId, aliceMessage2, aliceSession); } @Test @@ -1833,15 +1849,16 @@ public void test19_testAliceWithNewDeviceAndBobWithNewDevice() throws Exception Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; MXSession bobSession = pair.second; bobSession.getCrypto().setWarnOnUnknownDevices(false); aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); String bobUserId1 = bobSession.getMyUserId(); String aliceUserId1 = aliceSession.getMyUserId(); @@ -1876,14 +1893,14 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage1 = "Hello I'm Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession, aliceRoomId), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); - checkEncryptedEvent(event, mRoomId, aliceMessage1, aliceSession); + checkEncryptedEvent(event, aliceRoomId, aliceMessage1, aliceSession); // logout CountDownLatch lock2 = new CountDownLatch(1); @@ -1916,11 +1933,11 @@ public void onSuccess(Void info) { Assert.assertNotNull(aliceSession2); aliceSession2.getCrypto().setWarnOnUnknownDevices(false); - Room roomFromBob2POV = bobSession2.getDataHandler().getRoom(mRoomId); - Room roomFromAlice2POV = aliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromBob2POV = bobSession2.getDataHandler().getRoom(aliceRoomId); + Room roomFromAlice2POV = aliceSession2.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromBob2POV.isEncrypted()); - event = bobSession2.getDataHandler().getStore().getLatestEvent(mRoomId); + event = bobSession2.getDataHandler().getStore().getLatestEvent(aliceRoomId); Assert.assertNotNull(event); Assert.assertTrue(event.isEncrypted()); Assert.assertNull(event.getClearEvent()); @@ -1940,13 +1957,13 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBob2POV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); String messageFromAlice2 = "Hello I'm still Alice!"; - roomFromAlice2POV.sendEvent(buildTextEvent(messageFromAlice2, aliceSession2), new SimpleApiCallback()); + roomFromAlice2POV.sendEvent(buildTextEvent(messageFromAlice2, aliceSession2, aliceRoomId), new SimpleApiCallback()); lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); event = receivedEvents2.get(0); - checkEncryptedEvent(event, mRoomId, messageFromAlice2, aliceSession2); + checkEncryptedEvent(event, aliceRoomId, messageFromAlice2, aliceSession2); } @Test @@ -1954,15 +1971,16 @@ public void test20_testAliceAndBlockedBob() throws Exception { Log.e(LOG_TAG, "test20_testAliceAndBlockedBob"); final Map results = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; MXSession bobSession = pair.second; bobSession.getCrypto().setWarnOnUnknownDevices(false); aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -1983,13 +2001,13 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage1 = "Hello I'm Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession, aliceRoomId), new SimpleApiCallback()); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); - checkEncryptedEvent(event, mRoomId, aliceMessage1, aliceSession); + checkEncryptedEvent(event, aliceRoomId, aliceMessage1, aliceSession); // block the bob's device CountDownLatch lock1b = new CountDownLatch(1); @@ -2022,7 +2040,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage2 = "Hello I'm still Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, aliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, aliceSession, aliceRoomId), new SimpleApiCallback()); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); @@ -2062,13 +2080,13 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage3 = "Hello I'm still Alice and you can read this!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage3, aliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage3, aliceSession, aliceRoomId), new SimpleApiCallback()); lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents3.size()); event = receivedEvents3.get(0); - checkEncryptedEvent(event, mRoomId, aliceMessage3, aliceSession); + checkEncryptedEvent(event, aliceRoomId, aliceMessage3, aliceSession); } @@ -2077,15 +2095,16 @@ public void test21_testDownloadKeysWithUnreachableHS() throws Exception { Log.e(LOG_TAG, "test21_testDownloadKeysWithUnreachableHS"); final Map results = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; MXSession bobSession = pair.second; bobSession.getCrypto().setWarnOnUnknownDevices(false); aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -2119,8 +2138,9 @@ public void test22_testDownloadKeysForUserWithNoDevice() throws Exception { Log.e(LOG_TAG, "test22_testDownloadKeysForUserWithNoDevice"); final Map results = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoom(false); - MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(false); + MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; MXSession bobSession = pair.second; aliceSession.getCrypto().setWarnOnUnknownDevices(false); @@ -2168,15 +2188,16 @@ public void test23_testFirstMessageSentWhileSessionWasPaused() throws Exception final String messageFromAlice = "Hello I'm Alice!"; final Map results = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - final MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + final MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; MXSession bobSession = pair.second; bobSession.getCrypto().setWarnOnUnknownDevices(false); aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -2188,7 +2209,7 @@ public void test23_testFirstMessageSentWhileSessionWasPaused() throws Exception CountDownLatch lock0 = new CountDownLatch(1); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new TestApiCallback(lock0) { + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new TestApiCallback(lock0) { @Override public void onSuccess(Void info) { results.put("sendEvent", "sendEvent"); @@ -2204,7 +2225,7 @@ public void onSuccess(Void info) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); + checkEncryptedEvent(event, aliceRoomId, messageFromAlice, aliceSession); results.put("onLiveEvent", "onLiveEvent"); lock2.countDown(); @@ -2238,17 +2259,19 @@ public void test24_testExportImport() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession aliceSession = doE2ETestWithAliceInARoom(); + SessionAndRoomId sessionAndRoomId = doE2ETestWithAliceInARoom(); + MXSession aliceSession = sessionAndRoomId.first; + String aliceRoomId = sessionAndRoomId.second; aliceSession.getCrypto().setWarnOnUnknownDevices(false); String message = "Hello myself!"; String password = "hello"; - Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); CountDownLatch lock1 = new CountDownLatch(1); - roomFromAlicePOV.sendEvent(buildTextEvent(message, aliceSession), new TestApiCallback(lock1) { + roomFromAlicePOV.sendEvent(buildTextEvent(message, aliceSession, aliceRoomId), new TestApiCallback(lock1) { @Override public void onSuccess(Void info) { results.put("sendEvent", "sendEvent"); @@ -2341,12 +2364,12 @@ public void onCryptoSyncComplete() { Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); - Room roomFromAlicePOV2 = aliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV2 = aliceSession2.getDataHandler().getRoom(aliceRoomId); Assert.assertNotNull(roomFromAlicePOV2); Assert.assertTrue(roomFromAlicePOV2.getState().isEncrypted()); - Event event = roomFromAlicePOV2.getDataHandler().getStore().getLatestEvent(mRoomId); + Event event = roomFromAlicePOV2.getDataHandler().getStore().getLatestEvent(aliceRoomId); Assert.assertNotNull(event); Assert.assertTrue(event.isEncrypted()); Assert.assertNull(event.getClearEvent()); @@ -2386,7 +2409,7 @@ public void onUnexpectedError(Exception e) { Assert.assertTrue(results.containsKey("importRoomKeys_failed")); // check that the message cannot be decrypted - event = roomFromAlicePOV2.getDataHandler().getStore().getLatestEvent(mRoomId); + event = roomFromAlicePOV2.getDataHandler().getStore().getLatestEvent(aliceRoomId); Assert.assertNotNull(event); Assert.assertTrue(event.isEncrypted()); Assert.assertNull(event.getClearEvent()); @@ -2405,12 +2428,12 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("importRoomKeys")); // check that the message CAN be decrypted - event = roomFromAlicePOV2.getDataHandler().getStore().getLatestEvent(mRoomId); + event = roomFromAlicePOV2.getDataHandler().getStore().getLatestEvent(aliceRoomId); Assert.assertNotNull(event); Assert.assertTrue(event.isEncrypted()); Assert.assertNotNull(event.getClearEvent()); Assert.assertNull(event.getCryptoError()); - checkEncryptedEvent(event, mRoomId, message, aliceSession); + checkEncryptedEvent(event, aliceRoomId, message, aliceSession); aliceSession2.clear(context); } @@ -2453,9 +2476,9 @@ public void onSuccess(String roomId) { }); lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("roomId")); - mRoomId = (String) results.get("roomId"); + String aliceRoomId = (String) results.get("roomId"); - Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); CountDownLatch lock1 = new CountDownLatch(1); roomFromAlicePOV.enableEncryptionWithAlgorithm(MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_MEGOLM, new TestApiCallback(lock1) { @@ -2469,7 +2492,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("enableEncryptionWithAlgorithm")); CountDownLatch lock2 = new CountDownLatch(1); - bobSession.joinRoom(mRoomId, new TestApiCallback(lock2) { + bobSession.joinRoom(aliceRoomId, new TestApiCallback(lock2) { @Override public void onSuccess(String info) { results.put("joinRoom", "joinRoom"); @@ -2479,7 +2502,7 @@ public void onSuccess(String info) { lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("joinRoom")); - Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); final CountDownLatch lock3 = new CountDownLatch(1); final List receivedEvents = new ArrayList<>(); EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { @@ -2492,13 +2515,13 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }; roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); - checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); + checkEncryptedEvent(event, aliceRoomId, messageFromAlice, aliceSession); CountDownLatch lock4 = new CountDownLatch(1); roomFromBobPOV.leave(new TestApiCallback(lock4) { @@ -2522,7 +2545,7 @@ public void onSuccess(Void info) { bobSession2.getCrypto().setWarnOnUnknownDevices(false); CountDownLatch lock5 = new CountDownLatch(1); - bobSession2.joinRoom(mRoomId, new TestApiCallback(lock5) { + bobSession2.joinRoom(aliceRoomId, new TestApiCallback(lock5) { @Override public void onSuccess(String info) { results.put("joinRoom2", "joinRoom2"); @@ -2532,7 +2555,7 @@ public void onSuccess(String info) { lock5.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("joinRoom2")); - Room roomFromBobPOV2 = bobSession2.getDataHandler().getRoom(mRoomId); + Room roomFromBobPOV2 = bobSession2.getDataHandler().getRoom(aliceRoomId); final CountDownLatch lock6 = new CountDownLatch(1); final List receivedEvents2 = new ArrayList<>(); @@ -2546,13 +2569,13 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }; roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); - roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, aliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); lock6.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); event = receivedEvents2.get(0); - checkEncryptedEvent(event, mRoomId, message2FromAlice, aliceSession); + checkEncryptedEvent(event, aliceRoomId, message2FromAlice, aliceSession); bobSession2.clear(context); aliceSession.clear(context); @@ -2583,16 +2606,17 @@ public void test26_testBlackListUnverifiedDevices() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - Triple triple = doE2ETestWithAliceAndBobAndSamInARoom(); - final MXSession aliceSession = triple.first; + Triple triple = doE2ETestWithAliceAndBobAndSamInARoom(); + final MXSession aliceSession = triple.first.first; + final String aliceRoomId = triple.first.second; MXSession bobSession = triple.second; MXSession samSession = triple.third; final String messageFromAlice = "Hello I'm Alice!"; - Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); - Room roomFromSamPOV = samSession.getDataHandler().getRoom(mRoomId); + Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); + Room roomFromSamPOV = samSession.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -2600,7 +2624,7 @@ public void test26_testBlackListUnverifiedDevices() throws Exception { CountDownLatch lock1 = new CountDownLatch(1); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new TestApiCallback(lock1) { + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new TestApiCallback(lock1) { @Override public void onMatrixError(MatrixError e) { results.put("sendEventError", e); @@ -2643,7 +2667,7 @@ public void onSuccess(Void info) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); + checkEncryptedEvent(event, aliceRoomId, messageFromAlice, aliceSession); results.put("onLiveEventBob1", "onLiveEvent"); lock3.countDown(); @@ -2655,7 +2679,7 @@ public void onLiveEvent(Event event, RoomState roomState) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, messageFromAlice, aliceSession); + checkEncryptedEvent(event, aliceRoomId, messageFromAlice, aliceSession); results.put("onLiveEventSam1", "onLiveEvent"); lock3.countDown(); @@ -2682,7 +2706,7 @@ public void onToDeviceEvent(Event event) { roomFromBobPOV.addEventListener(eventListenerBob1); roomFromSamPOV.addEventListener(eventListenerSam1); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new TestApiCallback(lock3) { + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new TestApiCallback(lock3) { @Override public void onSuccess(Void info) { lock3.countDown(); @@ -2706,7 +2730,7 @@ public void onSuccess(Void info) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, activeMessage.get(0), aliceSession); + checkEncryptedEvent(event, aliceRoomId, activeMessage.get(0), aliceSession); results.put("eventListenerBob2", "onLiveEvent"); activeLock.get(0).countDown(); @@ -2721,7 +2745,7 @@ public void onLiveEvent(Event event, RoomState roomState) { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, activeMessage.get(0), aliceSession); + checkEncryptedEvent(event, aliceRoomId, activeMessage.get(0), aliceSession); results.put("eventListenerSam2", "onLiveEvent"); activeLock.get(0).countDown(); @@ -2755,7 +2779,7 @@ public void onSuccess(Void info) { activeMessage.clear(); activeMessage.add("message 1"); - roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession), new TestApiCallback(lock5)); + roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession, aliceRoomId), new TestApiCallback(lock5)); lock5.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertFalse(results.containsKey("eventListenerBob2")); @@ -2783,7 +2807,7 @@ public void onSuccess(Void info) { activeMessage.clear(); activeMessage.add("message 2"); - roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession), new TestApiCallback(lock7)); + roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession, aliceRoomId), new TestApiCallback(lock7)); lock7.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("eventListenerBob2")); @@ -2826,7 +2850,7 @@ public void onSuccess(Void info) { activeMessage.clear(); activeMessage.add("message 3"); - roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession), new TestApiCallback(lock10)); + roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession, aliceRoomId), new TestApiCallback(lock10)); lock10.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("eventListenerBob2")); @@ -2854,7 +2878,7 @@ public void onSuccess(Void info) { activeMessage.clear(); activeMessage.add("message 3"); - roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession), new TestApiCallback(lock12)); + roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession, aliceRoomId), new TestApiCallback(lock12)); lock12.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("eventListenerBob2")); @@ -2917,10 +2941,10 @@ public void onSuccess(String roomId) { }); lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("roomId")); - mRoomId = (String) results.get("roomId"); + String aliceRoomId = (String) results.get("roomId"); CountDownLatch lock1 = new CountDownLatch(1); - bobSession.joinRoom(mRoomId, new TestApiCallback(lock1) { + bobSession.joinRoom(aliceRoomId, new TestApiCallback(lock1) { @Override public void onSuccess(String info) { results.put("joinRoom", "joinRoom"); @@ -2930,10 +2954,10 @@ public void onSuccess(String info) { lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("joinRoom")); - Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); CountDownLatch lock2 = new CountDownLatch(1); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession), new TestApiCallback(lock2) { + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new TestApiCallback(lock2) { @Override public void onSuccess(Void info) { results.put("sendEvent1", "sendEvent1"); @@ -2964,7 +2988,7 @@ public void onSuccess(Void info) { lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("enableEncryptionWithAlgorithm")); - Room roomFromBobPOV2 = bobSession2.getDataHandler().getRoom(mRoomId); + Room roomFromBobPOV2 = bobSession2.getDataHandler().getRoom(aliceRoomId); final CountDownLatch lock4 = new CountDownLatch(1); final List receivedEvents2 = new ArrayList<>(); @@ -2980,13 +3004,13 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }; roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); - roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, aliceSession), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); Event event = receivedEvents2.get(0); - checkEncryptedEvent(event, mRoomId, message2FromAlice, aliceSession); + checkEncryptedEvent(event, aliceRoomId, message2FromAlice, aliceSession); bobSession2.clear(context); aliceSession.clear(context); @@ -3004,14 +3028,15 @@ public void test28_testLeftBobAndAliceWithNewDevice() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(true); - MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(true); + MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; final MXSession bobSession = pair.second; - + // - Bob leaves the room, so stops getting updates CountDownLatch lock1 = new CountDownLatch(1); - final Room bobLeftRoom = bobSession.getDataHandler().getRoom(mRoomId); + final Room bobLeftRoom = bobSession.getDataHandler().getRoom(aliceRoomId); bobLeftRoom.leave(new TestApiCallback(lock1) { @Override public void onSuccess(Void info) { @@ -3028,20 +3053,22 @@ public void onSuccess(Void info) { Assert.assertNotNull(aliceSession2); // - Alice and Bob start sharing a room again + final String[] aliceRoomId2 = {null}; + CountDownLatch lock3 = new CountDownLatch(1); aliceSession2.createRoom(null, null, RoomState.DIRECTORY_VISIBILITY_PUBLIC, null, RoomState.GUEST_ACCESS_CAN_JOIN, null, new TestApiCallback(lock3) { @Override public void onSuccess(String info) { - mRoomId = info; + aliceRoomId2[0] = info; super.onSuccess(info); } }); lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertNotNull(mRoomId); + Assert.assertNotNull(aliceRoomId2[0]); - Room roomFromAlicePOV = aliceSession2.getDataHandler().getRoom(mRoomId); + Room roomFromAlicePOV = aliceSession2.getDataHandler().getRoom(aliceRoomId2[0]); CountDownLatch lock4 = new CountDownLatch(1); roomFromAlicePOV.enableEncryptionWithAlgorithm(MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_MEGOLM, new TestApiCallback(lock4) { @Override @@ -3054,7 +3081,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("lock4")); CountDownLatch lock5 = new CountDownLatch(1); - bobSession.joinRoom(mRoomId, new TestApiCallback(lock5) { + bobSession.joinRoom(aliceRoomId2[0], new TestApiCallback(lock5) { @Override public void onSuccess(String info) { results.put("lock5", "lock5"); @@ -3065,14 +3092,14 @@ public void onSuccess(String info) { Assert.assertTrue(results.containsKey("lock5")); // - Bob has an out of date list of Alice's devices - Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); + Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId2[0]); final String messageFromBob = "Hello Alice with new device!"; final CountDownLatch lock6 = new CountDownLatch(2); MXEventListener eventListener = new MXEventListener() { @Override public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - checkEncryptedEvent(event, mRoomId, messageFromBob, bobSession); + checkEncryptedEvent(event, aliceRoomId2[0], messageFromBob, bobSession); results.put("lock6", "lock6"); lock6.countDown(); @@ -3082,7 +3109,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromAlicePOV.addEventListener(eventListener); - roomFromBobPOV.sendEvent(buildTextEvent(messageFromBob, bobSession), new TestApiCallback(lock6)); + roomFromBobPOV.sendEvent(buildTextEvent(messageFromBob, bobSession, aliceRoomId2[0]), new TestApiCallback(lock6)); lock6.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("lock6")); @@ -3101,15 +3128,16 @@ public void onLiveEvent(Event event, RoomState roomState) { public void test29_testAliceAndBobInAEncryptedRoomWithReplyTo() throws Exception { Log.e(LOG_TAG, "test08_testAliceAndBobInAEncryptedRoom2"); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - final MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + final MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; final MXSession bobSession = pair.second; bobSession.getCrypto().setWarnOnUnknownDevices(false); aliceSession.getCrypto().setWarnOnUnknownDevices(false); - final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); Assert.assertTrue(roomFromBobPOV.isEncrypted()); Assert.assertTrue(roomFromAlicePOV.isEncrypted()); @@ -3128,7 +3156,7 @@ public void onLiveEvent(Event event, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE) && !TextUtils.equals(event.getSender(), bobSession.getMyUserId())) { bobReceivedEvents.add(event); - checkEncryptedEvent(event, mRoomId, messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession); + checkEncryptedEvent(event, aliceRoomId, messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession); nbReceivedMessagesFromAlice[0]++; list.get(list.size() - 1).countDown(); @@ -3150,7 +3178,7 @@ public void onLiveEvent(Event event, RoomState roomState) { + messagesFromBob.get(nbReceivedMessagesFromBob[0]); - checkEncryptedEvent(event, mRoomId, expectedMessage, bobSession); + checkEncryptedEvent(event, aliceRoomId, expectedMessage, bobSession); nbReceivedMessagesFromBob[0]++; @@ -3179,7 +3207,7 @@ public void onToDeviceEvent(Event event) { }); // Alice sends a first event - roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession), callback); + roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession, aliceRoomId), callback); list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, nbReceivedMessagesFromAlice[0]); @@ -3217,11 +3245,10 @@ public void onToDeviceEvent(Event event) { /** - * * @return alice session * @throws Exception */ - private MXSession doE2ETestWithAliceInARoom() throws Exception { + private SessionAndRoomId doE2ETestWithAliceInARoom() throws Exception { final Map results = new HashMap<>(); MXSession aliceSession = mTestHelper.createAliceAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); @@ -3236,21 +3263,21 @@ public void onSuccess(Void info) { lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("enableCrypto")); - mRoomId = null; + final String[] roomId = {null}; CountDownLatch lock1 = new CountDownLatch(1); aliceSession.createRoom(new TestApiCallback(lock1) { @Override - public void onSuccess(String roomId) { - mRoomId = roomId; - super.onSuccess(roomId); + public void onSuccess(String createdRoomId) { + roomId[0] = createdRoomId; + super.onSuccess(createdRoomId); } }); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertNotNull(mRoomId); + Assert.assertNotNull(roomId[0]); - Room room = aliceSession.getDataHandler().getRoom(mRoomId); + Room room = aliceSession.getDataHandler().getRoom(roomId[0]); CountDownLatch lock2 = new CountDownLatch(1); room.enableEncryptionWithAlgorithm(MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_MEGOLM, new TestApiCallback(lock2) { @@ -3263,21 +3290,22 @@ public void onSuccess(Void info) { lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("enableEncryptionWithAlgorithm")); - return aliceSession; + return new SessionAndRoomId(aliceSession, roomId[0]); } /** - * * @param cryptedBob * @return alice and bob sessions * @throws Exception */ - private Pair doE2ETestWithAliceAndBobInARoom(boolean cryptedBob) throws Exception { + private Pair doE2ETestWithAliceAndBobInARoom(boolean cryptedBob) throws Exception { final Map statuses = new HashMap<>(); - MXSession aliceSession = doE2ETestWithAliceInARoom(); - - Room room = aliceSession.getDataHandler().getRoom(mRoomId); + SessionAndRoomId sessionAndRoomId = doE2ETestWithAliceInARoom(); + MXSession aliceSession = sessionAndRoomId.first; + final String aliceRoomId = sessionAndRoomId.second; + + Room room = aliceSession.getDataHandler().getRoom(aliceRoomId); MXSession bobSession = mTestHelper.createBobAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); @@ -3296,7 +3324,7 @@ public void onSuccess(Void info) { MXEventListener bobEventListener = new MXEventListener() { @Override public void onNewRoom(String roomId) { - if (TextUtils.equals(roomId, mRoomId)) { + if (TextUtils.equals(roomId, aliceRoomId)) { if (!statuses.containsKey("onNewRoom")) { statuses.put("onNewRoom", "onNewRoom"); lock1.countDown(); @@ -3323,7 +3351,7 @@ public void onSuccess(Void info) { final CountDownLatch lock2 = new CountDownLatch(2); - bobSession.joinRoom(mRoomId, new TestApiCallback(lock2) { + bobSession.joinRoom(aliceRoomId, new TestApiCallback(lock2) { @Override public void onSuccess(String info) { statuses.put("joinRoom", "joinRoom"); @@ -3370,21 +3398,21 @@ public void onLiveEvent(Event event, RoomState roomState) { bobSession.getDataHandler().removeListener(bobEventListener); - return new Pair<>(aliceSession, bobSession); + return new Pair<>(sessionAndRoomId, bobSession); } /** - * * @return Alice, Bbob and sam session * @throws Exception */ - private Triple doE2ETestWithAliceAndBobAndSamInARoom() throws Exception { + private Triple doE2ETestWithAliceAndBobAndSamInARoom() throws Exception { final Map statuses = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); - MXSession aliceSession = pair.first; + Pair pair = doE2ETestWithAliceAndBobInARoom(true); + MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; - Room room = aliceSession.getDataHandler().getRoom(mRoomId); + Room room = aliceSession.getDataHandler().getRoom(aliceRoomId); MXSession samSession = mTestHelper.createSamAccount(true, false); CountDownLatch lock0 = new CountDownLatch(1); @@ -3403,7 +3431,7 @@ public void onSuccess(Void info) { MXEventListener samEventListener = new MXEventListener() { @Override public void onNewRoom(String roomId) { - if (TextUtils.equals(roomId, mRoomId)) { + if (TextUtils.equals(roomId, aliceRoomId)) { if (!statuses.containsKey("onNewRoom")) { statuses.put("onNewRoom", "onNewRoom"); lock1.countDown(); @@ -3430,7 +3458,7 @@ public void onSuccess(Void info) { CountDownLatch lock2 = new CountDownLatch(1); - samSession.joinRoom(mRoomId, new TestApiCallback(lock2) { + samSession.joinRoom(aliceRoomId, new TestApiCallback(lock2) { @Override public void onSuccess(String info) { statuses.put("joinRoom", "joinRoom"); @@ -3445,27 +3473,27 @@ public void onSuccess(String info) { SystemClock.sleep(1000); samSession.getDataHandler().removeListener(samEventListener); - + return new Triple<>(pair, samSession); } - private Event buildTextEvent(String text, MXSession session) { + private Event buildTextEvent(String text, MXSession session, String roomId) { Message message = new Message(); message.msgtype = Message.MSGTYPE_TEXT; message.body = text; - return new Event(message, session.getCredentials().userId, mRoomId); + return new Event(message, session.getCredentials().userId, roomId); } /** - * * @param cryptedBob * @return Alice and Bob sessions * @throws Exception */ - private Pair doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(boolean cryptedBob) throws Exception { - Pair pair = doE2ETestWithAliceAndBobInARoom(cryptedBob); - final MXSession aliceSession = pair.first; + private Pair doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(boolean cryptedBob) throws Exception { + Pair pair = doE2ETestWithAliceAndBobInARoom(cryptedBob); + final MXSession aliceSession = pair.first.first; + final String aliceRoomId = pair.first.second; final MXSession bobSession = pair.second; if (null != bobSession.getCrypto()) { @@ -3476,8 +3504,8 @@ private Pair doE2ETestWithAliceAndBobInARoomWithEncryptedM aliceSession.getCrypto().setWarnOnUnknownDevices(false); } - final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(mRoomId); - final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(mRoomId); + final Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); + final Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); final int[] messagesCount = {0}; @@ -3516,7 +3544,7 @@ public void onToDeviceEvent(Event event) { } }); - roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(0), aliceSession), callback); + roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(0), aliceSession, aliceRoomId), callback); lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, messagesCount[0]); @@ -3524,7 +3552,7 @@ public void onToDeviceEvent(Event event) { lock = new CountDownLatch(1); list.clear(); list.add(lock); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(0), bobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(0), bobSession, aliceRoomId), callback); // android does not echo the messages sent from itself messagesCount[0]++; lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); @@ -3533,7 +3561,7 @@ public void onToDeviceEvent(Event event) { lock = new CountDownLatch(1); list.clear(); list.add(lock); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(1), bobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(1), bobSession, aliceRoomId), callback); // android does not echo the messages sent from itself messagesCount[0]++; lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); @@ -3542,7 +3570,7 @@ public void onToDeviceEvent(Event event) { lock = new CountDownLatch(1); list.clear(); list.add(lock); - roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(2), bobSession), callback); + roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(2), bobSession, aliceRoomId), callback); // android does not echo the messages sent from itself messagesCount[0]++; lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); @@ -3551,10 +3579,10 @@ public void onToDeviceEvent(Event event) { lock = new CountDownLatch(2); list.clear(); list.add(lock); - roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(1), aliceSession), callback); + roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(1), aliceSession, aliceRoomId), callback); lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(5, messagesCount[0]); - + return pair; } From 8378f396f99cd5c0cedda6898a3fabbd8e598f0a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 14:56:34 +0200 Subject: [PATCH 012/236] Improve test and remove useless code --- .../androidsdk/lazyloading/RoomStateTest.java | 16 ++++++------- .../matrix/androidsdk/data/EventTimeline.java | 24 ------------------- 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index cd5e7703a..544f04ca7 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -92,7 +92,7 @@ public void RoomState_BackPaginate_ShouldLoadAllMembers() throws Exception { RoomState_BackPaginate(false); } - public void RoomState_BackPaginate(final boolean withLazyLoading) throws Exception { + private void RoomState_BackPaginate(final boolean withLazyLoading) throws Exception { final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); mTestHelper.syncSession(data.aliceSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); @@ -127,7 +127,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }); recursiveBackPaginate(liveTimeline, 0, 30, 120); boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertEquals(true, handled); + Assert.assertTrue(handled); } @Test @@ -135,7 +135,7 @@ public void RoomState_Permalink_ShouldLoadAllMembers() throws Exception { RoomState_Permalink(false); } - public void RoomState_Permalink(final boolean withLazyLoading) throws Exception { + private void RoomState_Permalink(final boolean withLazyLoading) throws Exception { final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); mTestHelper.syncSession(data.aliceSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); @@ -150,7 +150,7 @@ public void onSuccess(Void info) { } }); boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertEquals(true, handled); + Assert.assertTrue(handled); final RoomState roomState = eventTimeline.getState(); if (withLazyLoading) { Assert.assertEquals(1, roomState.getMembers().size()); @@ -166,7 +166,7 @@ public void RoomState_PermalinkWithBackPagination_ShouldLoadAllMembers() throws RoomState_PermalinkWithBackPagination(false); } - public void RoomState_PermalinkWithBackPagination(final boolean withLazyLoading) throws Exception { + private void RoomState_PermalinkWithBackPagination(final boolean withLazyLoading) throws Exception { final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); mTestHelper.syncSession(data.aliceSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); @@ -208,7 +208,7 @@ public void onSuccess(Void info) { } }); boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertEquals(true, handled); + Assert.assertTrue(handled); } @Test @@ -221,7 +221,7 @@ public void RoomState_PermalinkWithForwardPagination_ShouldLoadAllMembers() thro // - We should only know Bob membership // - Paginate forward to get Alice next message // - We should know Alice membership now - public void RoomState_PermalinkWithForwardPagination(final boolean withLazyLoading) throws Exception { + private void RoomState_PermalinkWithForwardPagination(final boolean withLazyLoading) throws Exception { final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); mTestHelper.syncSession(data.aliceSession, false); final CountDownLatch lock = new CountDownLatch(1); @@ -260,7 +260,7 @@ public void onSuccess(Void info) { } }); boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertEquals(true, handled); + Assert.assertTrue(handled); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index a86aa09fe..75b106170 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -1521,30 +1521,6 @@ public void run() { }); } } - - @Override - public void onNetworkError(Exception e) { - super.onNetworkError(e); - if (callback != null) { - callback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(MatrixError e) { - super.onMatrixError(e); - if (callback != null) { - callback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(Exception e) { - super.onUnexpectedError(e); - if (callback != null) { - callback.onUnexpectedError(e); - } - } }); } From c222cdc2a18c8c108bfe84c01b8c46b65b3a6dba Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 14:58:28 +0200 Subject: [PATCH 013/236] typo --- .../androidTest/java/org/matrix/androidsdk/common/Triple.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/Triple.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/Triple.java index 144ea40b0..c97449248 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/Triple.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/Triple.java @@ -24,7 +24,7 @@ public class Triple { public C third; /** - * Constructor for a Pair. + * Constructor for a Triple. * * @param first the first object in the Triple * @param second the second object in the Triple From daa7c346c79f6061cccad909bcd610dae2213722 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 15:20:08 +0200 Subject: [PATCH 014/236] Fix compilation issue after rebase --- .../androidsdk/common/CommonTestHelper.java | 8 +- .../matrix/androidsdk/crypto/CryptoTest.java | 141 ++++++++++++++---- .../androidsdk/lazyloading/RoomStateTest.java | 11 +- 3 files changed, 127 insertions(+), 33 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index 45bd62f38..29e8bd8ed 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -45,7 +45,6 @@ import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -307,7 +306,8 @@ public void onSuccess(Credentials credentials) { IMXStore store = new MXFileStore(hs, context); - MXSession mxSession = new MXSession(hs, new MXDataHandler(store, credentials), context); + MXSession mxSession = new MXSession.Builder(hs, new MXDataHandler(store, credentials), context) + .build(); if (enableCrypto) { mxSession.enableCryptoWhenStarting(); @@ -355,7 +355,9 @@ public void onSuccess(Credentials credentials) { hs.setCredentials(credentials); final IMXStore store = new MXFileStore(hs, context); - final MXSession mxSession = new MXSession(hs, new MXDataHandler(store, credentials), context); + final MXSession mxSession = new MXSession.Builder(hs, new MXDataHandler(store, credentials), context) + .build(); + if (enableCrypto) { mxSession.enableCryptoWhenStarting(); } diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 26b517322..7629adcc1 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -150,8 +150,8 @@ public void onSuccess(Void info) { IMXStore store = new MXFileStore(hs, context); - MXSession bobSession2 = new MXSession(hs, new MXDataHandler(store, bobCredentials), context); - + MXSession bobSession2 = new MXSession.Builder(hs, new MXDataHandler(store, bobCredentials), context) + .build(); final CountDownLatch lock1 = new CountDownLatch(1); MXStoreListener listener = new MXStoreListener() { @@ -318,7 +318,8 @@ public void onSuccess(Void info) { IMXStore store = new MXFileStore(hs, context); - MXSession bobSession2 = new MXSession(hs, new MXDataHandler(store, bobCredentials), context); + MXSession bobSession2 = new MXSession.Builder(hs, new MXDataHandler(store, bobCredentials), context) + .build(); final CountDownLatch lock4 = new CountDownLatch(1); @@ -486,7 +487,8 @@ public void onSuccess(MXUsersDevicesMap info) { IMXStore store = new MXFileStore(hs, context); - MXSession bobSession2 = new MXSession(hs, new MXDataHandler(store, bobCredentials), context); + MXSession bobSession2 = new MXSession.Builder(hs, new MXDataHandler(store, bobCredentials), context) + .build(); final CountDownLatch lock5 = new CountDownLatch(1); @@ -788,7 +790,12 @@ public void onLiveEvent(Event event, RoomState roomState) { } }; - ApiCallback callback = new SimpleApiCallback<>(); + ApiCallback callback = new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignored + } + }; roomFromBobPOV.addEventListener(bobEventListener); roomFromAlicePOV.addEventListener(aliceEventListener); @@ -855,7 +862,8 @@ public void test09_testAliceInAEncryptedRoomAfterInitialSync() throws Exception final CountDownLatch lock1 = new CountDownLatch(1); - final MXSession aliceSession2 = new MXSession(hs, new MXDataHandler(store, aliceCredentials), context); + final MXSession aliceSession2 = new MXSession.Builder(hs, new MXDataHandler(store, aliceCredentials), context) + .build(); MXStoreListener listener = new MXStoreListener() { @Override @@ -987,7 +995,8 @@ public void onSuccess(Void info) { IMXStore store = new MXFileStore(hs, context); - MXSession aliceSession2 = new MXSession(hs, new MXDataHandler(store, aliceCredentials2), context); + MXSession aliceSession2 = new MXSession.Builder(hs, new MXDataHandler(store, aliceCredentials2), context) + .build(); aliceSession2.enableCryptoWhenStarting(); @@ -1077,7 +1086,8 @@ public void test11_testAliceAndBobInAEncryptedRoomBackPaginationFromMemoryStore( final CountDownLatch lock1 = new CountDownLatch(2); - MXSession bobSession2 = new MXSession(hs, new MXDataHandler(store, bobCredentials), context); + MXSession bobSession2 = new MXSession.Builder(hs, new MXDataHandler(store, bobCredentials), context) + .build(); MXEventListener eventListener = new MXEventListener() { @Override @@ -1236,7 +1246,12 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromBobPOV.addEventListener(bobEventListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("bobEcho")); @@ -1264,7 +1279,12 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromAlicePOV.addEventListener(aliceEventListener); - roomFromBobPOV.sendEvent(buildTextEvent("Hello I'm Bob!", bobSession, aliceRoomId), new SimpleApiCallback()); + roomFromBobPOV.sendEvent(buildTextEvent("Hello I'm Bob!", bobSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // ignore + } + }); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("aliceEcho")); @@ -1525,7 +1545,12 @@ public void onToDeviceEvent(Event event) { } }); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); @@ -1590,7 +1615,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); @@ -1666,7 +1696,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); @@ -1766,7 +1801,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage1 = "Hello I'm Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession, aliceRoomId), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); @@ -1834,7 +1874,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener4); String aliceMessage2 = "Hello I'm still Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, aliceSession, aliceRoomId), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, aliceSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals("received event of type " + results.get("event4"), 1, receivedEvents4.size()); @@ -1893,7 +1938,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage1 = "Hello I'm Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession, aliceRoomId), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(results.containsKey("onToDeviceEvent")); @@ -1957,7 +2007,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro roomFromBob2POV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); String messageFromAlice2 = "Hello I'm still Alice!"; - roomFromAlice2POV.sendEvent(buildTextEvent(messageFromAlice2, aliceSession2, aliceRoomId), new SimpleApiCallback()); + roomFromAlice2POV.sendEvent(buildTextEvent(messageFromAlice2, aliceSession2, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); @@ -2001,7 +2056,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage1 = "Hello I'm Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession, aliceRoomId), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage1, aliceSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents.size()); @@ -2040,7 +2100,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage2 = "Hello I'm still Alice!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, aliceSession, aliceRoomId), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, aliceSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); @@ -2080,7 +2145,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro String aliceMessage3 = "Hello I'm still Alice and you can read this!"; - roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage3, aliceSession, aliceRoomId), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage3, aliceSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents3.size()); @@ -2309,7 +2379,8 @@ public void onSuccess(byte[] info) { IMXStore store = new MXFileStore(hs, context); - MXSession aliceSession2 = new MXSession(hs, new MXDataHandler(store, aliceCredentials2), context); + MXSession aliceSession2 = new MXSession.Builder(hs, new MXDataHandler(store, aliceCredentials2), context) + .build(); aliceSession2.enableCryptoWhenStarting(); @@ -2515,7 +2586,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }; roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); - roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents.size()); @@ -2569,7 +2645,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }; roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); - roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, aliceSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock6.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); @@ -3004,7 +3085,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }; roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); - roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, aliceSession, aliceRoomId), new SimpleApiCallback()); + roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, aliceSession, aliceRoomId), new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }); lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertEquals(1, receivedEvents2.size()); @@ -3190,7 +3276,12 @@ public void onLiveEvent(Event event, RoomState roomState) { } }; - ApiCallback callback = new SimpleApiCallback<>(); + ApiCallback callback = new SimpleApiCallback() { + @Override + public void onSuccess(Void info) { + // Ignore + } + }; roomFromBobPOV.addEventListener(bobEventListener); roomFromAlicePOV.addEventListener(aliceEventListener); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index 544f04ca7..931f0bce7 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -145,7 +145,6 @@ private void RoomState_Permalink(final boolean withLazyLoading) throws Exception eventTimeline.resetPaginationAroundInitialEvent(10, new SimpleApiCallback() { @Override public void onSuccess(Void info) { - super.onSuccess(info); lock.countDown(); } }); @@ -203,7 +202,6 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro eventTimeline.resetPaginationAroundInitialEvent(0, new SimpleApiCallback() { @Override public void onSuccess(Void info) { - super.onSuccess(info); recursiveBackPaginate(eventTimeline, 0, 30, 120); } }); @@ -255,8 +253,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro eventTimeline.resetPaginationAroundInitialEvent(0, new SimpleApiCallback() { @Override public void onSuccess(Void info) { - super.onSuccess(info); - eventTimeline.forwardPaginate(new SimpleApiCallback()); + eventTimeline.forwardPaginate(new SimpleApiCallback() { + @Override + public void onSuccess(Integer info) { + // Ignore + } + }); } }); boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); @@ -275,7 +277,6 @@ private void recursiveBackPaginate(final EventTimeline timeline, final int curre timeline.backPaginate(eventCountStep, new SimpleApiCallback() { @Override public void onSuccess(Integer info) { - super.onSuccess(info); int realStep = Math.min(eventCountStep, info); int newEventCount = currentEventCount + realStep; if (newEventCount < maxEventCount) { From 3194e062048cac681a69d4981c5ea1ab55a1c5e1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 15:30:45 +0200 Subject: [PATCH 015/236] Avoid import static --- .../java/org/matrix/androidsdk/common/CommonTestHelper.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index 29e8bd8ed..d9a5dffb2 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -38,6 +38,7 @@ import org.matrix.androidsdk.rest.model.login.Credentials; import org.matrix.androidsdk.rest.model.login.RegistrationFlowResponse; import org.matrix.androidsdk.rest.model.login.RegistrationParams; +import org.matrix.androidsdk.rest.model.message.Message; import org.matrix.androidsdk.util.JsonUtils; import java.util.ArrayList; @@ -50,8 +51,6 @@ import javax.annotation.Nonnull; -import static org.matrix.androidsdk.rest.model.message.Message.FORMAT_MATRIX_HTML; - /** * This class exposes methods to be used in common cases @@ -152,7 +151,7 @@ public void onEventSent(Event event, String prevEventId) { }; room.addEventListener(onEventsentListener); for (int i = 0; i < nbOfMessages; i++) { - room.sendTextMessage(message, null, FORMAT_MATRIX_HTML, new RoomMediaMessage.EventCreationListener() { + room.sendTextMessage(message, null, Message.FORMAT_MATRIX_HTML, new RoomMediaMessage.EventCreationListener() { @Override public void onEventCreated(RoomMediaMessage roomMediaMessage) { final Event sentEvent = roomMediaMessage.getEvent(); From 8d245481eceeac440fb73faf4e1b3f95c2724ada Mon Sep 17 00:00:00 2001 From: Tiffany Thuy Kim Nguyen Date: Fri, 7 Sep 2018 04:13:00 +0000 Subject: [PATCH 016/236] Translated using Weblate (Spanish (Mexico)) Currently translated at 100.0% (59 of 59 strings) Translation: Riot Android/matrix-android-sdk Translate-URL: https://translate.riot.im/projects/riot-android/matrix-android-sdk/es_MX/ --- matrix-sdk/src/main/res/values-es-rMX/strings.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/matrix-sdk/src/main/res/values-es-rMX/strings.xml b/matrix-sdk/src/main/res/values-es-rMX/strings.xml index 1565fc9b7..6d3f4734b 100644 --- a/matrix-sdk/src/main/res/values-es-rMX/strings.xml +++ b/matrix-sdk/src/main/res/values-es-rMX/strings.xml @@ -75,4 +75,13 @@ Correo elecrónico Número telefónico +%1$s envió una pegatina. + + En respuesta a + + envió una imagen. + envió un vídeo. + envió un archivo de audio. + envió un archivo. + From 8eef115a31bc3860189c1e703b48d9c217c75ea0 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 14 Sep 2018 17:57:24 +0200 Subject: [PATCH 017/236] Manage events m.server_notice.usage_limit_reached and m.room.pinned_events --- .../org/matrix/androidsdk/data/RoomState.java | 26 +++++++++++++ .../matrix/androidsdk/rest/model/Event.java | 2 + .../rest/model/RoomPinnedEventsContent.java | 39 +++++++++++++++++++ .../model/ServerNoticeUsageLimitContent.java | 30 ++++++++++++++ .../org/matrix/androidsdk/util/JsonUtils.java | 14 +++++++ 5 files changed, 111 insertions(+) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomPinnedEventsContent.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ServerNoticeUsageLimitContent.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 898b73a45..957b860b6 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -18,6 +18,7 @@ package org.matrix.androidsdk.data; +import android.support.annotation.Nullable; import android.text.TextUtils; import com.google.gson.JsonObject; @@ -31,6 +32,7 @@ import org.matrix.androidsdk.rest.model.PowerLevels; import org.matrix.androidsdk.rest.model.RoomCreateContent; import org.matrix.androidsdk.rest.model.RoomMember; +import org.matrix.androidsdk.rest.model.RoomPinnedEventsContent; import org.matrix.androidsdk.rest.model.RoomTombstoneContent; import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.pid.RoomThirdPartyInvite; @@ -122,6 +124,10 @@ public class RoomState implements Externalizable { // the room create content private RoomCreateContent mRoomCreateContent; + // the room pinned events content + @Nullable + private RoomPinnedEventsContent mRoomPinnedEventsContent; + // the join rule public String join_rule; @@ -595,6 +601,7 @@ public RoomState deepCopy() { copy.topic = topic; copy.url = url; copy.mRoomCreateContent = mRoomCreateContent != null ? mRoomCreateContent.deepCopy() : null; + copy.mRoomPinnedEventsContent = mRoomPinnedEventsContent != null ? mRoomPinnedEventsContent.deepCopy() : null; copy.join_rule = join_rule; copy.guest_access = guest_access; copy.history_visibility = history_visibility; @@ -857,6 +864,14 @@ public RoomCreateContent getRoomCreateContent() { return mRoomCreateContent; } + /** + * @return the room pinned events content + */ + @Nullable + public RoomPinnedEventsContent getRoomPinnedEventsContent() { + return mRoomPinnedEventsContent; + } + /** * @return the encryption algorithm */ @@ -1016,6 +1031,8 @@ public boolean applyState(IMXStore store, Event event, EventTimeline.Direction d } } else if (Event.EVENT_TYPE_STATE_ROOM_TOMBSTONE.equals(eventType)) { mRoomTombstoneContent = JsonUtils.toRoomTombstoneContent(contentToConsider); + } else if (Event.EVENT_TYPE_STATE_PINNED_EVENT.equals(eventType)) { + mRoomPinnedEventsContent = JsonUtils.toRoomPinnedEventsContent(contentToConsider); } // same the latest room state events // excepts the membership ones @@ -1165,6 +1182,10 @@ public void readExternal(ObjectInput input) throws IOException, ClassNotFoundExc mRoomCreateContent = (RoomCreateContent) input.readObject(); } + if (input.readBoolean()) { + mRoomPinnedEventsContent = (RoomPinnedEventsContent) input.readObject(); + } + if (input.readBoolean()) { join_rule = input.readUTF(); } @@ -1289,6 +1310,11 @@ public void writeExternal(ObjectOutput output) throws IOException { output.writeObject(mRoomCreateContent); } + output.writeBoolean(null != mRoomPinnedEventsContent); + if (null != mRoomPinnedEventsContent) { + output.writeObject(mRoomPinnedEventsContent); + } + output.writeBoolean(null != join_rule); if (null != join_rule) { output.writeUTF(join_rule); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java index e06828e25..7f5b0d837 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java @@ -93,6 +93,7 @@ public enum SentState { public static final String EVENT_TYPE_ROOM_KEY_REQUEST = "m.room_key_request"; public static final String EVENT_TYPE_FORWARDED_ROOM_KEY = "m.forwarded_room_key"; public static final String EVENT_TYPE_URL_PREVIEW = "org.matrix.room.preview_urls"; + public static final String EVENT_TYPE_SERVER_NOTICE_USAGE_LIMIT = "m.server_notice.usage_limit_reached"; // State events public static final String EVENT_TYPE_STATE_ROOM_NAME = "m.room.name"; @@ -109,6 +110,7 @@ public enum SentState { public static final String EVENT_TYPE_STATE_CANONICAL_ALIAS = "m.room.canonical_alias"; public static final String EVENT_TYPE_STATE_HISTORY_VISIBILITY = "m.room.history_visibility"; public static final String EVENT_TYPE_STATE_RELATED_GROUPS = "m.room.related_groups"; + public static final String EVENT_TYPE_STATE_PINNED_EVENT = "m.room.pinned_events"; // call events public static final String EVENT_TYPE_CALL_INVITE = "m.call.invite"; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomPinnedEventsContent.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomPinnedEventsContent.java new file mode 100644 index 000000000..2dc96b5aa --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomPinnedEventsContent.java @@ -0,0 +1,39 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * Content of a m.room.pinned_events type event + */ +public class RoomPinnedEventsContent implements Serializable { + + public List pinned; + + public RoomPinnedEventsContent deepCopy() { + final RoomPinnedEventsContent copy = new RoomPinnedEventsContent(); + if (pinned == null) { + copy.pinned = null; + } else { + copy.pinned = new ArrayList<>(pinned); + } + return copy; + } + +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ServerNoticeUsageLimitContent.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ServerNoticeUsageLimitContent.java new file mode 100644 index 000000000..3605e14df --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ServerNoticeUsageLimitContent.java @@ -0,0 +1,30 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model; + +import com.google.gson.annotations.SerializedName; + +/** + * Content of a m.server_notice.usage_limit_reached type event + */ +public class ServerNoticeUsageLimitContent { + + public String limit; + @SerializedName("admin_contact") + public String adminUri; + +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java index 9778ad44b..cbc917cb0 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java @@ -36,6 +36,7 @@ import org.matrix.androidsdk.rest.model.PowerLevels; import org.matrix.androidsdk.rest.model.RoomCreateContent; import org.matrix.androidsdk.rest.model.RoomMember; +import org.matrix.androidsdk.rest.model.RoomPinnedEventsContent; import org.matrix.androidsdk.rest.model.RoomTags; import org.matrix.androidsdk.rest.model.RoomTombstoneContent; import org.matrix.androidsdk.rest.model.User; @@ -478,6 +479,19 @@ public static RoomCreateContent toRoomCreateContent(final JsonElement jsonElemen return toClass(jsonElement, RoomCreateContent.class); } + /** + * Convert a JSON object to a RoomPinnedEventsContent. + * The result is never null. + * + * @param jsonElement the json to convert + * @return a RoomPinnedEventsContent + */ + public static RoomPinnedEventsContent toRoomPinnedEventsContent(final JsonElement jsonElement) { + return toClass(jsonElement, RoomPinnedEventsContent.class); + } + + + /** * Convert a JSON object into a class instance. * The returned value cannot be null. From d8327054d7c9ccb3e8fe2e9f220731e20b4eda57 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 14 Sep 2018 17:57:29 +0200 Subject: [PATCH 018/236] DataRetriever : introduce a method to get an event in store and fallback to network if not present. --- .../matrix/androidsdk/data/DataRetriever.java | 194 ++++++++++-------- 1 file changed, 107 insertions(+), 87 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java index e4c466a4b..27f516f25 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java @@ -1,13 +1,13 @@ -/* +/* * Copyright 2014 OpenMarket Ltd * Copyright 2018 New Vector Ltd * * 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. @@ -86,6 +86,24 @@ public void cancelRemoteHistoryRequest(String roomId) { clearPendingToken(mPendingRemoteRequestTokenByRoomId, roomId); } + /** + * Get the event associated with the eventId and roomId + * Look in the store before hitting the rest client. + * + * @param store the store to look in + * @param roomId the room Id + * @param eventId the eventId + * @param callback the callback + */ + public void getEvent(final IMXStore store, final String roomId, final String eventId, final ApiCallback callback) { + final Event event = store.getEvent(eventId, roomId); + if (event == null) { + mRestClient.getEvent(roomId, eventId, callback); + } else { + callback.onSuccess(event); + } + } + /** * Trigger a back pagination for a dedicated room from Token. * @@ -159,82 +177,82 @@ public void run() { Log.d(LOG_TAG, "## backPaginate() : trigger a remote request"); mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, limit, new SimpleApiCallback>(callback) { - @Override - public void onSuccess(TokensChunkResponse events) { - String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); + @Override + public void onSuccess(TokensChunkResponse events) { + String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - Log.d(LOG_TAG, "## backPaginate() succeeds : roomId " + roomId + " token " + token + " vs " + expectedToken); + Log.d(LOG_TAG, "## backPaginate() succeeds : roomId " + roomId + " token " + token + " vs " + expectedToken); - if (TextUtils.equals(expectedToken, token)) { - clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); + if (TextUtils.equals(expectedToken, token)) { + clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - // Watch for the one event overlap - Event oldestEvent = store.getOldestEvent(roomId); + // Watch for the one event overlap + Event oldestEvent = store.getOldestEvent(roomId); - if (events.chunk.size() != 0) { - events.chunk.get(0).mToken = events.start; + if (events.chunk.size() != 0) { + events.chunk.get(0).mToken = events.start; - // there is no more data on server side - if (null == events.end) { - events.end = Event.PAGINATE_BACK_TOKEN_END; - } + // there is no more data on server side + if (null == events.end) { + events.end = Event.PAGINATE_BACK_TOKEN_END; + } + + events.chunk.get(events.chunk.size() - 1).mToken = events.end; + + Event firstReturnedEvent = events.chunk.get(0); + if ((oldestEvent != null) && (firstReturnedEvent != null) + && TextUtils.equals(oldestEvent.eventId, firstReturnedEvent.eventId)) { + events.chunk.remove(0); + } - events.chunk.get(events.chunk.size() - 1).mToken = events.end; + store.storeRoomEvents(roomId, events, EventTimeline.Direction.BACKWARDS); + } - Event firstReturnedEvent = events.chunk.get(0); - if ((oldestEvent != null) && (firstReturnedEvent != null) - && TextUtils.equals(oldestEvent.eventId, firstReturnedEvent.eventId)) { - events.chunk.remove(0); + Log.d(LOG_TAG, "## backPaginate() succeed : roomId " + roomId + " token " + token + " got " + events.chunk.size()); + callback.onSuccess(events); } + } - store.storeRoomEvents(roomId, events, EventTimeline.Direction.BACKWARDS); + private void logErrorMessage(String expectedToken, String errorMessage) { + Log.e(LOG_TAG, "## backPaginate() failed : roomId " + roomId + " token " + token + " expected " + expectedToken + " with " + errorMessage); } - Log.d(LOG_TAG, "## backPaginate() succeed : roomId " + roomId + " token " + token + " got " + events.chunk.size()); - callback.onSuccess(events); - } - } + @Override + public void onNetworkError(Exception e) { + String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); + logErrorMessage(expectedToken, e.getMessage()); - private void logErrorMessage(String expectedToken, String errorMessage) { - Log.e(LOG_TAG, "## backPaginate() failed : roomId " + roomId + " token " + token + " expected " + expectedToken + " with " + errorMessage); - } + // dispatch only if it is expected + if (TextUtils.equals(token, expectedToken)) { + clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); + callback.onNetworkError(e); + } + } - @Override - public void onNetworkError(Exception e) { - String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - logErrorMessage(expectedToken, e.getMessage()); - - // dispatch only if it is expected - if (TextUtils.equals(token, expectedToken)) { - clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - callback.onNetworkError(e); - } - } + @Override + public void onMatrixError(MatrixError e) { + String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); + logErrorMessage(expectedToken, e.getMessage()); - @Override - public void onMatrixError(MatrixError e) { - String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - logErrorMessage(expectedToken, e.getMessage()); - - // dispatch only if it is expected - if (TextUtils.equals(token, expectedToken)) { - clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - callback.onMatrixError(e); - } - } + // dispatch only if it is expected + if (TextUtils.equals(token, expectedToken)) { + clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); + callback.onMatrixError(e); + } + } - @Override - public void onUnexpectedError(Exception e) { - String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - logErrorMessage(expectedToken, e.getMessage()); - - // dispatch only if it is expected - if (TextUtils.equals(token, expectedToken)) { - clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); - callback.onUnexpectedError(e); - } - } - }); + @Override + public void onUnexpectedError(Exception e) { + String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); + logErrorMessage(expectedToken, e.getMessage()); + + // dispatch only if it is expected + if (TextUtils.equals(token, expectedToken)) { + clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); + callback.onUnexpectedError(e); + } + } + }); } } @@ -246,20 +264,21 @@ public void onUnexpectedError(Exception e) { * @param token the start token. * @param callback the callback */ - private void forwardPaginate(final IMXStore store, final String roomId, final String token, final ApiCallback> callback) { + private void forwardPaginate(final IMXStore store, final String roomId, + final String token, final ApiCallback> callback) { putPendingToken(mPendingForwardRequestTokenByRoomId, roomId, token); mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.FORWARDS, RoomsRestClient.DEFAULT_MESSAGES_PAGINATION_LIMIT, new SimpleApiCallback>(callback) { - @Override - public void onSuccess(TokensChunkResponse events) { - if (TextUtils.equals(getPendingToken(mPendingForwardRequestTokenByRoomId, roomId), token)) { - clearPendingToken(mPendingForwardRequestTokenByRoomId, roomId); - store.storeRoomEvents(roomId, events, EventTimeline.Direction.FORWARDS); - callback.onSuccess(events); - } - } - }); + @Override + public void onSuccess(TokensChunkResponse events) { + if (TextUtils.equals(getPendingToken(mPendingForwardRequestTokenByRoomId, roomId), token)) { + clearPendingToken(mPendingForwardRequestTokenByRoomId, roomId); + store.storeRoomEvents(roomId, events, EventTimeline.Direction.FORWARDS); + callback.onSuccess(events); + } + } + }); } /** @@ -272,7 +291,8 @@ public void onSuccess(TokensChunkResponse events) { * @param callback the onComplete callback */ public void paginate(final IMXStore store, final String roomId, final String token, - final EventTimeline.Direction direction, final ApiCallback> callback) { + final EventTimeline.Direction direction, + final ApiCallback> callback) { if (direction == EventTimeline.Direction.BACKWARDS) { backPaginate(store, roomId, token, RoomsRestClient.DEFAULT_MESSAGES_PAGINATION_LIMIT, callback); } else { @@ -297,20 +317,20 @@ public void requestServerRoomHistory(final String roomId, mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, paginationCount, new SimpleApiCallback>(callback) { - @Override - public void onSuccess(TokensChunkResponse info) { + @Override + public void onSuccess(TokensChunkResponse info) { - if (TextUtils.equals(getPendingToken(mPendingRemoteRequestTokenByRoomId, roomId), token)) { - if (info.chunk.size() != 0) { - info.chunk.get(0).mToken = info.start; - info.chunk.get(info.chunk.size() - 1).mToken = info.end; - } + if (TextUtils.equals(getPendingToken(mPendingRemoteRequestTokenByRoomId, roomId), token)) { + if (info.chunk.size() != 0) { + info.chunk.get(0).mToken = info.start; + info.chunk.get(info.chunk.size() - 1).mToken = info.end; + } - clearPendingToken(mPendingRemoteRequestTokenByRoomId, roomId); - callback.onSuccess(info); - } - } - }); + clearPendingToken(mPendingRemoteRequestTokenByRoomId, roomId); + callback.onSuccess(info); + } + } + }); } //============================================================================================================== From 51b2243a2b7b670cfa58c4e837c7171ee01a3dd3 Mon Sep 17 00:00:00 2001 From: dkanada Date: Wed, 29 Aug 2018 15:03:45 +0900 Subject: [PATCH 019/236] fix excessive whitespace on quoted messages --- .../main/java/org/matrix/androidsdk/util/EventDisplay.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/EventDisplay.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/EventDisplay.java index 54b2f3c19..316f6b2da 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/EventDisplay.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/EventDisplay.java @@ -607,6 +607,11 @@ private CharSequence getFormattedMessage(@NonNull final Context context, } else { text = Html.fromHtml(htmlBody, imageGetter, tagHandler); } + // fromHtml formats quotes (> character) with two newlines at the end + // remove any newlines at the end of the CharSequence + while (text.charAt(text.length() - 1) == '\n') { + text = text.subSequence(0, text.length() - 2); + } } } return text; From dc6167b9288a36f588ba22b371f7f391c99e7beb Mon Sep 17 00:00:00 2001 From: dkanada Date: Thu, 30 Aug 2018 12:59:42 +0900 Subject: [PATCH 020/236] update CHANGES.rst --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 2278a8ff9..5d5a7509e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,7 +8,7 @@ Improvements: - Bugfix: - - + - Fix excessive whitespace on quoted messages (#348) API Change: - From 2a4c5d25792c1b9f238e1efc0af86c4d90d6730a Mon Sep 17 00:00:00 2001 From: Arnaud Fontaine Date: Mon, 17 Sep 2018 19:07:31 +0200 Subject: [PATCH 021/236] Protect local data Signed-off-by: Arnaud Fontaine --- CHANGES.rst | 2 +- .../data/cryptostore/MXFileCryptoStore.java | 26 +- .../androidsdk/data/store/MXFileStore.java | 18 +- .../matrix/androidsdk/util/CompatUtil.java | 252 +++++++++++++++++- 4 files changed, 287 insertions(+), 11 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 2278a8ff9..51371aa60 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,7 @@ Features: - Improvements: - - + - Encrypt local data (PR #305) Bugfix: - diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java index 0ce0a2d48..039a29dd1 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java @@ -38,8 +38,10 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -162,6 +164,8 @@ public class MXFileCryptoStore implements IMXCryptoStore { // tell if the store is ready private boolean mIsReady = false; + private Context mContext; + public MXFileCryptoStore() { } @@ -216,6 +220,8 @@ public void initWithCredentials(Context context, Credentials credentials) { mTrackingStatuses = new HashMap<>(); mOlmSessions = new HashMap<>(); mInboundGroupSessions = new HashMap<>(); + + mContext = context; } @Override @@ -381,14 +387,17 @@ private boolean storeObject(Object object, File file, String description) { } FileOutputStream fos = new FileOutputStream(file); - GZIPOutputStream gz = CompatUtil.createGzipOutputStream(fos); + OutputStream cos = CompatUtil.createCipherOutputStream(fos, mContext); + GZIPOutputStream gz = CompatUtil.createGzipOutputStream(cos); ObjectOutputStream out = new ObjectOutputStream(gz); out.writeObject(object); + out.flush(); out.close(); succeed = true; Log.d(LOG_TAG, "## storeObject () : " + description + " done in " + (System.currentTimeMillis() - t0) + " ms"); + } catch (OutOfMemoryError oom) { Log.e(LOG_TAG, "storeObject failed : " + description + " -- " + oom.getMessage(), oom); } catch (Exception e) { @@ -1110,8 +1119,19 @@ private Object loadObject(File file, String description) { try { // the files are now zipped to reduce saving time FileInputStream fis = new FileInputStream(file); - GZIPInputStream gz = new GZIPInputStream(fis); + InputStream cis = CompatUtil.createCipherInputStream(fis, mContext); + GZIPInputStream gz; + + if (cis != null) { + gz = new GZIPInputStream(cis); + } else { + //fallback to unencrypted stream for backward compatibility + Log.i(LOG_TAG, "## loadObject() : failed to read encrypted, fallback to unencrypted read"); + gz = new GZIPInputStream(fis); + } + ObjectInputStream ois = new ObjectInputStream(gz); + object = ois.readObject(); ois.close(); } catch (Exception e) { @@ -1123,7 +1143,7 @@ private Object loadObject(File file, String description) { ObjectInputStream out = new ObjectInputStream(fis2); object = out.readObject(); - fis2.close(); + out.close(); } catch (Exception subEx) { // warn that some file loading fails mIsCorrupted = true; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java index a5c2f4bbd..e3d5082bb 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java @@ -47,8 +47,10 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -2303,10 +2305,12 @@ private boolean writeObject(String description, File file, Object object) { boolean succeed = false; try { FileOutputStream fos = new FileOutputStream(file); - GZIPOutputStream gz = CompatUtil.createGzipOutputStream(fos); + OutputStream cos = CompatUtil.createCipherOutputStream(fos, mContext); + GZIPOutputStream gz = CompatUtil.createGzipOutputStream(cos); ObjectOutputStream out = new ObjectOutputStream(gz); out.writeObject(object); + out.flush(); out.close(); succeed = true; @@ -2346,7 +2350,17 @@ private Object readObject(String description, File file) { Object object = null; try { FileInputStream fis = new FileInputStream(file); - GZIPInputStream gz = new GZIPInputStream(fis); + InputStream cis = CompatUtil.createCipherInputStream(fis, mContext); + GZIPInputStream gz; + + if (cis != null) { + gz = new GZIPInputStream(cis); + } else { + //fallback to unencrypted stream for backward compatibility + Log.i(LOG_TAG, "## readObject() : failed to read encrypted, fallback to unencrypted read"); + gz = new GZIPInputStream(fis); + } + ObjectInputStream ois = new ObjectInputStream(gz); object = ois.readObject(); ois.close(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java index 9e36ccbfb..e056e52b6 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java @@ -16,26 +16,268 @@ package org.matrix.androidsdk.util; +import android.content.Context; +import android.content.SharedPreferences; import android.os.Build; +import android.preference.PreferenceManager; +import android.security.KeyPairGeneratorSpec; +import android.security.keystore.KeyGenParameterSpec; +import android.security.keystore.KeyProperties; +import android.support.annotation.Nullable; +import android.support.annotation.RequiresApi; +import android.util.Base64; -import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.RSAKeyGenParameterSpec; +import java.util.Calendar; import java.util.zip.GZIPOutputStream; +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyGenerator; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.security.auth.x500.X500Principal; + public class CompatUtil { + private static final String TAG = CompatUtil.class.getSimpleName(); + private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore"; + private static final String AES_GCM_CIPHER_TYPE = "AES/GCM/NoPadding"; + private static final int AES_GCM_KEY_SIZE_IN_BITS = 128; + private static final int AES_GCM_IV_LENGTH = 12; + private static final String AES_LOCAL_PROTECTION_KEY_ALIAS = "aes_local_protection"; + + private static final String RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS = "rsa_wrap_local_protection"; + private static final String RSA_WRAP_CIPHER_TYPE = "RSA/NONE/PKCS1Padding"; + private static final String AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE = "aes_wrapped_local_protection"; + + private static SecretKey sLocalProtectionKey; + private static SecureRandom sPrng; /** * Create a GZIPOutputStream instance * Special treatment on KitKat device, force the syncFlush param to false * Before Kitkat, this param does not exist and after Kitkat it is set to false by default * - * @param fileOutputStream the output stream + * @param outputStream the output stream */ - public static GZIPOutputStream createGzipOutputStream(FileOutputStream fileOutputStream) throws IOException { + public static GZIPOutputStream createGzipOutputStream(OutputStream outputStream) throws IOException { if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { - return new GZIPOutputStream(fileOutputStream, false); + return new GZIPOutputStream(outputStream, false); } else { - return new GZIPOutputStream(fileOutputStream); + return new GZIPOutputStream(outputStream); + } + } + + /** + * Returns the AES key used for local storage encryption/decryption with AES/GCM. + * The key is created if it does not exist already in the keystore. + * From Marshmallow, this key is generated and operated directly from the android keystore. + * From KitKat and before Marshmallow, this key is stored in the application shared preferences + * wrapped by a RSA key generated and operated directly from the android keystore. + * Before Kitkat, this param does not exist and after Kitkat it is set to false by default. + * + * @param context the context holding the application shared preferences + */ + @RequiresApi(Build.VERSION_CODES.KITKAT) + private static synchronized SecretKey getAesGcmLocalProtectionKey(Context context) + throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, + NoSuchProviderException, InvalidAlgorithmParameterException, NoSuchPaddingException, + InvalidKeyException, IllegalBlockSizeException, UnrecoverableKeyException { + if (sLocalProtectionKey == null) { + final KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER); + keyStore.load(null); + + Log.i(TAG, "Loading local protection key"); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (keyStore.containsAlias(AES_LOCAL_PROTECTION_KEY_ALIAS)) { + Log.i(TAG, "AES local protection key found in keystore"); + sLocalProtectionKey = (SecretKey) keyStore.getKey(AES_LOCAL_PROTECTION_KEY_ALIAS, null); + } else { + Log.i(TAG, "Generating AES key with keystore"); + final KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE_PROVIDER); + generator.init( + new KeyGenParameterSpec.Builder(AES_LOCAL_PROTECTION_KEY_ALIAS, + KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) + .setBlockModes(KeyProperties.BLOCK_MODE_GCM) + .setKeySize(AES_GCM_KEY_SIZE_IN_BITS) + .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) + .build()); + sLocalProtectionKey = generator.generateKey(); + } + } else { + final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + final String wrappedAesKeyString = sharedPreferences.getString(AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE, null); + if (wrappedAesKeyString != null && keyStore.containsAlias(RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS)) { + Log.i(TAG, "RSA + wrapped AES local protection keys found in keystore"); + final PrivateKey privateKey = (PrivateKey) keyStore.getKey(RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS, null); + final byte[] wrappedAesKey = Base64.decode(wrappedAesKeyString, 0); + final Cipher cipher = Cipher.getInstance(RSA_WRAP_CIPHER_TYPE); + cipher.init(Cipher.UNWRAP_MODE, privateKey); + sLocalProtectionKey = (SecretKey) cipher.unwrap(wrappedAesKey, "AES", Cipher.SECRET_KEY); + } else { + Log.i(TAG, "Generating RSA key pair with keystore"); + final KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEY_STORE_PROVIDER); + final Calendar start = Calendar.getInstance(); + final Calendar end = Calendar.getInstance(); + end.add(Calendar.YEAR, 10); + + generator.initialize( + new KeyPairGeneratorSpec.Builder(context) + .setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4)) + .setAlias(RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS) + .setSubject(new X500Principal("CN=matrix-android-sdk")) + .setStartDate(start.getTime()) + .setEndDate(end.getTime()) + .setSerialNumber(BigInteger.ONE) + .build()); + final KeyPair keyPair = generator.generateKeyPair(); + + Log.i(TAG, "Generating wrapped AES key"); + + final byte[] aesKeyRaw = new byte[AES_GCM_KEY_SIZE_IN_BITS / Byte.SIZE]; + getPrng().nextBytes(aesKeyRaw); + sLocalProtectionKey = new SecretKeySpec(aesKeyRaw, "AES"); + + final Cipher cipher = Cipher.getInstance(RSA_WRAP_CIPHER_TYPE); + cipher.init(Cipher.WRAP_MODE, keyPair.getPublic()); + byte[] wrappedAesKey = cipher.wrap(sLocalProtectionKey); + + final SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit(); + editor.putString(AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE, Base64.encodeToString(wrappedAesKey, 0)); + editor.apply(); + } + } + } + + return sLocalProtectionKey; + } + + + /** + * Returns the unique SecureRandom instance shared for all local storage encryption operations. + */ + private static SecureRandom getPrng() { + if (sPrng == null) { + sPrng = new SecureRandom(); } + + return sPrng; + } + + /** + * Create a CipherOutputStream instance. + * Before Kitkat, this method will return out as local storage encryption is not implemented for + * devices before KitKat. + * + * @param out the output stream + * @param context the context holding the application shared preferences + */ + @Nullable + public static OutputStream createCipherOutputStream(OutputStream out, Context context) + throws IOException, CertificateException, NoSuchAlgorithmException, + UnrecoverableKeyException, InvalidKeyException, InvalidAlgorithmParameterException, + NoSuchPaddingException, NoSuchProviderException, KeyStoreException, IllegalBlockSizeException { + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + return out; + } + + final SecretKey key = getAesGcmLocalProtectionKey(context); + if (key == null) { + throw new KeyStoreException(); + } + + final Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE); + byte[] iv = null; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + cipher.init(Cipher.ENCRYPT_MODE, key); + iv = cipher.getIV(); + } else { + iv = new byte[AES_GCM_IV_LENGTH]; + getPrng().nextBytes(iv); + cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); + } + + if (iv.length != AES_GCM_IV_LENGTH) { + Log.e(TAG, "Invalid IV length " + iv.length); + return null; + } + + out.write(iv.length); + out.write(iv); + + return new CipherOutputStream(out, cipher); + } + + /** + * Create a CipherInputStream instance. + * Before Kitkat, this method will return in as local storage encryption is not implemented + * for devices before KitKat. + * + * @param in the output stream + * @param context the context holding the application shared preferences + */ + @Nullable + public static InputStream createCipherInputStream(InputStream in, Context context) + throws NoSuchPaddingException, NoSuchAlgorithmException, CertificateException, + InvalidKeyException, KeyStoreException, UnrecoverableKeyException, IllegalBlockSizeException, + NoSuchProviderException, InvalidAlgorithmParameterException, IOException { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + return in; + } + + in.mark(4 + AES_GCM_IV_LENGTH); + final int iv_len = in.read(); + if (iv_len != AES_GCM_IV_LENGTH) { + Log.e(TAG, "Invalid IV length " + iv_len); + in.reset(); + return null; + } + + final byte[] iv = new byte[iv_len]; + in.read(iv); + + final Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE); + + final SecretKey key = getAesGcmLocalProtectionKey(context); + if (key == null) { + throw new KeyStoreException(); + } + + AlgorithmParameterSpec spec = null; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + spec = new GCMParameterSpec(AES_GCM_KEY_SIZE_IN_BITS, iv); + } else { + spec = new IvParameterSpec(iv); + } + + cipher.init(Cipher.DECRYPT_MODE, key, spec); + + return new CipherInputStream(in, cipher); } } From cc043e20a70273f4451b07dd8d445737d91f2a53 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 18 Sep 2018 14:30:57 +0200 Subject: [PATCH 022/236] ServerNoticeUsageLimitContent : add a type field --- .../androidsdk/rest/model/ServerNoticeUsageLimitContent.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ServerNoticeUsageLimitContent.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ServerNoticeUsageLimitContent.java index 3605e14df..0add6bc83 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ServerNoticeUsageLimitContent.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ServerNoticeUsageLimitContent.java @@ -26,5 +26,7 @@ public class ServerNoticeUsageLimitContent { public String limit; @SerializedName("admin_contact") public String adminUri; + @SerializedName("server_notice_type") + public String type; } From c46a9008d2268c4418aba8e6765a69e028885fe5 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 18 Sep 2018 16:27:28 +0200 Subject: [PATCH 023/236] Update CHANGES.rst --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 2278a8ff9..847526589 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,7 +2,7 @@ Changes to Matrix Android SDK in 0.9.10 (2018-XX-XX) ======================================================= Features: - - + - Handle m.room.pinned_events state event and ServerNoticeUsageLimitContent Improvements: - From 0ac4690d81e4f2f2d899070ff4abeaede6dae054 Mon Sep 17 00:00:00 2001 From: dkanada Date: Tue, 18 Sep 2018 23:24:45 +0900 Subject: [PATCH 024/236] scroll to bottom no longer keeps inertia after position change --- .../matrix/androidsdk/fragments/MatrixMessageListFragment.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java index 4c2cd7483..6316fcdac 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java @@ -735,6 +735,8 @@ public void scrollToBottom(int delayMs) { @Override public void run() { mMessageListView.setSelection(mAdapter.getCount() - 1); + // stop any scroll inertia after the jump + mMessageListView.smoothScrollBy(0, 0); } }, Math.max(delayMs, 0)); } From 1fd91afb3c76eace3bc5e439846b80e0219b5447 Mon Sep 17 00:00:00 2001 From: dkanada Date: Tue, 18 Sep 2018 23:25:03 +0900 Subject: [PATCH 025/236] update CHANGES.rst --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index 5d5a7509e..65cb0e128 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -9,6 +9,7 @@ Improvements: Bugfix: - Fix excessive whitespace on quoted messages (#348) + - Scroll to bottom no longer keeps inertia after position change (#354) API Change: - From f5b0cd36a51912684c9ad885ae48da4fdec51147 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Sep 2018 18:09:51 +0200 Subject: [PATCH 026/236] Create constructor to enable file encryption --- .../java/org/matrix/androidsdk/MXSession.java | 14 +++++++-- .../data/cryptostore/MXFileCryptoStore.java | 25 +++++++++++++-- .../androidsdk/data/store/MXFileStore.java | 31 +++++++++++++------ 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index bc176e83b..b64fc8dff 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -161,6 +161,9 @@ public class MXSession { private final HomeServerConnectionConfig mHsConfig; + // True if file encryption is enabled + private boolean mEnableFileEncryption; + // the application is launched from a notification // so, mEventsThread.start might be not ready private boolean mIsBgCatchupPending = false; @@ -270,7 +273,7 @@ public void postProcess(String accountId) { // test if the crypto instance has already been created if (null == mCrypto) { - MXFileCryptoStore store = new MXFileCryptoStore(); + MXFileCryptoStore store = new MXFileCryptoStore(mEnableFileEncryption); store.initWithCredentials(mAppContent, mCredentials); if (store.hasData() || mEnableCryptoWhenStartingMXSession) { @@ -2184,7 +2187,7 @@ private void decryptRoomSummaries() { * Launch it it is was not yet done. */ public void checkCrypto() { - MXFileCryptoStore fileCryptoStore = new MXFileCryptoStore(); + MXFileCryptoStore fileCryptoStore = new MXFileCryptoStore(mEnableFileEncryption); fileCryptoStore.initWithCredentials(mAppContent, mCredentials); if ((fileCryptoStore.hasData() || mEnableCryptoWhenStartingMXSession) && (null == mCrypto)) { @@ -2238,7 +2241,7 @@ public void enableCrypto(boolean cryptoEnabled, final ApiCallback callback if (cryptoEnabled != isCryptoEnabled()) { if (cryptoEnabled) { Log.d(LOG_TAG, "Crypto is enabled"); - MXFileCryptoStore fileCryptoStore = new MXFileCryptoStore(); + MXFileCryptoStore fileCryptoStore = new MXFileCryptoStore(mEnableFileEncryption); fileCryptoStore.initWithCredentials(mAppContent, mCredentials); fileCryptoStore.open(); mCrypto = new MXCrypto(this, fileCryptoStore, sCryptoConfig); @@ -2476,6 +2479,11 @@ public Builder(HomeServerConnectionConfig hsConfig, MXDataHandler dataHandler, C mxSession = new MXSession(hsConfig, dataHandler, context); } + public Builder withFileEncryption() { + mxSession.mEnableFileEncryption = true; + return this; + } + /** * Create a pusher rest client, overriding the push server url if necessary * diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java index 039a29dd1..a46bc71bf 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java @@ -166,7 +166,16 @@ public class MXFileCryptoStore implements IMXCryptoStore { private Context mContext; - public MXFileCryptoStore() { + // True if file encryption is enabled + private final boolean mEnableFileEncryption; + + /** + * Constructor + * + * @param enableFileEncryption set to true to enable file encryption. + */ + public MXFileCryptoStore(boolean enableFileEncryption) { + mEnableFileEncryption = enableFileEncryption; } @Override @@ -387,7 +396,12 @@ private boolean storeObject(Object object, File file, String description) { } FileOutputStream fos = new FileOutputStream(file); - OutputStream cos = CompatUtil.createCipherOutputStream(fos, mContext); + OutputStream cos; + if (mEnableFileEncryption) { + cos = CompatUtil.createCipherOutputStream(fos, mContext); + } else { + cos = fos; + } GZIPOutputStream gz = CompatUtil.createGzipOutputStream(cos); ObjectOutputStream out = new ObjectOutputStream(gz); @@ -1119,7 +1133,12 @@ private Object loadObject(File file, String description) { try { // the files are now zipped to reduce saving time FileInputStream fis = new FileInputStream(file); - InputStream cis = CompatUtil.createCipherInputStream(fis, mContext); + InputStream cis; + if (mEnableFileEncryption) { + cis = CompatUtil.createCipherInputStream(fis, mContext); + } else { + cis = fis; + } GZIPInputStream gz; if (cis != null) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java index e3d5082bb..b59e90cb0 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java @@ -29,9 +29,7 @@ import org.matrix.androidsdk.data.RoomAccountData; import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.data.RoomSummary; -import org.matrix.androidsdk.data.metrics.MetricsListener; import org.matrix.androidsdk.rest.callback.ApiCallback; -import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.ReceiptData; import org.matrix.androidsdk.rest.model.RoomMember; @@ -144,6 +142,9 @@ public class MXFileStore extends MXMemoryStore { // store some stats private final Map mStoreStats = new HashMap<>(); + // True if file encryption is enabled + private final boolean mEnableFileEncryption; + /** * Create the file store dirtrees */ @@ -214,15 +215,17 @@ private void createDirTree(String userId) { } /** - * Default constructor + * Constructor * - * @param hsConfig the expected credentials - * @param context the context. + * @param hsConfig the expected credentials + * @param enableFileEncryption set to true to enable file encryption. + * @param context the context. */ - public MXFileStore(HomeServerConnectionConfig hsConfig, Context context) { - initCommon(); + public MXFileStore(HomeServerConnectionConfig hsConfig, boolean enableFileEncryption, Context context) { setContext(context); + mEnableFileEncryption = enableFileEncryption; + mIsReady = false; mCredentials = hsConfig.getCredentials(); @@ -2305,7 +2308,12 @@ private boolean writeObject(String description, File file, Object object) { boolean succeed = false; try { FileOutputStream fos = new FileOutputStream(file); - OutputStream cos = CompatUtil.createCipherOutputStream(fos, mContext); + OutputStream cos; + if (mEnableFileEncryption) { + cos = CompatUtil.createCipherOutputStream(fos, mContext); + } else { + cos = fos; + } GZIPOutputStream gz = CompatUtil.createGzipOutputStream(cos); ObjectOutputStream out = new ObjectOutputStream(gz); @@ -2350,7 +2358,12 @@ private Object readObject(String description, File file) { Object object = null; try { FileInputStream fis = new FileInputStream(file); - InputStream cis = CompatUtil.createCipherInputStream(fis, mContext); + InputStream cis; + if (mEnableFileEncryption) { + cis = CompatUtil.createCipherInputStream(fis, mContext); + } else { + cis = fis; + } GZIPInputStream gz; if (cis != null) { From 03c8986dcf7844f845b4b5f7ccca940a882eb7bd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Sep 2018 18:54:13 +0200 Subject: [PATCH 027/236] Ensure a file encrypted on Android < M can be decrypted on Android >= M --- .../matrix/androidsdk/util/CompatUtil.java | 121 +++++++++++------- .../androidsdk/util/SecretKeyAndVersion.java | 40 ++++++ 2 files changed, 118 insertions(+), 43 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/util/SecretKeyAndVersion.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java index e056e52b6..53d912a78 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java @@ -72,7 +72,9 @@ public class CompatUtil { private static final String RSA_WRAP_CIPHER_TYPE = "RSA/NONE/PKCS1Padding"; private static final String AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE = "aes_wrapped_local_protection"; - private static SecretKey sLocalProtectionKey; + private static final String SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED = "android_version_when_key_has_been_generated"; + + private static SecretKeyAndVersion sSecretKeyAndVersion; private static SecureRandom sPrng; /** @@ -101,43 +103,50 @@ public static GZIPOutputStream createGzipOutputStream(OutputStream outputStream) * @param context the context holding the application shared preferences */ @RequiresApi(Build.VERSION_CODES.KITKAT) - private static synchronized SecretKey getAesGcmLocalProtectionKey(Context context) + private static synchronized SecretKeyAndVersion getAesGcmLocalProtectionKey(Context context) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, NoSuchProviderException, InvalidAlgorithmParameterException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, UnrecoverableKeyException { - if (sLocalProtectionKey == null) { + if (sSecretKeyAndVersion == null) { final KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER); keyStore.load(null); Log.i(TAG, "Loading local protection key"); + SecretKey key; + + final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + final int androidVersion = sharedPreferences.getInt(SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED, Build.VERSION.SDK_INT); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (keyStore.containsAlias(AES_LOCAL_PROTECTION_KEY_ALIAS)) { Log.i(TAG, "AES local protection key found in keystore"); - sLocalProtectionKey = (SecretKey) keyStore.getKey(AES_LOCAL_PROTECTION_KEY_ALIAS, null); + key = (SecretKey) keyStore.getKey(AES_LOCAL_PROTECTION_KEY_ALIAS, null); } else { - Log.i(TAG, "Generating AES key with keystore"); - final KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE_PROVIDER); - generator.init( - new KeyGenParameterSpec.Builder(AES_LOCAL_PROTECTION_KEY_ALIAS, - KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) - .setBlockModes(KeyProperties.BLOCK_MODE_GCM) - .setKeySize(AES_GCM_KEY_SIZE_IN_BITS) - .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) - .build()); - sLocalProtectionKey = generator.generateKey(); + // Check if a key has been created on version < M (in case of OS upgrade) + key = readKeyApiL(sharedPreferences, keyStore); + + if (key == null) { + Log.i(TAG, "Generating AES key with keystore"); + final KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE_PROVIDER); + generator.init( + new KeyGenParameterSpec.Builder(AES_LOCAL_PROTECTION_KEY_ALIAS, + KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) + .setBlockModes(KeyProperties.BLOCK_MODE_GCM) + .setKeySize(AES_GCM_KEY_SIZE_IN_BITS) + .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) + .build()); + key = generator.generateKey(); + + sharedPreferences.edit() + .putInt(SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED, Build.VERSION.SDK_INT) + .apply(); + } } } else { - final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); - final String wrappedAesKeyString = sharedPreferences.getString(AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE, null); - if (wrappedAesKeyString != null && keyStore.containsAlias(RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS)) { - Log.i(TAG, "RSA + wrapped AES local protection keys found in keystore"); - final PrivateKey privateKey = (PrivateKey) keyStore.getKey(RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS, null); - final byte[] wrappedAesKey = Base64.decode(wrappedAesKeyString, 0); - final Cipher cipher = Cipher.getInstance(RSA_WRAP_CIPHER_TYPE); - cipher.init(Cipher.UNWRAP_MODE, privateKey); - sLocalProtectionKey = (SecretKey) cipher.unwrap(wrappedAesKey, "AES", Cipher.SECRET_KEY); - } else { + key = readKeyApiL(sharedPreferences, keyStore); + + if (key == null) { Log.i(TAG, "Generating RSA key pair with keystore"); final KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEY_STORE_PROVIDER); final Calendar start = Calendar.getInstance(); @@ -159,22 +168,48 @@ private static synchronized SecretKey getAesGcmLocalProtectionKey(Context contex final byte[] aesKeyRaw = new byte[AES_GCM_KEY_SIZE_IN_BITS / Byte.SIZE]; getPrng().nextBytes(aesKeyRaw); - sLocalProtectionKey = new SecretKeySpec(aesKeyRaw, "AES"); + key = new SecretKeySpec(aesKeyRaw, "AES"); final Cipher cipher = Cipher.getInstance(RSA_WRAP_CIPHER_TYPE); cipher.init(Cipher.WRAP_MODE, keyPair.getPublic()); - byte[] wrappedAesKey = cipher.wrap(sLocalProtectionKey); + byte[] wrappedAesKey = cipher.wrap(key); - final SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit(); - editor.putString(AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE, Base64.encodeToString(wrappedAesKey, 0)); - editor.apply(); + sharedPreferences.edit() + .putString(AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE, Base64.encodeToString(wrappedAesKey, 0)) + .putInt(SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED, Build.VERSION.SDK_INT) + .apply(); } } + + sSecretKeyAndVersion = new SecretKeyAndVersion(key, androidVersion); } - return sLocalProtectionKey; + return sSecretKeyAndVersion; } + /** + * Read the key, which may have been stored when the OS was < M + * + * @param sharedPreferences shared pref + * @param keyStore key store + * @return the key if it exists or null + */ + @Nullable + private static SecretKey readKeyApiL(SharedPreferences sharedPreferences, KeyStore keyStore) + throws KeyStoreException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, UnrecoverableKeyException { + final String wrappedAesKeyString = sharedPreferences.getString(AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE, null); + if (wrappedAesKeyString != null && keyStore.containsAlias(RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS)) { + Log.i(TAG, "RSA + wrapped AES local protection keys found in keystore"); + final PrivateKey privateKey = (PrivateKey) keyStore.getKey(RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS, null); + final byte[] wrappedAesKey = Base64.decode(wrappedAesKeyString, 0); + final Cipher cipher = Cipher.getInstance(RSA_WRAP_CIPHER_TYPE); + cipher.init(Cipher.UNWRAP_MODE, privateKey); + return (SecretKey) cipher.unwrap(wrappedAesKey, "AES", Cipher.SECRET_KEY); + } + + // Key does not exist + return null; + } /** * Returns the unique SecureRandom instance shared for all local storage encryption operations. @@ -192,7 +227,7 @@ private static SecureRandom getPrng() { * Before Kitkat, this method will return out as local storage encryption is not implemented for * devices before KitKat. * - * @param out the output stream + * @param out the output stream * @param context the context holding the application shared preferences */ @Nullable @@ -205,21 +240,21 @@ public static OutputStream createCipherOutputStream(OutputStream out, Context co return out; } - final SecretKey key = getAesGcmLocalProtectionKey(context); - if (key == null) { + final SecretKeyAndVersion keyAndVersion = getAesGcmLocalProtectionKey(context); + if (keyAndVersion == null || keyAndVersion.getLocalProtectionKey() == null) { throw new KeyStoreException(); } final Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE); - byte[] iv = null; + byte[] iv; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - cipher.init(Cipher.ENCRYPT_MODE, key); + if (keyAndVersion.getAndroidVersion() >= Build.VERSION_CODES.M) { + cipher.init(Cipher.ENCRYPT_MODE, keyAndVersion.getLocalProtectionKey()); iv = cipher.getIV(); } else { iv = new byte[AES_GCM_IV_LENGTH]; getPrng().nextBytes(iv); - cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); + cipher.init(Cipher.ENCRYPT_MODE, keyAndVersion.getLocalProtectionKey(), new IvParameterSpec(iv)); } if (iv.length != AES_GCM_IV_LENGTH) { @@ -238,7 +273,7 @@ public static OutputStream createCipherOutputStream(OutputStream out, Context co * Before Kitkat, this method will return in as local storage encryption is not implemented * for devices before KitKat. * - * @param in the output stream + * @param in the output stream * @param context the context holding the application shared preferences */ @Nullable @@ -263,20 +298,20 @@ public static InputStream createCipherInputStream(InputStream in, Context contex final Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE); - final SecretKey key = getAesGcmLocalProtectionKey(context); - if (key == null) { + final SecretKeyAndVersion keyAndVersion = getAesGcmLocalProtectionKey(context); + if (keyAndVersion == null || keyAndVersion.getLocalProtectionKey() == null) { throw new KeyStoreException(); } - AlgorithmParameterSpec spec = null; + AlgorithmParameterSpec spec; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (keyAndVersion.getAndroidVersion() >= Build.VERSION_CODES.M) { spec = new GCMParameterSpec(AES_GCM_KEY_SIZE_IN_BITS, iv); } else { spec = new IvParameterSpec(iv); } - cipher.init(Cipher.DECRYPT_MODE, key, spec); + cipher.init(Cipher.DECRYPT_MODE, keyAndVersion.getLocalProtectionKey(), spec); return new CipherInputStream(in, cipher); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/SecretKeyAndVersion.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/SecretKeyAndVersion.java new file mode 100644 index 000000000..6d64dd425 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/SecretKeyAndVersion.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.util; + +import javax.crypto.SecretKey; + +public class SecretKeyAndVersion { + // The key + private final SecretKey localProtectionKey; + + // the android version when the key has been generated + private final int androidVersion; + + public SecretKeyAndVersion(SecretKey localProtectionKey, int androidVersion) { + this.localProtectionKey = localProtectionKey; + this.androidVersion = androidVersion; + } + + public SecretKey getLocalProtectionKey() { + return localProtectionKey; + } + + public int getAndroidVersion() { + return androidVersion; + } +} From 6954d67c897317db3f27eb110f3475ed0711f42d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 19 Sep 2018 10:04:04 +0200 Subject: [PATCH 028/236] read() will only read 1 byte --- .../src/main/java/org/matrix/androidsdk/util/CompatUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java index 53d912a78..63daf56d5 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java @@ -285,7 +285,7 @@ public static InputStream createCipherInputStream(InputStream in, Context contex return in; } - in.mark(4 + AES_GCM_IV_LENGTH); + in.mark(1 + AES_GCM_IV_LENGTH); final int iv_len = in.read(); if (iv_len != AES_GCM_IV_LENGTH) { Log.e(TAG, "Invalid IV length " + iv_len); From 6b406dbca5ed6aec6c39f22e5d2af83c3037b85e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 19 Sep 2018 10:14:41 +0200 Subject: [PATCH 029/236] FileInputStream does not support mark. Close and reopen the stream when the file is not encrypted. --- .../data/cryptostore/MXFileCryptoStore.java | 17 ++++++++--------- .../androidsdk/data/store/MXFileStore.java | 17 ++++++++--------- .../org/matrix/androidsdk/util/CompatUtil.java | 11 +++++------ 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java index a46bc71bf..0de50da72 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java @@ -1136,19 +1136,18 @@ private Object loadObject(File file, String description) { InputStream cis; if (mEnableFileEncryption) { cis = CompatUtil.createCipherInputStream(fis, mContext); - } else { - cis = fis; - } - GZIPInputStream gz; - if (cis != null) { - gz = new GZIPInputStream(cis); + if (cis == null) { + // fallback to unencrypted stream for backward compatibility + Log.i(LOG_TAG, "## loadObject() : failed to read encrypted, fallback to unencrypted read"); + fis.close(); + cis = new FileInputStream(file); + } } else { - //fallback to unencrypted stream for backward compatibility - Log.i(LOG_TAG, "## loadObject() : failed to read encrypted, fallback to unencrypted read"); - gz = new GZIPInputStream(fis); + cis = fis; } + GZIPInputStream gz = new GZIPInputStream(cis); ObjectInputStream ois = new ObjectInputStream(gz); object = ois.readObject(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java index b59e90cb0..49ce8b4e9 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java @@ -2361,19 +2361,18 @@ private Object readObject(String description, File file) { InputStream cis; if (mEnableFileEncryption) { cis = CompatUtil.createCipherInputStream(fis, mContext); - } else { - cis = fis; - } - GZIPInputStream gz; - if (cis != null) { - gz = new GZIPInputStream(cis); + if (cis == null) { + // fallback to unencrypted stream for backward compatibility + Log.i(LOG_TAG, "## readObject() : failed to read encrypted, fallback to unencrypted read"); + fis.close(); + cis = new FileInputStream(file); + } } else { - //fallback to unencrypted stream for backward compatibility - Log.i(LOG_TAG, "## readObject() : failed to read encrypted, fallback to unencrypted read"); - gz = new GZIPInputStream(fis); + cis = fis; } + GZIPInputStream gz = new GZIPInputStream(cis); ObjectInputStream ois = new ObjectInputStream(gz); object = ois.readObject(); ois.close(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java index 63daf56d5..3728dc261 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java @@ -270,11 +270,12 @@ public static OutputStream createCipherOutputStream(OutputStream out, Context co /** * Create a CipherInputStream instance. - * Before Kitkat, this method will return in as local storage encryption is not implemented - * for devices before KitKat. + * Before Kitkat, this method will return `in` because local storage encryption is not implemented for devices before KitKat. + * Warning, if `in` is not an encrypted stream, it's up to the caller to close and reopen `in`, because the stream has been read. * - * @param in the output stream + * @param in the input stream * @param context the context holding the application shared preferences + * @return in, or the created InputStream, or null if the InputStream `in` does not contain encrypted data */ @Nullable public static InputStream createCipherInputStream(InputStream in, Context context) @@ -285,15 +286,13 @@ public static InputStream createCipherInputStream(InputStream in, Context contex return in; } - in.mark(1 + AES_GCM_IV_LENGTH); final int iv_len = in.read(); if (iv_len != AES_GCM_IV_LENGTH) { Log.e(TAG, "Invalid IV length " + iv_len); - in.reset(); return null; } - final byte[] iv = new byte[iv_len]; + final byte[] iv = new byte[AES_GCM_IV_LENGTH]; in.read(iv); final Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE); From 983a28822d86f72dc0c7401d3e6063cbd1ca83ab Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 19 Sep 2018 10:28:12 +0200 Subject: [PATCH 030/236] Add a parameter for easier usage of the builder --- matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index b64fc8dff..5425ea64d 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -2479,8 +2479,8 @@ public Builder(HomeServerConnectionConfig hsConfig, MXDataHandler dataHandler, C mxSession = new MXSession(hsConfig, dataHandler, context); } - public Builder withFileEncryption() { - mxSession.mEnableFileEncryption = true; + public Builder withFileEncryption(boolean enableFileEncryption) { + mxSession.mEnableFileEncryption = enableFileEncryption; return this; } From 5f0c67896758fb77ccf5d0e6b88a4fafccb54bf4 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 19 Sep 2018 14:56:25 +0200 Subject: [PATCH 031/236] Clean code after benoit's review --- .../matrix/androidsdk/data/DataRetriever.java | 31 ++++++++++++------- .../matrix/androidsdk/rest/model/Event.java | 1 - .../rest/model/RoomPinnedEventsContent.java | 1 + .../model/ServerNoticeUsageLimitContent.java | 7 +++++ .../org/matrix/androidsdk/util/JsonUtils.java | 2 -- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java index 27f516f25..69bc438bb 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java @@ -48,7 +48,7 @@ public RoomsRestClient getRoomsRestClient() { return mRestClient; } - public void setRoomsRestClient(RoomsRestClient client) { + public void setRoomsRestClient(final RoomsRestClient client) { mRestClient = client; } @@ -59,7 +59,7 @@ public void setRoomsRestClient(RoomsRestClient client) { * @param roomId the roomId * @return the events list, null if the room does not exist */ - public Collection getCachedRoomMessages(IMXStore store, final String roomId) { + public Collection getCachedRoomMessages(final IMXStore store, final String roomId) { return store.getRoomMessages(roomId); } @@ -68,7 +68,7 @@ public Collection getCachedRoomMessages(IMXStore store, final String room * * @param roomId the room id. */ - public void cancelHistoryRequest(String roomId) { + public void cancelHistoryRequest(final String roomId) { Log.d(LOG_TAG, "## cancelHistoryRequest() : roomId " + roomId); clearPendingToken(mPendingForwardRequestTokenByRoomId, roomId); @@ -80,7 +80,7 @@ public void cancelHistoryRequest(String roomId) { * * @param roomId the room id. */ - public void cancelRemoteHistoryRequest(String roomId) { + public void cancelRemoteHistoryRequest(final String roomId) { Log.d(LOG_TAG, "## cancelRemoteHistoryRequest() : roomId " + roomId); clearPendingToken(mPendingRemoteRequestTokenByRoomId, roomId); @@ -113,8 +113,11 @@ public void getEvent(final IMXStore store, final String roomId, final String eve * @param limit the maximum number of messages to retrieve * @param callback the callback */ - public void backPaginate(final IMXStore store, final String roomId, final String token, - final int limit, final ApiCallback> callback) { + public void backPaginate(final IMXStore store, + final String roomId, + final String token, + final int limit, + final ApiCallback> callback) { // reach the marker end if (TextUtils.equals(token, Event.PAGINATE_BACK_TOKEN_END)) { // nothing more to provide @@ -264,8 +267,10 @@ public void onUnexpectedError(Exception e) { * @param token the start token. * @param callback the callback */ - private void forwardPaginate(final IMXStore store, final String roomId, - final String token, final ApiCallback> callback) { + private void forwardPaginate(final IMXStore store, + final String roomId, + final String token, + final ApiCallback> callback) { putPendingToken(mPendingForwardRequestTokenByRoomId, roomId, token); mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.FORWARDS, RoomsRestClient.DEFAULT_MESSAGES_PAGINATION_LIMIT, @@ -290,7 +295,9 @@ public void onSuccess(TokensChunkResponse events) { * @param direction the pagination direction * @param callback the onComplete callback */ - public void paginate(final IMXStore store, final String roomId, final String token, + public void paginate(final IMXStore store, + final String roomId, + final String token, final EventTimeline.Direction direction, final ApiCallback> callback) { if (direction == EventTimeline.Direction.BACKWARDS) { @@ -343,7 +350,7 @@ public void onSuccess(TokensChunkResponse info) { * @param dict the token cache * @param roomId the room id */ - private void clearPendingToken(Map dict, String roomId) { + private void clearPendingToken(final Map dict, final String roomId) { Log.d(LOG_TAG, "## clearPendingToken() : roomId " + roomId); if (null != roomId) { @@ -360,7 +367,7 @@ private void clearPendingToken(Map dict, String roomId) { * @param roomId the room Id * @return the token */ - private String getPendingToken(Map dict, String roomId) { + private String getPendingToken(final Map dict, final String roomId) { String expectedToken = "Not a valid token"; synchronized (dict) { @@ -385,7 +392,7 @@ private String getPendingToken(Map dict, String roomId) { * @param roomId the room id * @param token the token */ - private void putPendingToken(Map dict, String roomId, String token) { + private void putPendingToken(final Map dict, final String roomId, final String token) { Log.d(LOG_TAG, "## putPendingToken() : roomId " + roomId + " token " + token); synchronized (dict) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java index 7f5b0d837..2d7b828f7 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java @@ -93,7 +93,6 @@ public enum SentState { public static final String EVENT_TYPE_ROOM_KEY_REQUEST = "m.room_key_request"; public static final String EVENT_TYPE_FORWARDED_ROOM_KEY = "m.forwarded_room_key"; public static final String EVENT_TYPE_URL_PREVIEW = "org.matrix.room.preview_urls"; - public static final String EVENT_TYPE_SERVER_NOTICE_USAGE_LIMIT = "m.server_notice.usage_limit_reached"; // State events public static final String EVENT_TYPE_STATE_ROOM_NAME = "m.room.name"; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomPinnedEventsContent.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomPinnedEventsContent.java index 2dc96b5aa..33413eabe 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomPinnedEventsContent.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomPinnedEventsContent.java @@ -24,6 +24,7 @@ */ public class RoomPinnedEventsContent implements Serializable { + // List of eventIds of pinned events public List pinned; public RoomPinnedEventsContent deepCopy() { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ServerNoticeUsageLimitContent.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ServerNoticeUsageLimitContent.java index 0add6bc83..dcabd74fe 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ServerNoticeUsageLimitContent.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ServerNoticeUsageLimitContent.java @@ -23,10 +23,17 @@ */ public class ServerNoticeUsageLimitContent { + private static final String EVENT_TYPE_SERVER_NOTICE_USAGE_LIMIT = "m.server_notice.usage_limit_reached"; + + // The kind of user limit, generally is monthly_active_user public String limit; @SerializedName("admin_contact") public String adminUri; @SerializedName("server_notice_type") public String type; + public boolean isServerNoticeUsageLimit() { + return EVENT_TYPE_SERVER_NOTICE_USAGE_LIMIT.equals(type); + } + } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java index cbc917cb0..e2e32c9ca 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java @@ -490,8 +490,6 @@ public static RoomPinnedEventsContent toRoomPinnedEventsContent(final JsonElemen return toClass(jsonElement, RoomPinnedEventsContent.class); } - - /** * Convert a JSON object into a class instance. * The returned value cannot be null. From e7174b89a17cf18a9d6431f5f6162c62271c236e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Sep 2018 12:11:38 +0200 Subject: [PATCH 032/236] Avoid creating instances of Gson #1 --- .../org/matrix/androidsdk/MXDataHandler.java | 6 +----- .../rest/json/ConditionDeserializerTest.java | 17 +++++------------ 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 90dd94962..8f7ba5913 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -1033,11 +1033,7 @@ private void managePushRulesUpdate(List> events) { if (TextUtils.equals(type, "m.push_rules")) { if (event.containsKey("content")) { - Gson gson = new GsonBuilder() - .setFieldNamingStrategy(new JsonUtils.MatrixFieldNamingStrategy()) - .excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.STATIC) - .registerTypeAdapter(Condition.class, new ConditionDeserializer()) - .create(); + Gson gson = JsonUtils.getGson(false); // convert the data to PushRulesResponse // because BingRulesManager supports only PushRulesResponse diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/rest/json/ConditionDeserializerTest.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/rest/json/ConditionDeserializerTest.java index 77fe806c3..856a5621d 100644 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/rest/json/ConditionDeserializerTest.java +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/rest/json/ConditionDeserializerTest.java @@ -1,13 +1,13 @@ -/* +/* * Copyright 2014 OpenMarket Ltd * Copyright 2017 Vector Creations Ltd - * + * * 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. @@ -17,7 +17,6 @@ package org.matrix.androidsdk.rest.json; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import org.junit.Assert; import org.junit.Test; @@ -30,8 +29,6 @@ import org.matrix.androidsdk.util.JsonUtils; import org.robolectric.RobolectricTestRunner; -import java.lang.reflect.Modifier; - /** * Class for unit testing the ConditionDeserializer. */ @@ -39,11 +36,7 @@ @RunWith(RobolectricTestRunner.class) public class ConditionDeserializerTest { - private Gson gson = new GsonBuilder() - .setFieldNamingStrategy(new JsonUtils.MatrixFieldNamingStrategy()) - .excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.STATIC) - .registerTypeAdapter(Condition.class, new ConditionDeserializer()) - .create(); + private Gson gson = JsonUtils.getGson(false); @Test public void testEventMatchCondition() { From fb13cf1a2791be882639d2ca5a3aa210175f8a7c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Sep 2018 12:21:50 +0200 Subject: [PATCH 033/236] Avoid creating instances of Gson #3 --- .../java/org/matrix/androidsdk/data/Room.java | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index eb53d5f22..8b018fcfd 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -34,7 +34,6 @@ import android.util.Pair; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; @@ -126,9 +125,6 @@ public class Room { // initial sync callback. private ApiCallback mOnInitialSyncCallback; - // gson parser - private final Gson gson = new GsonBuilder().create(); - // This is used to block live events and history requests until the state is fully processed and ready private boolean mIsReady = false; @@ -549,7 +545,6 @@ public boolean isInvited() { } /** - * * @param membership is the string representing one of the membership state * @return true if the user membership is equals to the membership param */ @@ -1196,6 +1191,29 @@ public boolean handleReceiptData(ReceiptData receiptData) { /** * Handle receipt event. + * Event content will contains the receipts dictionaries + *
+     * key   : $EventId
+     * value : dict key $UserId
+     *              value dict key ts
+     *                    dict value ts value
+     * 
+ *

+ * Example: + *

+     * {
+     *     "$1535657109773196ZjoWE:matrix.org": {
+     *         "m.read": {
+     *             "@slash_benoit:matrix.org": {
+     *                 "ts": 1535708570621
+     *             },
+     *             "@benoit.marty:matrix.org": {
+     *                 "ts": 1535657109472
+     *             }
+     *         }
+     *     }
+     * },
+     * 
* * @param event the event receipts. * @return the sender user IDs list. @@ -1204,14 +1222,9 @@ private List handleReceiptEvent(Event event) { List senderIDs = new ArrayList<>(); try { - // the receipts dictionnaries - // key : $EventId - // value : dict key $UserId - // value dict key ts - // dict value ts value Type type = new TypeToken>>>>() { }.getType(); - Map>>> receiptsDict = gson.fromJson(event.getContent(), type); + Map>>> receiptsDict = JsonUtils.getGson(false).fromJson(event.getContent(), type); for (String eventId : receiptsDict.keySet()) { Map>> receiptDict = receiptsDict.get(eventId); From 3eef5e967078c6efd14b3fa768d52d6ca2fcc311 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Sep 2018 12:40:08 +0200 Subject: [PATCH 034/236] Improve comparator --- .../androidsdk/comparators/Comparators.java | 40 +++++++++++++++++++ .../java/org/matrix/androidsdk/data/Room.java | 4 +- .../androidsdk/data/store/MXMemoryStore.java | 4 +- .../androidsdk/interfaces/DatedObject.java | 25 ++++++++++++ .../androidsdk/rest/model/ReceiptData.java | 32 +++++---------- 5 files changed, 80 insertions(+), 25 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/comparators/Comparators.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/interfaces/DatedObject.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/comparators/Comparators.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/comparators/Comparators.java new file mode 100644 index 000000000..163fa4c2d --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/comparators/Comparators.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.comparators; + +import org.matrix.androidsdk.interfaces.DatedObject; + +import java.util.Comparator; + +public class Comparators { + + // comparator to sort from the oldest to the latest. + public static final Comparator ascComparator = new Comparator() { + @Override + public int compare(DatedObject datedObject1, DatedObject datedObject2) { + return (int) (datedObject1.getDate() - datedObject2.getDate()); + } + }; + + // comparator to sort from the latest to the oldest. + public static final Comparator descComparator = new Comparator() { + @Override + public int compare(DatedObject datedObject1, DatedObject datedObject2) { + return (int) (datedObject2.getDate() - datedObject1.getDate()); + } + }; +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 8b018fcfd..b186949d2 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -1194,8 +1194,8 @@ public boolean handleReceiptData(ReceiptData receiptData) { * Event content will contains the receipts dictionaries *
      * key   : $EventId
-     * value : dict key $UserId
-     *              value dict key ts
+     * value : dict key @UserId
+     *              value dict key "ts"
      *                    dict value ts value
      * 
*

diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java index 0bd18bbd0..24d42aca0 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java @@ -24,13 +24,13 @@ import android.support.annotation.Nullable; import android.text.TextUtils; +import org.matrix.androidsdk.comparators.Comparators; import org.matrix.androidsdk.data.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomAccountData; import org.matrix.androidsdk.data.RoomSummary; import org.matrix.androidsdk.data.metrics.MetricsListener; import org.matrix.androidsdk.rest.callback.ApiCallback; -import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.ReceiptData; import org.matrix.androidsdk.rest.model.RoomMember; @@ -1174,7 +1174,7 @@ public List getEventReceipts(String roomId, String eventId, boolean } if (sort && (receipts.size() > 0)) { - Collections.sort(receipts, ReceiptData.descComparator); + Collections.sort(receipts, Comparators.descComparator); } return receipts; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/interfaces/DatedObject.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/interfaces/DatedObject.java new file mode 100644 index 000000000..4b594397c --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/interfaces/DatedObject.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.interfaces; + +/** + * Can be implemented by any object containing a timestamp. + * This interface can be use to sort such object + */ +public interface DatedObject { + long getDate(); +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ReceiptData.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ReceiptData.java index 0e8ae84dc..d5ea7de5a 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ReceiptData.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ReceiptData.java @@ -1,12 +1,13 @@ -/* +/* * Copyright 2014 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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. @@ -15,9 +16,9 @@ */ package org.matrix.androidsdk.rest.model; -import java.util.Comparator; +import org.matrix.androidsdk.interfaces.DatedObject; -public class ReceiptData implements java.io.Serializable { +public class ReceiptData implements java.io.Serializable, DatedObject { // the user id public String userId; @@ -34,19 +35,8 @@ public ReceiptData(String anUserId, String anEventId, long aTs) { originServerTs = aTs; } - // comparator to sort from the oldest to the latest. - public static final Comparator ascComparator = new Comparator() { - @Override - public int compare(ReceiptData receipt1, ReceiptData receipt2) { - return (int) (receipt1.originServerTs - receipt2.originServerTs); - } - }; - - // comparator to sort from the latest to the oldest. - public static final Comparator descComparator = new Comparator() { - @Override - public int compare(ReceiptData receipt1, ReceiptData receipt2) { - return (int) (receipt2.originServerTs - receipt1.originServerTs); - } - }; + @Override + public long getDate() { + return originServerTs; + } } \ No newline at end of file From 15551f99e2f42138c2771703144fd689efead49b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Sep 2018 13:53:58 +0200 Subject: [PATCH 035/236] Improve comparator --- .../rest/model/sync/DeviceInfo.java | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/DeviceInfo.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/DeviceInfo.java index 52a3792c0..73106d1df 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/DeviceInfo.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/DeviceInfo.java @@ -1,13 +1,14 @@ -/* +/* * Copyright 2014 OpenMarket Ltd * Copyright 2017 Vector Creations Ltd + * Copyright 2018 New Vector Ltd * * 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. @@ -16,14 +17,16 @@ */ package org.matrix.androidsdk.rest.model.sync; +import org.matrix.androidsdk.comparators.Comparators; +import org.matrix.androidsdk.interfaces.DatedObject; + import java.util.Collections; -import java.util.Comparator; import java.util.List; /** * This class describes the device information */ -public class DeviceInfo { +public class DeviceInfo implements DatedObject { /** * The owner user id */ @@ -49,24 +52,19 @@ public class DeviceInfo { */ public String last_seen_ip; + @Override + public long getDate() { + return last_seen_ts; + } + /** * Sort a devices list by their presences from the most recent to the oldest one. * * @param deviceInfos the deviceinfo list */ public static void sortByLastSeen(List deviceInfos) { - if (null != deviceInfos) - Collections.sort(deviceInfos, new Comparator() { - @Override - public int compare(DeviceInfo lhs, DeviceInfo rhs) { - if (lhs.last_seen_ts == rhs.last_seen_ts) { - return 0; - } else if (lhs.last_seen_ts > rhs.last_seen_ts) { - return -1; - } else { - return +1; - } - } - }); + if (null != deviceInfos) { + Collections.sort(deviceInfos, Comparators.descComparator); + } } } From 7f8ce71728b7d6f611fb10de95df142a00de74ae Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Sep 2018 13:55:04 +0200 Subject: [PATCH 036/236] Move class --- .../{comparators => data/comparator}/Comparators.java | 2 +- .../java/org/matrix/androidsdk/data/store/MXMemoryStore.java | 2 +- .../java/org/matrix/androidsdk/rest/model/sync/DeviceInfo.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename matrix-sdk/src/main/java/org/matrix/androidsdk/{comparators => data/comparator}/Comparators.java (96%) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/comparators/Comparators.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/comparator/Comparators.java similarity index 96% rename from matrix-sdk/src/main/java/org/matrix/androidsdk/comparators/Comparators.java rename to matrix-sdk/src/main/java/org/matrix/androidsdk/data/comparator/Comparators.java index 163fa4c2d..19c306c14 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/comparators/Comparators.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/comparator/Comparators.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.androidsdk.comparators; +package org.matrix.androidsdk.data.comparator; import org.matrix.androidsdk.interfaces.DatedObject; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java index 24d42aca0..7bd112c61 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java @@ -24,11 +24,11 @@ import android.support.annotation.Nullable; import android.text.TextUtils; -import org.matrix.androidsdk.comparators.Comparators; import org.matrix.androidsdk.data.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomAccountData; import org.matrix.androidsdk.data.RoomSummary; +import org.matrix.androidsdk.data.comparator.Comparators; import org.matrix.androidsdk.data.metrics.MetricsListener; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.model.Event; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/DeviceInfo.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/DeviceInfo.java index 73106d1df..f0eab03ad 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/DeviceInfo.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/DeviceInfo.java @@ -17,7 +17,7 @@ */ package org.matrix.androidsdk.rest.model.sync; -import org.matrix.androidsdk.comparators.Comparators; +import org.matrix.androidsdk.data.comparator.Comparators; import org.matrix.androidsdk.interfaces.DatedObject; import java.util.Collections; From 34452bf734ddc1ba29b0dee14daf6f235718a84a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Sep 2018 14:13:26 +0200 Subject: [PATCH 037/236] Split long line --- .../main/java/org/matrix/androidsdk/data/DataRetriever.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java index 69bc438bb..47589d908 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java @@ -217,7 +217,10 @@ public void onSuccess(TokensChunkResponse events) { } private void logErrorMessage(String expectedToken, String errorMessage) { - Log.e(LOG_TAG, "## backPaginate() failed : roomId " + roomId + " token " + token + " expected " + expectedToken + " with " + errorMessage); + Log.e(LOG_TAG, "## backPaginate() failed : roomId " + roomId + + " token " + token + + " expected " + expectedToken + + " with " + errorMessage); } @Override From b7a2f8f9fbb724b77804cb4c527620aec212758d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Sep 2018 14:54:43 +0200 Subject: [PATCH 038/236] Move MatrixFieldNamingStrategy to its own class --- .../rest/json/MatrixFieldNamingStrategy.java | 58 +++++++++++++++++++ .../org/matrix/androidsdk/util/JsonUtils.java | 40 +------------ 2 files changed, 59 insertions(+), 39 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/json/MatrixFieldNamingStrategy.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/json/MatrixFieldNamingStrategy.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/json/MatrixFieldNamingStrategy.java new file mode 100644 index 000000000..b2d48832d --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/json/MatrixFieldNamingStrategy.java @@ -0,0 +1,58 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.json; + +import com.google.gson.FieldNamingStrategy; + +import java.lang.reflect.Field; +import java.util.Locale; + +/** + * Based on FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES. + * toLowerCase() is replaced by toLowerCase(Locale.ENGLISH). + * In some languages like turkish, toLowerCase does not provide the expected string. + * e.g _I is not converted to _i. + */ +public class MatrixFieldNamingStrategy implements FieldNamingStrategy { + + /** + * Converts the field name that uses camel-case define word separation into + * separate words that are separated by the provided {@code separatorString}. + */ + private static String separateCamelCase(String name, String separator) { + StringBuilder translation = new StringBuilder(); + for (int i = 0; i < name.length(); i++) { + char character = name.charAt(i); + if (Character.isUpperCase(character) && translation.length() != 0) { + translation.append(separator); + } + translation.append(character); + } + return translation.toString(); + } + + /** + * Translates the field name into its JSON field name representation. + * + * @param f the field object that we are translating + * @return the translated field name. + * @since 1.3 + */ + public String translateName(Field f) { + return separateCamelCase(f.getName(), "_").toLowerCase(Locale.ENGLISH); + } +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java index e2e32c9ca..bde361750 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java @@ -20,7 +20,6 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.google.gson.FieldNamingStrategy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; @@ -29,6 +28,7 @@ import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.rest.json.ConditionDeserializer; +import org.matrix.androidsdk.rest.json.MatrixFieldNamingStrategy; import org.matrix.androidsdk.rest.model.ContentResponse; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.EventContent; @@ -59,9 +59,7 @@ import org.matrix.androidsdk.rest.model.pid.RoomThirdPartyInvite; import java.lang.reflect.Constructor; -import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.util.Locale; import java.util.Map; import java.util.TreeSet; @@ -71,42 +69,6 @@ public class JsonUtils { private static final String LOG_TAG = JsonUtils.class.getSimpleName(); - /** - * Based on FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES. - * toLowerCase() is replaced by toLowerCase(Locale.ENGLISH). - * In some languages like turkish, toLowerCase does not provide the expected string. - * e.g _I is not converted to _i. - */ - public static class MatrixFieldNamingStrategy implements FieldNamingStrategy { - - /** - * Converts the field name that uses camel-case define word separation into - * separate words that are separated by the provided {@code separatorString}. - */ - private static String separateCamelCase(String name, String separator) { - StringBuilder translation = new StringBuilder(); - for (int i = 0; i < name.length(); i++) { - char character = name.charAt(i); - if (Character.isUpperCase(character) && translation.length() != 0) { - translation.append(separator); - } - translation.append(character); - } - return translation.toString(); - } - - /** - * Translates the field name into its JSON field name representation. - * - * @param f the field object that we are translating - * @return the translated field name. - * @since 1.3 - */ - public String translateName(Field f) { - return separateCamelCase(f.getName(), "_").toLowerCase(Locale.ENGLISH); - } - } - private static final Gson gson = new GsonBuilder() .setFieldNamingStrategy(new MatrixFieldNamingStrategy()) .excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.STATIC) From 63bacdb83bb755a726af771dbe76f10deff21a81 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Sep 2018 16:13:01 +0200 Subject: [PATCH 039/236] Rename variable to improve code clarity --- .../matrix/androidsdk/util/CompatUtil.java | 21 +++++------ .../androidsdk/util/SecretKeyAndVersion.java | 35 ++++++++++++++----- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java index 3728dc261..7cacb994d 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java @@ -98,7 +98,6 @@ public static GZIPOutputStream createGzipOutputStream(OutputStream outputStream) * From Marshmallow, this key is generated and operated directly from the android keystore. * From KitKat and before Marshmallow, this key is stored in the application shared preferences * wrapped by a RSA key generated and operated directly from the android keystore. - * Before Kitkat, this param does not exist and after Kitkat it is set to false by default. * * @param context the context holding the application shared preferences */ @@ -116,7 +115,9 @@ private static synchronized SecretKeyAndVersion getAesGcmLocalProtectionKey(Cont SecretKey key; final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); - final int androidVersion = sharedPreferences.getInt(SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED, Build.VERSION.SDK_INT); + // Get the version of Android when the key has been generated, default to the current version of the system. In this case, the + // key will be generated + final int androidVersionWhenTheKeyHasBeenGenerated = sharedPreferences.getInt(SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED, Build.VERSION.SDK_INT); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (keyStore.containsAlias(AES_LOCAL_PROTECTION_KEY_ALIAS)) { @@ -181,7 +182,7 @@ private static synchronized SecretKeyAndVersion getAesGcmLocalProtectionKey(Cont } } - sSecretKeyAndVersion = new SecretKeyAndVersion(key, androidVersion); + sSecretKeyAndVersion = new SecretKeyAndVersion(key, androidVersionWhenTheKeyHasBeenGenerated); } return sSecretKeyAndVersion; @@ -241,20 +242,20 @@ public static OutputStream createCipherOutputStream(OutputStream out, Context co } final SecretKeyAndVersion keyAndVersion = getAesGcmLocalProtectionKey(context); - if (keyAndVersion == null || keyAndVersion.getLocalProtectionKey() == null) { + if (keyAndVersion == null || keyAndVersion.getSecretKey() == null) { throw new KeyStoreException(); } final Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE); byte[] iv; - if (keyAndVersion.getAndroidVersion() >= Build.VERSION_CODES.M) { - cipher.init(Cipher.ENCRYPT_MODE, keyAndVersion.getLocalProtectionKey()); + if (keyAndVersion.getAndroidVersionWhenTheKeyHasBeenGenerated() >= Build.VERSION_CODES.M) { + cipher.init(Cipher.ENCRYPT_MODE, keyAndVersion.getSecretKey()); iv = cipher.getIV(); } else { iv = new byte[AES_GCM_IV_LENGTH]; getPrng().nextBytes(iv); - cipher.init(Cipher.ENCRYPT_MODE, keyAndVersion.getLocalProtectionKey(), new IvParameterSpec(iv)); + cipher.init(Cipher.ENCRYPT_MODE, keyAndVersion.getSecretKey(), new IvParameterSpec(iv)); } if (iv.length != AES_GCM_IV_LENGTH) { @@ -298,19 +299,19 @@ public static InputStream createCipherInputStream(InputStream in, Context contex final Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE); final SecretKeyAndVersion keyAndVersion = getAesGcmLocalProtectionKey(context); - if (keyAndVersion == null || keyAndVersion.getLocalProtectionKey() == null) { + if (keyAndVersion == null || keyAndVersion.getSecretKey() == null) { throw new KeyStoreException(); } AlgorithmParameterSpec spec; - if (keyAndVersion.getAndroidVersion() >= Build.VERSION_CODES.M) { + if (keyAndVersion.getAndroidVersionWhenTheKeyHasBeenGenerated() >= Build.VERSION_CODES.M) { spec = new GCMParameterSpec(AES_GCM_KEY_SIZE_IN_BITS, iv); } else { spec = new IvParameterSpec(iv); } - cipher.init(Cipher.DECRYPT_MODE, keyAndVersion.getLocalProtectionKey(), spec); + cipher.init(Cipher.DECRYPT_MODE, keyAndVersion.getSecretKey(), spec); return new CipherInputStream(in, cipher); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/SecretKeyAndVersion.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/SecretKeyAndVersion.java index 6d64dd425..61635a091 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/SecretKeyAndVersion.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/SecretKeyAndVersion.java @@ -18,23 +18,40 @@ import javax.crypto.SecretKey; +/** + * Tuple which contains the secret key and the version of Android when the key has been generated + */ public class SecretKeyAndVersion { // The key - private final SecretKey localProtectionKey; + private final SecretKey secretKey; // the android version when the key has been generated - private final int androidVersion; + private final int androidVersionWhenTheKeyHasBeenGenerated; - public SecretKeyAndVersion(SecretKey localProtectionKey, int androidVersion) { - this.localProtectionKey = localProtectionKey; - this.androidVersion = androidVersion; + /** + * @param secretKey the key + * @param androidVersionWhenTheKeyHasBeenGenerated the android version when the key has been generated + */ + public SecretKeyAndVersion(SecretKey secretKey, int androidVersionWhenTheKeyHasBeenGenerated) { + this.secretKey = secretKey; + this.androidVersionWhenTheKeyHasBeenGenerated = androidVersionWhenTheKeyHasBeenGenerated; } - public SecretKey getLocalProtectionKey() { - return localProtectionKey; + /** + * Get the key + * + * @return the key + */ + public SecretKey getSecretKey() { + return secretKey; } - public int getAndroidVersion() { - return androidVersion; + /** + * Get the android version when the key has been generated + * + * @return the android version when the key has been generated + */ + public int getAndroidVersionWhenTheKeyHasBeenGenerated() { + return androidVersionWhenTheKeyHasBeenGenerated; } } From fdcd3e6b69653da2f44621231ae3881ea9c5fc1a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 25 Sep 2018 09:55:43 +0200 Subject: [PATCH 040/236] Ensure Boolean can be correctly deserialised if value is integer or String --- CHANGES.rst | 2 +- .../rest/json/BooleanDeserializer.java | 96 +++++++++++++++++++ .../org/matrix/androidsdk/util/JsonUtils.java | 7 ++ 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/json/BooleanDeserializer.java diff --git a/CHANGES.rst b/CHANGES.rst index c1443f6e2..c98e3d96e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -17,7 +17,7 @@ Translations: - Others: - - + - Boolean deserialization is more permissive: "1" or 1 will be handle as a true value (#358) Build: - diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/json/BooleanDeserializer.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/json/BooleanDeserializer.java new file mode 100644 index 000000000..d4645f1b2 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/json/BooleanDeserializer.java @@ -0,0 +1,96 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.json; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; + +import org.matrix.androidsdk.util.Log; + +import java.lang.reflect.Type; + +/** + * Convenient JsonDeserializer to accept various type of Boolean + */ +public class BooleanDeserializer implements JsonDeserializer { + + private static final String LOG_TAG = BooleanDeserializer.class.getSimpleName(); + + private final boolean mCanReturnNull; + + /** + * Constructor + * + * @param canReturnNull true if the deserializer can return null in case of error + */ + public BooleanDeserializer(boolean canReturnNull) { + mCanReturnNull = canReturnNull; + } + + /** + * @param json The Json data being deserialized + * @param typeOfT The type of the Object to deserialize to + * @param context not used + * @return true if json is: true, 1, "true" or "1". false for other values. null in other cases. + * @throws JsonParseException + */ + @Override + public Boolean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + if (json.isJsonPrimitive()) { + JsonPrimitive jsonPrimitive = json.getAsJsonPrimitive(); + + if (jsonPrimitive.isBoolean()) { + // Nominal case + return jsonPrimitive.getAsBoolean(); + } else if (jsonPrimitive.isNumber()) { + Log.w(LOG_TAG, "Boolean detected as a number"); + return jsonPrimitive.getAsInt() == 1; + } else if (jsonPrimitive.isString()) { + Log.w(LOG_TAG, "Boolean detected as a string"); + + String jsonPrimitiveString = jsonPrimitive.getAsString(); + return "1".equals(jsonPrimitiveString) + || "true".equals(jsonPrimitiveString); + } else { + // Should not happen + Log.e(LOG_TAG, "Unknown primitive"); + if (mCanReturnNull) { + return null; + } else { + return false; + } + } + } else if (json.isJsonNull()) { + if (mCanReturnNull) { + return null; + } else { + Log.w(LOG_TAG, "Boolean is null, but not allowed to return null"); + return false; + } + } + + Log.w(LOG_TAG, "Boolean detected as not a primitive type"); + if (mCanReturnNull) { + return null; + } else { + return false; + } + } +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java index bde361750..d66668164 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java @@ -27,6 +27,7 @@ import com.google.gson.JsonObject; import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.rest.json.BooleanDeserializer; import org.matrix.androidsdk.rest.json.ConditionDeserializer; import org.matrix.androidsdk.rest.json.MatrixFieldNamingStrategy; import org.matrix.androidsdk.rest.model.ContentResponse; @@ -73,6 +74,8 @@ public class JsonUtils { .setFieldNamingStrategy(new MatrixFieldNamingStrategy()) .excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.STATIC) .registerTypeAdapter(Condition.class, new ConditionDeserializer()) + .registerTypeAdapter(boolean.class, new BooleanDeserializer(false)) + .registerTypeAdapter(Boolean.class, new BooleanDeserializer(true)) .create(); // add a call to serializeNulls(). @@ -83,6 +86,8 @@ public class JsonUtils { .excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.STATIC) .serializeNulls() .registerTypeAdapter(Condition.class, new ConditionDeserializer()) + .registerTypeAdapter(boolean.class, new BooleanDeserializer(false)) + .registerTypeAdapter(Boolean.class, new BooleanDeserializer(true)) .create(); // for crypto (canonicalize) @@ -92,6 +97,8 @@ public class JsonUtils { .disableHtmlEscaping() .excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.STATIC) .registerTypeAdapter(Condition.class, new ConditionDeserializer()) + .registerTypeAdapter(boolean.class, new BooleanDeserializer(false)) + .registerTypeAdapter(Boolean.class, new BooleanDeserializer(true)) .create(); /** From 874273086d9cfba643f9831f27b16549e26bce2d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 25 Sep 2018 11:50:36 +0200 Subject: [PATCH 041/236] Fix test compilation issue --- .../matrix/androidsdk/common/CommonTestHelper.java | 4 ++-- .../org/matrix/androidsdk/crypto/CryptoTest.java | 14 +++++++------- .../androidsdk/HomeServerConnectionConfig.java | 2 +- .../java/org/matrix/androidsdk/TestsHelper.java | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index d9a5dffb2..c97873c5c 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -303,7 +303,7 @@ public void onSuccess(Credentials credentials) { hs.setCredentials(credentials); - IMXStore store = new MXFileStore(hs, context); + IMXStore store = new MXFileStore(hs, false, context); MXSession mxSession = new MXSession.Builder(hs, new MXDataHandler(store, credentials), context) .build(); @@ -353,7 +353,7 @@ public void onSuccess(Credentials credentials) { hs.setCredentials(credentials); - final IMXStore store = new MXFileStore(hs, context); + final IMXStore store = new MXFileStore(hs, false, context); final MXSession mxSession = new MXSession.Builder(hs, new MXDataHandler(store, credentials), context) .build(); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 7629adcc1..e9701eabe 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -148,7 +148,7 @@ public void onSuccess(Void info) { HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(bobCredentials); - IMXStore store = new MXFileStore(hs, context); + IMXStore store = new MXFileStore(hs, false, context); MXSession bobSession2 = new MXSession.Builder(hs, new MXDataHandler(store, bobCredentials), context) .build(); @@ -316,7 +316,7 @@ public void onSuccess(Void info) { HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(bobCredentials); - IMXStore store = new MXFileStore(hs, context); + IMXStore store = new MXFileStore(hs, false, context); MXSession bobSession2 = new MXSession.Builder(hs, new MXDataHandler(store, bobCredentials), context) .build(); @@ -485,7 +485,7 @@ public void onSuccess(MXUsersDevicesMap info) { HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(bobCredentials); - IMXStore store = new MXFileStore(hs, context); + IMXStore store = new MXFileStore(hs, false, context); MXSession bobSession2 = new MXSession.Builder(hs, new MXDataHandler(store, bobCredentials), context) .build(); @@ -858,7 +858,7 @@ public void test09_testAliceInAEncryptedRoomAfterInitialSync() throws Exception HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(aliceCredentials); - IMXStore store = new MXFileStore(hs, context); + IMXStore store = new MXFileStore(hs, false, context); final CountDownLatch lock1 = new CountDownLatch(1); @@ -993,7 +993,7 @@ public void onSuccess(Void info) { HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(aliceCredentials2); - IMXStore store = new MXFileStore(hs, context); + IMXStore store = new MXFileStore(hs,false, context); MXSession aliceSession2 = new MXSession.Builder(hs, new MXDataHandler(store, aliceCredentials2), context) .build(); @@ -1082,7 +1082,7 @@ public void test11_testAliceAndBobInAEncryptedRoomBackPaginationFromMemoryStore( HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(bobCredentials); - IMXStore store = new MXFileStore(hs, context); + IMXStore store = new MXFileStore(hs, false, context); final CountDownLatch lock1 = new CountDownLatch(2); @@ -2377,7 +2377,7 @@ public void onSuccess(byte[] info) { HomeServerConnectionConfig hs = mTestHelper.createHomeServerConfig(aliceCredentials2); - IMXStore store = new MXFileStore(hs, context); + IMXStore store = new MXFileStore(hs, false, context); MXSession aliceSession2 = new MXSession.Builder(hs, new MXDataHandler(store, aliceCredentials2), context) .build(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java index 8790e06ee..abf5edef1 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java @@ -300,7 +300,7 @@ public String toString() { ", mPin=" + mPin + ", mShouldAcceptTlsExtensions=" + mShouldAcceptTlsExtensions + ", mTlsVersions=" + (null == mTlsVersions ? "" : mTlsVersions.size()) + - ", mTlsCipherSuitess=" + (null == mTlsCipherSuites ? "" : mTlsCipherSuites.size()) + + ", mTlsCipherSuites=" + (null == mTlsCipherSuites ? "" : mTlsCipherSuites.size()) + '}'; } diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestsHelper.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/TestsHelper.java index 27071894d..4bdb582f3 100644 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestsHelper.java +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/TestsHelper.java @@ -155,7 +155,7 @@ public void onUnexpectedError(Exception e) { hs.setCredentials(credentials); - IMXStore store = new MXFileStore(hs, context); + IMXStore store = new MXFileStore(hs, false, context); MXSession mxSession = new MXSession.Builder(hs, new MXDataHandler(store, credentials), context) .build(); From f643c33c04b08368f85e4b888f730840b1a36934 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 25 Sep 2018 12:01:38 +0200 Subject: [PATCH 042/236] Create a Builder for HomeServerConnectionConfig --- CHANGES.rst | 2 +- .../androidsdk/common/CommonTestHelper.java | 8 +- .../HomeServerConnectionConfig.java | 324 ++++++++++-------- .../java/org/matrix/androidsdk/MXSession.java | 6 +- .../org/matrix/androidsdk/TestsHelper.java | 4 +- 5 files changed, 194 insertions(+), 150 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 4f415e34b..e1effb0d1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -12,7 +12,7 @@ Bugfix: - Scroll to bottom no longer keeps inertia after position change (#354) API Change: - - + - A Builder has been added to create HomeServerConnectionConfig instances. Translations: - diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index c97873c5c..23a5d4b61 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -89,9 +89,11 @@ public MXSession logIntoSamAccount(final String samUserId, final boolean withIni * @return */ public HomeServerConnectionConfig createHomeServerConfig(@Nullable Credentials credentials) { - final HomeServerConnectionConfig hs = new HomeServerConnectionConfig(Uri.parse(TestConstants.TESTS_HOME_SERVER_URL)); - hs.allowHttpConnection(); - hs.setCredentials(credentials); + final HomeServerConnectionConfig hs = new HomeServerConnectionConfig.Builder() + .withHomeServerUri(Uri.parse(TestConstants.TESTS_HOME_SERVER_URL)) + .withCredentials(credentials) + .withAllowHttpConnection() + .build(); return hs; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java index abf5edef1..689995900 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java @@ -56,78 +56,15 @@ public class HomeServerConnectionConfig { // the accepted TLS cipher suites private List mTlsCipherSuites; // should accept TLS extensions - private boolean mShouldAcceptTlsExtensions; + private boolean mShouldAcceptTlsExtensions = true; // allow Http connection private boolean mAllowHttpExtension; /** - * @param hsUri The URI to use to connect to the homeserver + * Private constructor. Please use the Builder */ - public HomeServerConnectionConfig(Uri hsUri) { - this(hsUri, null); - } - - /** - * @param hsUri The URI to use to connect to the homeserver - * @param credentials The credentials to use, if needed. Can be null. - */ - public HomeServerConnectionConfig(Uri hsUri, @Nullable Credentials credentials) { - this(hsUri, null, credentials, new ArrayList(), false); - } - - /** - * @param hsUri The URI to use to connect to the homeserver - * @param identityServerUri The URI to use to manage identity - * @param credentials The credentials to use, if needed. Can be null. - * @param allowedFingerprints If using SSL, allow server certs that match these fingerprints. - * @param pin If true only allow certs matching given fingerprints, otherwise fallback to - * standard X509 checks. - */ - public HomeServerConnectionConfig(Uri hsUri, - @Nullable Uri identityServerUri, - @Nullable Credentials credentials, - List allowedFingerprints, - boolean pin) { - if (hsUri == null || (!"http".equals(hsUri.getScheme()) && !"https".equals(hsUri.getScheme()))) { - throw new RuntimeException("Invalid home server URI: " + hsUri); - } - - if ((null != identityServerUri) && (!"http".equals(hsUri.getScheme()) && !"https".equals(hsUri.getScheme()))) { - throw new RuntimeException("Invalid identity server URI: " + identityServerUri); - } - - // remove trailing / - if (hsUri.toString().endsWith("/")) { - try { - String url = hsUri.toString(); - hsUri = Uri.parse(url.substring(0, url.length() - 1)); - } catch (Exception e) { - throw new RuntimeException("Invalid home server URI: " + hsUri); - } - } - - // remove trailing / - if ((null != identityServerUri) && identityServerUri.toString().endsWith("/")) { - try { - String url = identityServerUri.toString(); - identityServerUri = Uri.parse(url.substring(0, url.length() - 1)); - } catch (Exception e) { - throw new RuntimeException("Invalid identity server URI: " + identityServerUri); - } - } - - mHsUri = hsUri; - mIdentityServerUri = identityServerUri; - mAntiVirusServerUri = null; - - if (null != allowedFingerprints) { - mAllowedFingerprints = allowedFingerprints; - } - - mPin = pin; - mCredentials = credentials; - - mShouldAcceptTlsExtensions = true; + private HomeServerConnectionConfig() { + // Private constructor } /** @@ -146,15 +83,6 @@ public Uri getHomeserverUri() { return mHsUri; } - /** - * Update the identity server uri. - * - * @param uri the new identity server uri - */ - public void setIdentityServerUri(Uri uri) { - mIdentityServerUri = uri; - } - /** * @return the identity server uri */ @@ -166,15 +94,6 @@ public Uri getIdentityServerUri() { return mHsUri; } - /** - * Update the anti-virus server URI. - * - * @param uri the new anti-virus uri - */ - public void setAntiVirusServerUri(Uri uri) { - mAntiVirusServerUri = uri; - } - /** * @return the anti-virus server uri */ @@ -217,19 +136,6 @@ public boolean shouldPin() { return mPin; } - /** - * Update the set of TLS versions accepted for TLS connections with the home server. - * - * @param tlsVersions the set of TLS versions accepted. - */ - public void setAcceptedTlsVersions(@Nullable List tlsVersions) { - if (tlsVersions == null) { - mTlsVersions = null; - } else { - mTlsVersions = Collections.unmodifiableList(tlsVersions); - } - } - /** * TLS versions accepted for TLS connections with the home server. */ @@ -238,19 +144,6 @@ public List getAcceptedTlsVersions() { return mTlsVersions; } - /** - * Update the set of TLS cipher suites accepted for TLS connections with the home server. - * - * @param tlsCipherSuites the set of TLS cipher suites accepted. - */ - public void setAcceptedTlsCipherSuites(@Nullable List tlsCipherSuites) { - if (tlsCipherSuites == null) { - mTlsCipherSuites = null; - } else { - mTlsCipherSuites = Collections.unmodifiableList(tlsCipherSuites); - } - } - /** * TLS cipher suites accepted for TLS connections with the home server. */ @@ -259,14 +152,6 @@ public List getAcceptedTlsCipherSuites() { return mTlsCipherSuites; } - /** - * @param shouldAcceptTlsExtensions if true TLS extensions will be accepted for TLS - * connections with the home server. - */ - public void setShouldAcceptTlsExtensions(boolean shouldAcceptTlsExtensions) { - mShouldAcceptTlsExtensions = shouldAcceptTlsExtensions; - } - /** * @return whether we should accept TLS extensions. */ @@ -274,14 +159,6 @@ public boolean shouldAcceptTlsExtensions() { return mShouldAcceptTlsExtensions; } - /** - * For test only: allow Http connection - */ - @VisibleForTesting() - public void allowHttpConnection() { - mAllowHttpExtension = true; - } - /** * @return true if Http connection is allowed (false by default). */ @@ -376,19 +253,19 @@ public static HomeServerConnectionConfig fromJson(JSONObject jsonObject) throws JSONObject credentialsObj = jsonObject.optJSONObject("credentials"); Credentials creds = credentialsObj != null ? Credentials.fromJson(credentialsObj) : null; - HomeServerConnectionConfig config = new HomeServerConnectionConfig( - Uri.parse(jsonObject.getString("home_server_url")), - jsonObject.has("identity_server_url") ? Uri.parse(jsonObject.getString("identity_server_url")) : null, - creds, - fingerprints, - jsonObject.optBoolean("pin", false)); + Builder builder = new Builder() + .withHomeServerUri(Uri.parse(jsonObject.getString("home_server_url"))) + .withIdentityServerUri(jsonObject.has("identity_server_url") ? Uri.parse(jsonObject.getString("identity_server_url")) : null) + .withCredentials(creds) + .withAllowedFingerPrints(fingerprints) + .withPin(jsonObject.optBoolean("pin", false)); // Set the anti-virus server uri if any if (jsonObject.has("antivirus_server_url")) { - config.setAntiVirusServerUri(Uri.parse(jsonObject.getString("antivirus_server_url"))); + builder.withAntiVirusServerUri(Uri.parse(jsonObject.getString("antivirus_server_url"))); } - config.setShouldAcceptTlsExtensions(jsonObject.optBoolean("tls_extensions", true)); + builder.withShouldAcceptTlsExtensions(jsonObject.optBoolean("tls_extensions", true)); // Set the TLS versions if any if (jsonObject.has("tls_versions")) { @@ -399,13 +276,10 @@ public static HomeServerConnectionConfig fromJson(JSONObject jsonObject) throws tlsVersions.add(TlsVersion.forJavaName(tlsVersionsArray.getString(i))); } } - config.setAcceptedTlsVersions(tlsVersions); - } else { - config.setAcceptedTlsVersions(null); + builder.withAcceptedTlsVersions(tlsVersions); } // Set the TLS cipher suites if any - if (jsonObject.has("tls_cipher_suites")) { List tlsCipherSuites = new ArrayList<>(); JSONArray tlsCipherSuitesArray = jsonObject.optJSONArray("tls_cipher_suites"); @@ -414,11 +288,175 @@ public static HomeServerConnectionConfig fromJson(JSONObject jsonObject) throws tlsCipherSuites.add(CipherSuite.forJavaName(tlsCipherSuitesArray.getString(i))); } } - config.setAcceptedTlsCipherSuites(tlsCipherSuites); - } else { - config.setAcceptedTlsCipherSuites(null); + builder.withAcceptedTlsCipherSuites(tlsCipherSuites); + } + + return builder.build(); + } + + /** + * Builder + */ + public static class Builder { + private HomeServerConnectionConfig mHomeServerConnectionConfig; + + /** + * Builder constructor + */ + public Builder() { + mHomeServerConnectionConfig = new HomeServerConnectionConfig(); + } + + /** + * @param hsUri The URI to use to connect to the homeserver. Cannot be null + * @return + */ + public Builder withHomeServerUri(final Uri hsUri) { + if (hsUri == null || (!"http".equals(hsUri.getScheme()) && !"https".equals(hsUri.getScheme()))) { + throw new RuntimeException("Invalid home server URI: " + hsUri); + } + + // remove trailing / + if (hsUri.toString().endsWith("/")) { + try { + String url = hsUri.toString(); + mHomeServerConnectionConfig.mHsUri = Uri.parse(url.substring(0, url.length() - 1)); + } catch (Exception e) { + throw new RuntimeException("Invalid home server URI: " + hsUri); + } + } else { + mHomeServerConnectionConfig.mHsUri = hsUri; + } + + return this; + } + + /** + * @param identityServerUri The URI to use to manage identity. Can be null + * @return + */ + public Builder withIdentityServerUri(final Uri identityServerUri) { + if ((null != identityServerUri) && (!"http".equals(identityServerUri.getScheme()) && !"https".equals(identityServerUri.getScheme()))) { + throw new RuntimeException("Invalid identity server URI: " + identityServerUri); + } + + // remove trailing / + if ((null != identityServerUri) && identityServerUri.toString().endsWith("/")) { + try { + String url = identityServerUri.toString(); + mHomeServerConnectionConfig.mIdentityServerUri = Uri.parse(url.substring(0, url.length() - 1)); + } catch (Exception e) { + throw new RuntimeException("Invalid identity server URI: " + identityServerUri); + } + } else { + mHomeServerConnectionConfig.mIdentityServerUri = identityServerUri; + } + + return this; + } + + /** + * @param credentials The credentials to use, if needed. Can be null. + * @return + */ + public Builder withCredentials(@Nullable Credentials credentials) { + mHomeServerConnectionConfig.mCredentials = credentials; + return this; + } + + /** + * @param allowedFingerprints If using SSL, allow server certs that match these fingerprints. + * @return + */ + public Builder withAllowedFingerPrints(@Nullable List allowedFingerprints) { + if (allowedFingerprints != null) { + mHomeServerConnectionConfig.mAllowedFingerprints.addAll(allowedFingerprints); + } + + return this; + } + + /** + * @param pin If true only allow certs matching given fingerprints, otherwise fallback to + * standard X509 checks. + */ + public Builder withPin(boolean pin) { + mHomeServerConnectionConfig.mPin = pin; + + return this; + } + + public Builder withShouldAcceptTlsExtensions(boolean shouldAcceptTlsExtension) { + mHomeServerConnectionConfig.mShouldAcceptTlsExtensions = shouldAcceptTlsExtension; + + return this; + } + + /** + * Update the set of TLS versions accepted for TLS connections with the home server. + * + * @param tlsVersions the set of TLS versions accepted. + */ + public Builder withAcceptedTlsVersions(@Nullable List tlsVersions) { + if (tlsVersions == null) { + mHomeServerConnectionConfig.mTlsVersions = null; + } else { + mHomeServerConnectionConfig.mTlsVersions = Collections.unmodifiableList(tlsVersions); + } + + return this; + } + + /** + * Update the set of TLS cipher suites accepted for TLS connections with the home server. + * + * @param tlsCipherSuites the set of TLS cipher suites accepted. + */ + public Builder withAcceptedTlsCipherSuites(@Nullable List tlsCipherSuites) { + if (tlsCipherSuites == null) { + mHomeServerConnectionConfig.mTlsCipherSuites = null; + } else { + mHomeServerConnectionConfig.mTlsCipherSuites = Collections.unmodifiableList(tlsCipherSuites); + } + + return this; + } + + /** + * Update the anti-virus server URI. + * + * @param antivirusServerUri the new anti-virus uri. Can be null + */ + public Builder withAntiVirusServerUri(Uri antivirusServerUri) { + if ((null != antivirusServerUri) && (!"http".equals(antivirusServerUri.getScheme()) && !"https".equals(antivirusServerUri.getScheme()))) { + throw new RuntimeException("Invalid antivirus server URI: " + antivirusServerUri); + } + + mHomeServerConnectionConfig.mAntiVirusServerUri = antivirusServerUri; + + return this; + } + + /** + * For test only: allow Http connection + */ + @VisibleForTesting + public Builder withAllowHttpConnection() { + mHomeServerConnectionConfig.mAllowHttpExtension = true; + return this; + } + + /** + * @return the {@link HomeServerConnectionConfig} + */ + public HomeServerConnectionConfig build() { + // Check mandatory parameters + if (mHomeServerConnectionConfig.mHsUri == null) { + throw new RuntimeException("Home server URI not set"); + } + + return mHomeServerConnectionConfig; } - return config; } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index 5425ea64d..d0de37efc 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -2497,8 +2497,10 @@ public Builder withPushServerUrl(@Nullable String pushServerUrl) { if (!TextUtils.isEmpty(pushServerUrl)) { // pusher uses a custom server try { - HomeServerConnectionConfig alteredHsConfig = new HomeServerConnectionConfig(Uri.parse(pushServerUrl)); - alteredHsConfig.setCredentials(mxSession.mHsConfig.getCredentials()); + HomeServerConnectionConfig alteredHsConfig = new HomeServerConnectionConfig.Builder() + .withHomeServerUri(Uri.parse(pushServerUrl)) + .withCredentials(mxSession.mHsConfig.getCredentials()) + .build(); pushersRestClient = new PushersRestClient(alteredHsConfig); } catch (Exception e) { Log.e(LOG_TAG, "## withPushServerUrl() failed " + e.getMessage(), e); diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestsHelper.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/TestsHelper.java index 4bdb582f3..1dfcd6bfb 100644 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestsHelper.java +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/TestsHelper.java @@ -58,7 +58,9 @@ public static void createAccountAndSync(Context context, RestClient.mUseMXExecutor = true; Uri uri = Uri.parse(TESTS_HOME_SERVER_URL); - HomeServerConnectionConfig hs = new HomeServerConnectionConfig(uri); + HomeServerConnectionConfig hs = new HomeServerConnectionConfig.Builder() + .withHomeServerUri(uri) + .build(); LoginRestClient loginRestClient = new LoginRestClient(hs); final Map params = new HashMap<>(); From d1b240c6ecba3ad414ef9ab77fad370a03894e6b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 25 Sep 2018 12:21:16 +0200 Subject: [PATCH 043/236] Improve the builder --- .../HomeServerConnectionConfig.java | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java index 689995900..af8963553 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java @@ -18,6 +18,7 @@ package org.matrix.androidsdk; import android.net.Uri; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; @@ -28,7 +29,6 @@ import org.matrix.androidsdk.ssl.Fingerprint; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import okhttp3.CipherSuite; @@ -269,26 +269,22 @@ public static HomeServerConnectionConfig fromJson(JSONObject jsonObject) throws // Set the TLS versions if any if (jsonObject.has("tls_versions")) { - List tlsVersions = new ArrayList<>(); JSONArray tlsVersionsArray = jsonObject.optJSONArray("tls_versions"); if (tlsVersionsArray != null) { for (int i = 0; i < tlsVersionsArray.length(); i++) { - tlsVersions.add(TlsVersion.forJavaName(tlsVersionsArray.getString(i))); + builder.addAcceptedTlsVersion(TlsVersion.forJavaName(tlsVersionsArray.getString(i))); } } - builder.withAcceptedTlsVersions(tlsVersions); } // Set the TLS cipher suites if any if (jsonObject.has("tls_cipher_suites")) { - List tlsCipherSuites = new ArrayList<>(); JSONArray tlsCipherSuitesArray = jsonObject.optJSONArray("tls_cipher_suites"); if (tlsCipherSuitesArray != null) { for (int i = 0; i < tlsCipherSuitesArray.length(); i++) { - tlsCipherSuites.add(CipherSuite.forJavaName(tlsCipherSuitesArray.getString(i))); + builder.addAcceptedTlsCipherSuite(CipherSuite.forJavaName(tlsCipherSuitesArray.getString(i))); } } - builder.withAcceptedTlsCipherSuites(tlsCipherSuites); } return builder.build(); @@ -393,32 +389,32 @@ public Builder withShouldAcceptTlsExtensions(boolean shouldAcceptTlsExtension) { } /** - * Update the set of TLS versions accepted for TLS connections with the home server. + * Add an accepted TLS version for TLS connections with the home server. * - * @param tlsVersions the set of TLS versions accepted. + * @param tlsVersion the tls version to add to the set of TLS versions accepted. */ - public Builder withAcceptedTlsVersions(@Nullable List tlsVersions) { - if (tlsVersions == null) { - mHomeServerConnectionConfig.mTlsVersions = null; - } else { - mHomeServerConnectionConfig.mTlsVersions = Collections.unmodifiableList(tlsVersions); + public Builder addAcceptedTlsVersion(@NonNull TlsVersion tlsVersion) { + if (mHomeServerConnectionConfig.mTlsVersions == null) { + mHomeServerConnectionConfig.mTlsVersions = new ArrayList<>(); } + mHomeServerConnectionConfig.mTlsVersions.add(tlsVersion); + return this; } /** - * Update the set of TLS cipher suites accepted for TLS connections with the home server. + * Add a TLS cipher suite to the list of accepted TLS connections with the home server. * - * @param tlsCipherSuites the set of TLS cipher suites accepted. + * @param tlsCipherSuite the tls cipher suite to add. */ - public Builder withAcceptedTlsCipherSuites(@Nullable List tlsCipherSuites) { - if (tlsCipherSuites == null) { - mHomeServerConnectionConfig.mTlsCipherSuites = null; - } else { - mHomeServerConnectionConfig.mTlsCipherSuites = Collections.unmodifiableList(tlsCipherSuites); + public Builder addAcceptedTlsCipherSuite(@NonNull CipherSuite tlsCipherSuite) { + if (mHomeServerConnectionConfig.mTlsCipherSuites == null) { + mHomeServerConnectionConfig.mTlsCipherSuites = new ArrayList<>(); } + mHomeServerConnectionConfig.mTlsCipherSuites.add(tlsCipherSuite); + return this; } From 8038b89a00060e44e848ebf8799db96f1518f367 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 25 Sep 2018 14:28:49 +0200 Subject: [PATCH 044/236] Split long line --- .../src/main/java/org/matrix/androidsdk/util/CompatUtil.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java index 7cacb994d..dc845bd74 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/CompatUtil.java @@ -117,7 +117,8 @@ private static synchronized SecretKeyAndVersion getAesGcmLocalProtectionKey(Cont final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); // Get the version of Android when the key has been generated, default to the current version of the system. In this case, the // key will be generated - final int androidVersionWhenTheKeyHasBeenGenerated = sharedPreferences.getInt(SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED, Build.VERSION.SDK_INT); + final int androidVersionWhenTheKeyHasBeenGenerated + = sharedPreferences.getInt(SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED, Build.VERSION.SDK_INT); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (keyStore.containsAlias(AES_LOCAL_PROTECTION_KEY_ALIAS)) { From d07456efa3f71f38c3b21b6932bd6b996ec620ab Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 25 Sep 2018 15:19:38 +0200 Subject: [PATCH 045/236] Add method to limit TLS usage to the builder --- .../HomeServerConnectionConfig.java | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java index af8963553..16a6bd64f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java @@ -305,7 +305,7 @@ public Builder() { /** * @param hsUri The URI to use to connect to the homeserver. Cannot be null - * @return + * @return this builder */ public Builder withHomeServerUri(final Uri hsUri) { if (hsUri == null || (!"http".equals(hsUri.getScheme()) && !"https".equals(hsUri.getScheme()))) { @@ -329,7 +329,7 @@ public Builder withHomeServerUri(final Uri hsUri) { /** * @param identityServerUri The URI to use to manage identity. Can be null - * @return + * @return this builder */ public Builder withIdentityServerUri(final Uri identityServerUri) { if ((null != identityServerUri) && (!"http".equals(identityServerUri.getScheme()) && !"https".equals(identityServerUri.getScheme()))) { @@ -353,7 +353,7 @@ public Builder withIdentityServerUri(final Uri identityServerUri) { /** * @param credentials The credentials to use, if needed. Can be null. - * @return + * @return this builder */ public Builder withCredentials(@Nullable Credentials credentials) { mHomeServerConnectionConfig.mCredentials = credentials; @@ -362,7 +362,7 @@ public Builder withCredentials(@Nullable Credentials credentials) { /** * @param allowedFingerprints If using SSL, allow server certs that match these fingerprints. - * @return + * @return this builder */ public Builder withAllowedFingerPrints(@Nullable List allowedFingerprints) { if (allowedFingerprints != null) { @@ -375,6 +375,7 @@ public Builder withAllowedFingerPrints(@Nullable List allowedFinger /** * @param pin If true only allow certs matching given fingerprints, otherwise fallback to * standard X509 checks. + * @return this builder */ public Builder withPin(boolean pin) { mHomeServerConnectionConfig.mPin = pin; @@ -382,6 +383,10 @@ public Builder withPin(boolean pin) { return this; } + /** + * @param shouldAcceptTlsExtension + * @return this builder + */ public Builder withShouldAcceptTlsExtensions(boolean shouldAcceptTlsExtension) { mHomeServerConnectionConfig.mShouldAcceptTlsExtensions = shouldAcceptTlsExtension; @@ -392,6 +397,7 @@ public Builder withShouldAcceptTlsExtensions(boolean shouldAcceptTlsExtension) { * Add an accepted TLS version for TLS connections with the home server. * * @param tlsVersion the tls version to add to the set of TLS versions accepted. + * @return this builder */ public Builder addAcceptedTlsVersion(@NonNull TlsVersion tlsVersion) { if (mHomeServerConnectionConfig.mTlsVersions == null) { @@ -407,6 +413,7 @@ public Builder addAcceptedTlsVersion(@NonNull TlsVersion tlsVersion) { * Add a TLS cipher suite to the list of accepted TLS connections with the home server. * * @param tlsCipherSuite the tls cipher suite to add. + * @return this builder */ public Builder addAcceptedTlsCipherSuite(@NonNull CipherSuite tlsCipherSuite) { if (mHomeServerConnectionConfig.mTlsCipherSuites == null) { @@ -422,6 +429,7 @@ public Builder addAcceptedTlsCipherSuite(@NonNull CipherSuite tlsCipherSuite) { * Update the anti-virus server URI. * * @param antivirusServerUri the new anti-virus uri. Can be null + * @return this builder */ public Builder withAntiVirusServerUri(Uri antivirusServerUri) { if ((null != antivirusServerUri) && (!"http".equals(antivirusServerUri.getScheme()) && !"https".equals(antivirusServerUri.getScheme()))) { @@ -442,6 +450,37 @@ public Builder withAllowHttpConnection() { return this; } + /** + * Convenient method to limit the TLS versions and cipher suites for this Builder + * Ref: + * - https://www.ssi.gouv.fr/uploads/2017/02/security-recommendations-for-tls_v1.1.pdf + * - https://developer.android.com/reference/javax/net/ssl/SSLEngine + * + * @param tlsLimitations true to use Tls limitations + * @return this builder + */ + public Builder withTlsLimitations(boolean tlsLimitations) { + if (tlsLimitations) { + withShouldAcceptTlsExtensions(false); + + // Tls versions + addAcceptedTlsVersion(TlsVersion.TLS_1_2); + addAcceptedTlsVersion(TlsVersion.TLS_1_3); + + // Cipher suites + addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256); + addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256); + addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256); + addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256); + addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384); + addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384); + addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256); + addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256); + } + + return this; + } + /** * @return the {@link HomeServerConnectionConfig} */ From d72b95a45e42b9500c36935889ca488364866bfb Mon Sep 17 00:00:00 2001 From: daniel tygel Date: Wed, 26 Sep 2018 07:42:24 +0000 Subject: [PATCH 046/236] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (59 of 59 strings) Translation: Riot Android/matrix-android-sdk Translate-URL: https://translate.riot.im/projects/riot-android/matrix-android-sdk/pt_BR/ --- matrix-sdk/src/main/res/values-pt-rBR/strings.xml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/res/values-pt-rBR/strings.xml b/matrix-sdk/src/main/res/values-pt-rBR/strings.xml index d4eb2d42d..25e573909 100644 --- a/matrix-sdk/src/main/res/values-pt-rBR/strings.xml +++ b/matrix-sdk/src/main/res/values-pt-rBR/strings.xml @@ -1,4 +1,4 @@ - + Matrix Android SDK @@ -76,4 +76,13 @@ Número de telefone +%1$s enviou um sticker. + + Em resposta a + + enviou uma imagem. + enviou um vídeo. + enviou um arquivo de áudio. + enviou um arquivo. + From 04b1c8a6963d06f2a9c2ccff05510d1bf0281099 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Sep 2018 10:04:42 +0200 Subject: [PATCH 047/236] Configure sonarcloud --- README.md | 2 ++ build.gradle | 32 ++++++++++++++++++++++++++++++++ gradle.properties | 3 +++ 3 files changed, 37 insertions(+) diff --git a/README.md b/README.md index 8e000716d..8acdf1695 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=matrix.android.sdk&metric=alert_status)](https://sonarcloud.io/dashboard?id=matrix.android.sdk) [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=matrix.android.sdk&metric=vulnerabilities)](https://sonarcloud.io/dashboard?id=matrix.android.sdk) [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=matrix.android.sdk&metric=bugs)](https://sonarcloud.io/dashboard?id=matrix.android.sdk) + matrix-android-sdk ================== The [Matrix] SDK for Android wraps the Matrix REST API calls in asynchronous Java methods and provides basic structures for storing and handling data. diff --git a/build.gradle b/build.gradle index c06df431e..fac233415 100644 --- a/build.gradle +++ b/build.gradle @@ -4,10 +4,14 @@ buildscript { repositories { jcenter() google() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { classpath 'com.android.tools.build:gradle:3.1.2' + classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -19,3 +23,31 @@ allprojects { google() } } + +apply plugin: 'org.sonarqube' + +sonarqube { + properties { + property "sonar.projectName", "Matrix Android SDK" + property "sonar.projectKey", "matrix.android.sdk" + property "sonar.host.url", "https://sonarcloud.io" + property "sonar.projectVersion", project(":matrix-sdk").android.defaultConfig.versionName + property "sonar.sourceEncoding", "UTF-8" + property "sonar.links.homepage", "https://github.com/matrix-org/matrix-android-sdk/" + property "sonar.links.ci", "https://matrix.org/jenkins/view/MatrixView/job/MatrixAndroidSDKDevelop/" + property "sonar.links.scm", "https://github.com/matrix-org/matrix-android-sdk/" + property "sonar.links.issue", "https://github.com/matrix-org/matrix-android-sdk/issues" + property "sonar.organization", "new_vector_ltd_organization" + property "sonar.login", project.hasProperty("SONAR_LOGIN") ? SONAR_LOGIN : "invalid" + } +} + +project(":matrix-sdk") { + sonarqube { + properties { + property "sonar.sources", project(":matrix-sdk").android.sourceSets.main.java.srcDirs + // exclude source code from analyses separated by a colon (:) + // property "sonar.exclusions", "**/*.*" + } + } +} diff --git a/gradle.properties b/gradle.properties index 0985dcf0c..17829c1a4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,4 +24,7 @@ # RELEASE_KEY_ALIAS=alias # RELEASE_KEY_PASSWORD=password +# To be able to analyse with sonar, put these variables in ~/.gradle/gradle.properties +# SONAR_LOGIN=sonar_login + org.gradle.configureondemand=false From 6ee38300e374589d42f727992778d25275349e6a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Sep 2018 12:55:35 +0200 Subject: [PATCH 048/236] Force usage of accepted Tls Versions for Android < 20 --- .../org/matrix/androidsdk/ssl/CertUtil.java | 13 +- .../androidsdk/ssl/TLSSocketFactory.java | 111 ++++++++++++++++++ 2 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/CertUtil.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/CertUtil.java index 01541d8a6..0d0d128d4 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/CertUtil.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/CertUtil.java @@ -183,9 +183,16 @@ public static Pair newPinnedSSLSocketFactory new PinnedTrustManager(hsConfig.getAllowedFingerprints(), defaultTrustManager) }; - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, trustPinned, new java.security.SecureRandom()); - SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + SSLSocketFactory sslSocketFactory; + + if (hsConfig.getAcceptedTlsVersions() == null) { + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, trustPinned, new java.security.SecureRandom()); + sslSocketFactory = sslContext.getSocketFactory(); + } else { + // Force usage of accepted Tls Versions for Android < 20 + sslSocketFactory = new TLSSocketFactory(trustPinned, hsConfig.getAcceptedTlsVersions()); + } return new Pair<>(sslSocketFactory, defaultTrustManager); } catch (Exception e) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java new file mode 100644 index 000000000..bbe5ab603 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java @@ -0,0 +1,111 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.ssl; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.List; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; + +import okhttp3.TlsVersion; + +/** + * Force the usage of Tls versions on every created socket + */ +public class TLSSocketFactory extends SSLSocketFactory { + + private SSLSocketFactory internalSSLSocketFactory; + + private String[] enabledProtocol; + + /** + * Constructor + * + * @param trustPinned + * @param acceptedTlsVersions + * @throws KeyManagementException + * @throws NoSuchAlgorithmException + */ + public TLSSocketFactory(TrustManager[] trustPinned, List acceptedTlsVersions) throws KeyManagementException, NoSuchAlgorithmException { + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, trustPinned, new SecureRandom()); + internalSSLSocketFactory = context.getSocketFactory(); + + enabledProtocol = new String[acceptedTlsVersions.size()]; + int i = 0; + for (TlsVersion tlsVersion : acceptedTlsVersions) { + enabledProtocol[i] = tlsVersion.javaName(); + i++; + } + } + + @Override + public String[] getDefaultCipherSuites() { + return internalSSLSocketFactory.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return internalSSLSocketFactory.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket() throws IOException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket()); + } + + @Override + public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose)); + } + + @Override + public Socket createSocket(String host, int port) throws IOException, UnknownHostException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort)); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort)); + } + + private Socket enableTLSOnSocket(Socket socket) { + if (socket != null && (socket instanceof SSLSocket)) { + ((SSLSocket) socket).setEnabledProtocols(enabledProtocol); + } + return socket; + } +} From 867515750054bdb3d75593a42ad8654a56ae2ce1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Sep 2018 15:00:25 +0200 Subject: [PATCH 049/236] Cleanup stuff related to an Android APK --- gradle.properties | 7 ------- matrix-sdk/build.gradle | 9 --------- 2 files changed, 16 deletions(-) diff --git a/gradle.properties b/gradle.properties index 17829c1a4..ead439d15 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,13 +17,6 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true - -# To do a signed release APK, put these variables in ~/.gradle/gradle.properties -# RELEASE_STORE_FILE=/path/to/keystore -# RELEASE_STORE_PASSWORD=password -# RELEASE_KEY_ALIAS=alias -# RELEASE_KEY_PASSWORD=password - # To be able to analyse with sonar, put these variables in ~/.gradle/gradle.properties # SONAR_LOGIN=sonar_login diff --git a/matrix-sdk/build.gradle b/matrix-sdk/build.gradle index 91da93097..df52fb6bd 100644 --- a/matrix-sdk/build.gradle +++ b/matrix-sdk/build.gradle @@ -26,15 +26,6 @@ android { include "**/*Test.class" // whatever Ant pattern matches your test class files } - signingConfigs { - release { - storeFile file(project.hasProperty("RELEASE_STORE_FILE") ? RELEASE_STORE_FILE : "/dummy/path") - storePassword project.hasProperty("RELEASE_STORE_PASSWORD") ? RELEASE_STORE_PASSWORD : "dummy password" - keyAlias project.hasProperty("RELEASE_KEY_ALIAS") ? RELEASE_KEY_ALIAS : "dummy alias" - keyPassword project.hasProperty("RELEASE_KEY_PASSWORD") ? RELEASE_KEY_PASSWORD : "dummy password" - } - } - android.libraryVariants.all { variant -> task("${variant.name}Docs", type: Javadoc) { source = variant.javaCompiler.source From 65fa7853f6a460bd7839e52c18ba9731a26edd0b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Sep 2018 17:05:34 +0200 Subject: [PATCH 050/236] Rename method for code clarity --- .../main/java/org/matrix/androidsdk/data/EventTimeline.java | 6 +++--- .../androidsdk/fragments/MatrixMessageListFragment.java | 6 +++--- .../main/java/org/matrix/androidsdk/rest/model/Event.java | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index 75b106170..9a76229bc 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -701,8 +701,8 @@ private void storeLiveRoomEvent(Event event, boolean checkRedactedStateEvent) { String myUserId = mDataHandler.getCredentials().userId; if (Event.EVENT_TYPE_REDACTION.equals(event.getType())) { - if (event.getRedacts() != null) { - Event eventToPrune = mStore.getEvent(event.getRedacts(), event.roomId); + if (event.getRedactedEventId() != null) { + Event eventToPrune = mStore.getEvent(event.getRedactedEventId(), event.roomId); // when an event is redacted, some fields must be kept. if (null != eventToPrune) { @@ -1536,7 +1536,7 @@ public void run() { */ private void checkStateEventRedaction(final Event redactionEvent) { - final String eventId = redactionEvent.getRedacts(); + final String eventId = redactionEvent.getRedactedEventId(); Log.d(LOG_TAG, "checkStateEventRedaction of event " + eventId); // check if the state events is locally known diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java index 6316fcdac..4538dcac2 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java @@ -1763,13 +1763,13 @@ public void onEvent(final Event event, final EventTimeline.Direction direction, if (direction == EventTimeline.Direction.FORWARDS) { if (Event.EVENT_TYPE_REDACTION.equals(event.getType())) { - MessageRow messageRow = mAdapter.getMessageRow(event.getRedacts()); + MessageRow messageRow = mAdapter.getMessageRow(event.getRedactedEventId()); if (null != messageRow) { - Event prunedEvent = mSession.getDataHandler().getStore().getEvent(event.getRedacts(), event.roomId); + Event prunedEvent = mSession.getDataHandler().getStore().getEvent(event.getRedactedEventId(), event.roomId); if (null == prunedEvent) { - mAdapter.removeEventById(event.getRedacts()); + mAdapter.removeEventById(event.getRedactedEventId()); } else { messageRow.updateEvent(prunedEvent); JsonObject content = messageRow.getEvent().getContentAsJsonObject(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java index 2d7b828f7..ec04facc5 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java @@ -451,7 +451,8 @@ public long getAge() { /** * @return the redacted event id. */ - public String getRedacts() { + @Nullable + public String getRedactedEventId() { if (null != redacts) { return redacts; } else if (isRedacted()) { From 5b6021fbf0543b222017effc8f34b3ff043d8b3c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Sep 2018 17:35:53 +0200 Subject: [PATCH 051/236] better comment format --- .../matrix/androidsdk/rest/model/Event.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java index ec04facc5..67bbe02ed 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java @@ -62,13 +62,20 @@ public class Event implements Externalizable { private static final long serialVersionUID = -1431845331022808337L; public enum SentState { - UNSENT, // the event has not been sent - ENCRYPTING, // the event is encrypting - SENDING, // the event is currently sending - WAITING_RETRY, // the event is going to be resent asap - SENT, // the event has been sent - UNDELIVERABLE, // The event failed to be sent - FAILED_UNKNOWN_DEVICES // the event failed to be sent because some unknown devices have been found while encrypting it + // the event has not been sent + UNSENT, + // the event is encrypting + ENCRYPTING, + // the event is currently sending + SENDING, + // the event is going to be resent asap + WAITING_RETRY, + // the event has been sent + SENT, + // The event failed to be sent + UNDELIVERABLE, + // the event failed to be sent because some unknown devices have been found while encrypting it + FAILED_UNKNOWN_DEVICES } // when there is no more message to be paginated in a room From 54a65f40fb335ba9399e6df406b13f8db076e4c0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Sep 2018 17:51:17 +0200 Subject: [PATCH 052/236] Rename State for code clarity --- .../java/org/matrix/androidsdk/data/Room.java | 16 ++++++++-------- .../androidsdk/data/RoomMediaMessagesSender.java | 6 +++--- .../matrix/androidsdk/data/store/IMXStore.java | 6 +++--- .../androidsdk/data/store/MXFileStore.java | 7 +++---- .../androidsdk/data/store/MXMemoryStore.java | 12 ++++++------ .../fragments/MatrixMessageListFragment.java | 6 +++--- .../org/matrix/androidsdk/rest/model/Event.java | 16 ++++++++-------- 7 files changed, 34 insertions(+), 35 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index b186949d2..bfa4acc63 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -2349,7 +2349,7 @@ public void onSuccess(final CreatedEvent createdEvent) { @Override public void onNetworkError(Exception e) { event.unsentException = e; - mDataHandler.updateEventState(event, Event.SentState.UNDELIVERABLE); + mDataHandler.updateEventState(event, Event.SentState.UNDELIVERED); try { callback.onNetworkError(e); } catch (Exception anException) { @@ -2360,7 +2360,7 @@ public void onNetworkError(Exception e) { @Override public void onMatrixError(MatrixError e) { event.unsentMatrixError = e; - mDataHandler.updateEventState(event, Event.SentState.UNDELIVERABLE); + mDataHandler.updateEventState(event, Event.SentState.UNDELIVERED); if (MatrixError.isConfigurationErrorCode(e.errcode)) { mDataHandler.onConfigurationError(e.errcode); @@ -2376,7 +2376,7 @@ public void onMatrixError(MatrixError e) { @Override public void onUnexpectedError(Exception e) { event.unsentException = e; - mDataHandler.updateEventState(event, Event.SentState.UNDELIVERABLE); + mDataHandler.updateEventState(event, Event.SentState.UNDELIVERED); try { callback.onUnexpectedError(e); } catch (Exception anException) { @@ -2429,7 +2429,7 @@ public void onSuccess(MXEncryptEventContentResult encryptEventContentResult) { @Override public void onNetworkError(Exception e) { event.unsentException = e; - mDataHandler.updateEventState(event, Event.SentState.UNDELIVERABLE); + mDataHandler.updateEventState(event, Event.SentState.UNDELIVERED); if (null != callback) { callback.onNetworkError(e); @@ -2442,7 +2442,7 @@ public void onMatrixError(MatrixError e) { if ((e instanceof MXCryptoError) && TextUtils.equals(((MXCryptoError) e).errcode, MXCryptoError.UNKNOWN_DEVICES_CODE)) { event.mSentState = Event.SentState.FAILED_UNKNOWN_DEVICES; } else { - event.mSentState = Event.SentState.UNDELIVERABLE; + event.mSentState = Event.SentState.UNDELIVERED; } event.unsentMatrixError = e; mDataHandler.onEventSentStateUpdated(event); @@ -2455,7 +2455,7 @@ public void onMatrixError(MatrixError e) { @Override public void onUnexpectedError(Exception e) { event.unsentException = e; - mDataHandler.updateEventState(event, Event.SentState.UNDELIVERABLE); + mDataHandler.updateEventState(event, Event.SentState.UNDELIVERED); if (null != callback) { callback.onUnexpectedError(e); @@ -2490,7 +2490,7 @@ public void cancelEventSending(final Event event) { (Event.SentState.ENCRYPTING == event.mSentState)) { // the message cannot be sent anymore - mDataHandler.updateEventState(event, Event.SentState.UNDELIVERABLE); + mDataHandler.updateEventState(event, Event.SentState.UNDELIVERED); } List urls = event.getMediaUrls(); @@ -3015,7 +3015,7 @@ public List getUnsentEvents() { List unsent = new ArrayList<>(); if (null != getStore()) { - List undeliverableEvents = getStore().getUndeliverableEvents(getRoomId()); + List undeliverableEvents = getStore().getUndeliveredEvents(getRoomId()); List unknownDeviceEvents = getStore().getUnknownDeviceEvents(getRoomId()); if (null != undeliverableEvents) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomMediaMessagesSender.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomMediaMessagesSender.java index b7cb5e11e..2ff1435ff 100755 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomMediaMessagesSender.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomMediaMessagesSender.java @@ -832,7 +832,7 @@ public void run() { mUiHandler.post(new Runnable() { @Override public void run() { - mDataHandler.updateEventState(roomMediaMessage.getEvent(), Event.SentState.UNDELIVERABLE); + mDataHandler.updateEventState(roomMediaMessage.getEvent(), Event.SentState.UNDELIVERED); mRoom.storeOutgoingEvent(roomMediaMessage.getEvent()); mDataHandler.getStore().commit(); @@ -874,7 +874,7 @@ public void onUploadCancel(final String uploadId) { mUiHandler.post(new Runnable() { @Override public void run() { - mDataHandler.updateEventState(roomMediaMessage.getEvent(), Event.SentState.UNDELIVERABLE); + mDataHandler.updateEventState(roomMediaMessage.getEvent(), Event.SentState.UNDELIVERED); if (null != roomMediaMessage.getMediaUploadListener()) { roomMediaMessage.getMediaUploadListener().onUploadCancel(uploadId); @@ -892,7 +892,7 @@ public void onUploadError(final String uploadId, final int serverResponseCode, f mUiHandler.post(new Runnable() { @Override public void run() { - mDataHandler.updateEventState(roomMediaMessage.getEvent(), Event.SentState.UNDELIVERABLE); + mDataHandler.updateEventState(roomMediaMessage.getEvent(), Event.SentState.UNDELIVERED); if (null != roomMediaMessage.getMediaUploadListener()) { roomMediaMessage.getMediaUploadListener().onUploadError(uploadId, serverResponseCode, serverErrorMessage); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java index a160e297f..a9f466b7d 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java @@ -450,12 +450,12 @@ public interface IMXStore { List getLatestUnsentEvents(String roomId); /** - * Return the list of undeliverable events + * Return the list of undelivered events * * @param roomId the room id - * @return list of undeliverable events + * @return list of undelivered events */ - List getUndeliverableEvents(String roomId); + List getUndeliveredEvents(String roomId); /** * Return the list of unknown device events. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java index 49ce8b4e9..eabbb7cda 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java @@ -1220,13 +1220,12 @@ private boolean loadRoomMessages(final String roomId) { // finalizes the deserialization for (Event event : events.values()) { - // if a message was not sent, mark at as UNDELIVERABLE - if ((event.mSentState == Event.SentState.UNDELIVERABLE) || - (event.mSentState == Event.SentState.UNSENT) || + // if a message was not sent, mark it as UNDELIVERED + if ((event.mSentState == Event.SentState.UNSENT) || (event.mSentState == Event.SentState.SENDING) || (event.mSentState == Event.SentState.WAITING_RETRY) || (event.mSentState == Event.SentState.ENCRYPTING)) { - event.mSentState = Event.SentState.UNDELIVERABLE; + event.mSentState = Event.SentState.UNDELIVERED; shouldSave = true; } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java index 7bd112c61..865c1f9e3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java @@ -1076,12 +1076,12 @@ public List getLatestUnsentEvents(String roomId) { } @Override - public List getUndeliverableEvents(String roomId) { + public List getUndeliveredEvents(String roomId) { if (null == roomId) { return null; } - List undeliverableRoomEvents = new ArrayList<>(); + List undeliveredEvents = new ArrayList<>(); synchronized (mRoomEventsLock) { LinkedHashMap events = mRoomEvents.get(roomId); @@ -1093,16 +1093,16 @@ public List getUndeliverableEvents(String roomId) { for (int index = events.size() - 1; index >= 0; index--) { Event event = eventsList.get(index); - if (event.isUndeliverable()) { - undeliverableRoomEvents.add(event); + if (event.isUndelivered()) { + undeliveredEvents.add(event); } } - Collections.reverse(undeliverableRoomEvents); + Collections.reverse(undeliveredEvents); } } - return undeliverableRoomEvents; + return undeliveredEvents; } @Override diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java index 4538dcac2..9acad5572 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java @@ -1009,7 +1009,7 @@ private void add(final RoomMediaMessage roomMediaMessage) { final Event event = messageRow.getEvent(); - if (!event.isUndeliverable()) { + if (!event.isUndelivered()) { ApiCallback callback = new ApiCallback() { @Override public void onSuccess(Void info) { @@ -1029,7 +1029,7 @@ public void run() { if (null != activity) { // display the error message only if the message cannot be resent - if ((null != event.unsentException) && (event.isUndeliverable())) { + if ((null != event.unsentException) && (event.isUndelivered())) { if (event.unsentException instanceof IOException) { Toast.makeText(activity, activity.getString(R.string.unable_to_send_message) + " : " + activity.getString(R.string.network_error), Toast.LENGTH_LONG).show(); @@ -1181,7 +1181,7 @@ public void run() { Log.e(LOG_TAG, "relaunchTimer.schedule failed " + throwable.getMessage(), throwable); } } else { - messageRow.getEvent().mSentState = Event.SentState.UNDELIVERABLE; + messageRow.getEvent().mSentState = Event.SentState.UNDELIVERED; onMessageSendingFailed(messageRow.getEvent()); mAdapter.notifyDataSetChanged(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java index 67bbe02ed..03c9a7ca3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java @@ -73,7 +73,7 @@ public enum SentState { // the event has been sent SENT, // The event failed to be sent - UNDELIVERABLE, + UNDELIVERED, // the event failed to be sent because some unknown devices have been found while encrypting it FAILED_UNKNOWN_DEVICES } @@ -602,7 +602,7 @@ public Event deepCopy() { * @return true if it can be resent. */ public boolean canBeResent() { - return (mSentState == SentState.WAITING_RETRY) || (mSentState == SentState.UNDELIVERABLE) || (mSentState == SentState.FAILED_UNKNOWN_DEVICES); + return (mSentState == SentState.WAITING_RETRY) || (mSentState == SentState.UNDELIVERED) || (mSentState == SentState.FAILED_UNKNOWN_DEVICES); } /** @@ -633,12 +633,12 @@ public boolean isSending() { } /** - * Tell if the message is undeliverable + * Tell if the message sending failed * - * @return true if the event is undeliverable + * @return true if the event has not been sent because of a failure */ - public boolean isUndeliverable() { - return (mSentState == SentState.UNDELIVERABLE); + public boolean isUndelivered() { + return (mSentState == SentState.UNDELIVERED); } /** @@ -855,8 +855,8 @@ public String toString() { text += "WAITING_RETRY"; } else if (mSentState == SentState.SENT) { text += "SENT"; - } else if (mSentState == SentState.UNDELIVERABLE) { - text += "UNDELIVERABLE"; + } else if (mSentState == SentState.UNDELIVERED) { + text += "UNDELIVERED"; } else if (mSentState == SentState.FAILED_UNKNOWN_DEVICES) { text += "FAILED UNKNOWN DEVICES"; } From 02adff949a75b3775dae86fa01d14bee6c5d0c64 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Sep 2018 17:51:36 +0200 Subject: [PATCH 053/236] Remove deprecated method --- .../main/java/org/matrix/androidsdk/rest/model/Event.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java index 03c9a7ca3..93d203512 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java @@ -650,14 +650,6 @@ public boolean isUnknownDevice() { return (mSentState == SentState.FAILED_UNKNOWN_DEVICES); } - /** - * @deprecated call isUnknownDevice() - */ - @Deprecated - public boolean isUnkownDevice() { - return isUnknownDevice(); - } - /** * Check if the current event is sent. * From 0c867ac632a9e0f1540033696462329379a96c79 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Sep 2018 17:55:08 +0200 Subject: [PATCH 054/236] Better algo --- .../org/matrix/androidsdk/data/store/MXMemoryStore.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java index 865c1f9e3..0809cc6be 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java @@ -1090,15 +1090,13 @@ public List getUndeliveredEvents(String roomId) { if ((null != events) && (events.size() > 0)) { List eventsList = new ArrayList<>(events.values()); - for (int index = events.size() - 1; index >= 0; index--) { + for (int index = 0; index < events.size(); index++) { Event event = eventsList.get(index); if (event.isUndelivered()) { undeliveredEvents.add(event); } } - - Collections.reverse(undeliveredEvents); } } @@ -1120,15 +1118,13 @@ public List getUnknownDeviceEvents(String roomId) { if ((null != events) && (events.size() > 0)) { List eventsList = new ArrayList<>(events.values()); - for (int index = events.size() - 1; index >= 0; index--) { + for (int index = 0; index < events.size(); index++) { Event event = eventsList.get(index); if (event.isUnknownDevice()) { unknownDeviceEvents.add(event); } } - - Collections.reverse(unknownDeviceEvents); } } From a3db54af2bf28a2dcb054643d095dee203376037 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 26 Sep 2018 19:03:28 +0200 Subject: [PATCH 055/236] Initial state when creating an Event is UNSENT --- .../main/java/org/matrix/androidsdk/rest/model/Event.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java index 93d203512..d2b9c1380 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java @@ -164,7 +164,7 @@ public enum SentState { public MatrixError unsentMatrixError = null; // sent state - public SentState mSentState = SentState.SENT; + public SentState mSentState; // save the token to back paginate // the room history could have been reduced to save memory. @@ -483,7 +483,7 @@ public Event(Message message, String anUserId, String aRoomId) { originServerTs = System.currentTimeMillis(); sender = userId = anUserId; roomId = aRoomId; - mSentState = Event.SentState.SENDING; + mSentState = Event.SentState.UNSENT; createDummyEventId(); } @@ -501,7 +501,7 @@ public Event(String aType, JsonObject aContent, String anUserId, String aRoomId) originServerTs = System.currentTimeMillis(); sender = userId = anUserId; roomId = aRoomId; - mSentState = Event.SentState.SENDING; + mSentState = Event.SentState.UNSENT; createDummyEventId(); } From 615604f50d2b3db9adfa8cd2fc2cb9bf3632612e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 27 Sep 2018 10:16:04 +0200 Subject: [PATCH 056/236] Giom review: add reference to the source --- .../java/org/matrix/androidsdk/ssl/TLSSocketFactory.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java index bbe5ab603..fb73a023c 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java @@ -34,8 +34,9 @@ /** * Force the usage of Tls versions on every created socket + * Inspired from https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/ */ -public class TLSSocketFactory extends SSLSocketFactory { +/*package*/ class TLSSocketFactory extends SSLSocketFactory { private SSLSocketFactory internalSSLSocketFactory; @@ -49,7 +50,7 @@ public class TLSSocketFactory extends SSLSocketFactory { * @throws KeyManagementException * @throws NoSuchAlgorithmException */ - public TLSSocketFactory(TrustManager[] trustPinned, List acceptedTlsVersions) throws KeyManagementException, NoSuchAlgorithmException { + /*package*/ TLSSocketFactory(TrustManager[] trustPinned, List acceptedTlsVersions) throws KeyManagementException, NoSuchAlgorithmException { SSLContext context = SSLContext.getInstance("TLS"); context.init(null, trustPinned, new SecureRandom()); internalSSLSocketFactory = context.getSocketFactory(); From 89edfc3b9147b6ab794949074f062a410c243900 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 27 Sep 2018 10:19:52 +0200 Subject: [PATCH 057/236] Giom review: add a setter to force usage of Tls only for old Android version --- .../HomeServerConnectionConfig.java | 36 ++++++++++++++++--- .../org/matrix/androidsdk/ssl/CertUtil.java | 8 ++--- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java index 16a6bd64f..d0ce2805c 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java @@ -59,6 +59,8 @@ public class HomeServerConnectionConfig { private boolean mShouldAcceptTlsExtensions = true; // allow Http connection private boolean mAllowHttpExtension; + // Force usage of TLS versions + private boolean mForceUsageTlsVersions; /** * Private constructor. Please use the Builder @@ -166,6 +168,13 @@ public boolean isHttpConnectionAllowed() { return mAllowHttpExtension; } + /** + * @return true if the usage of TlsVersions has to be forced + */ + public boolean forceUsageOfTlsVersions() { + return mForceUsageTlsVersions; + } + @Override public String toString() { return "HomeserverConnectionConfig{" + @@ -221,6 +230,8 @@ public JSONObject toJson() throws JSONException { json.put("tls_versions", new JSONArray(tlsVersions)); } + json.put("force_usage_of_tls_versions", mForceUsageTlsVersions); + if (mTlsCipherSuites != null) { List tlsCipherSuites = new ArrayList<>(mTlsCipherSuites.size()); @@ -277,6 +288,8 @@ public static HomeServerConnectionConfig fromJson(JSONObject jsonObject) throws } } + builder.forceUsageOfTlsVersions(jsonObject.optBoolean("force_usage_of_tls_versions", false)); + // Set the TLS cipher suites if any if (jsonObject.has("tls_cipher_suites")) { JSONArray tlsCipherSuitesArray = jsonObject.optJSONArray("tls_cipher_suites"); @@ -331,7 +344,7 @@ public Builder withHomeServerUri(final Uri hsUri) { * @param identityServerUri The URI to use to manage identity. Can be null * @return this builder */ - public Builder withIdentityServerUri(final Uri identityServerUri) { + public Builder withIdentityServerUri(@Nullable final Uri identityServerUri) { if ((null != identityServerUri) && (!"http".equals(identityServerUri.getScheme()) && !"https".equals(identityServerUri.getScheme()))) { throw new RuntimeException("Invalid identity server URI: " + identityServerUri); } @@ -409,6 +422,18 @@ public Builder addAcceptedTlsVersion(@NonNull TlsVersion tlsVersion) { return this; } + /** + * Force the usage of TlsVersion. This can be usefull for device on Android version < 20 + * + * @param forceUsageOfTlsVersions set to true to force the usage of specified TlsVersions (with {@link #addAcceptedTlsVersion(TlsVersion)} + * @return this builder + */ + public Builder forceUsageOfTlsVersions(boolean forceUsageOfTlsVersions) { + mHomeServerConnectionConfig.mForceUsageTlsVersions = forceUsageOfTlsVersions; + + return this; + } + /** * Add a TLS cipher suite to the list of accepted TLS connections with the home server. * @@ -431,7 +456,7 @@ public Builder addAcceptedTlsCipherSuite(@NonNull CipherSuite tlsCipherSuite) { * @param antivirusServerUri the new anti-virus uri. Can be null * @return this builder */ - public Builder withAntiVirusServerUri(Uri antivirusServerUri) { + public Builder withAntiVirusServerUri(@Nullable Uri antivirusServerUri) { if ((null != antivirusServerUri) && (!"http".equals(antivirusServerUri.getScheme()) && !"https".equals(antivirusServerUri.getScheme()))) { throw new RuntimeException("Invalid antivirus server URI: " + antivirusServerUri); } @@ -456,10 +481,11 @@ public Builder withAllowHttpConnection() { * - https://www.ssi.gouv.fr/uploads/2017/02/security-recommendations-for-tls_v1.1.pdf * - https://developer.android.com/reference/javax/net/ssl/SSLEngine * - * @param tlsLimitations true to use Tls limitations + * @param tlsLimitations true to use Tls limitations + * @param forceUsageOfTlsVersion set to true for Android < 20 * @return this builder */ - public Builder withTlsLimitations(boolean tlsLimitations) { + public Builder withTlsLimitations(boolean tlsLimitations, boolean forceUsageOfTlsVersion) { if (tlsLimitations) { withShouldAcceptTlsExtensions(false); @@ -467,6 +493,8 @@ public Builder withTlsLimitations(boolean tlsLimitations) { addAcceptedTlsVersion(TlsVersion.TLS_1_2); addAcceptedTlsVersion(TlsVersion.TLS_1_3); + forceUsageOfTlsVersions(forceUsageOfTlsVersion); + // Cipher suites addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256); addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/CertUtil.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/CertUtil.java index 0d0d128d4..85f5b4620 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/CertUtil.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/CertUtil.java @@ -185,13 +185,13 @@ public static Pair newPinnedSSLSocketFactory SSLSocketFactory sslSocketFactory; - if (hsConfig.getAcceptedTlsVersions() == null) { + if (hsConfig.forceUsageOfTlsVersions() && hsConfig.getAcceptedTlsVersions() != null) { + // Force usage of accepted Tls Versions for Android < 20 + sslSocketFactory = new TLSSocketFactory(trustPinned, hsConfig.getAcceptedTlsVersions()); + } else { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustPinned, new java.security.SecureRandom()); sslSocketFactory = sslContext.getSocketFactory(); - } else { - // Force usage of accepted Tls Versions for Android < 20 - sslSocketFactory = new TLSSocketFactory(trustPinned, hsConfig.getAcceptedTlsVersions()); } return new Pair<>(sslSocketFactory, defaultTrustManager); From 3967403631043cd1d421b6b15d67bf09215a0929 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 27 Sep 2018 10:34:44 +0200 Subject: [PATCH 058/236] Update CHANGES.rst --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index e1effb0d1..1ab9bfda8 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -13,6 +13,7 @@ Bugfix: API Change: - A Builder has been added to create HomeServerConnectionConfig instances. + - SentState.UNDELIVERABLE has been renamed to SentState.UNDELIVERED Translations: - From 182cda16b6d9bfa906a5a9ba8a1a787086e92031 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 27 Sep 2018 11:41:05 +0200 Subject: [PATCH 059/236] Extract patterns and corresponding methods from MXSession to a dedicated MXPatterns class It fixes issue on unitary test, because MXSession cannot be loaded in UT due to Olm lib --- CHANGES.rst | 1 + .../org/matrix/androidsdk/MXPatterns.java | 117 ++++++++++++++++++ .../java/org/matrix/androidsdk/MXSession.java | 87 ------------- .../androidsdk/call/MXCallsManager.java | 3 +- .../androidsdk/crypto/MXDeviceList.java | 3 +- .../java/org/matrix/androidsdk/data/Room.java | 7 +- .../androidsdk/groups/GroupsManager.java | 6 +- .../rest/model/CreateRoomParams.java | 4 +- 8 files changed, 131 insertions(+), 97 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java diff --git a/CHANGES.rst b/CHANGES.rst index 1ab9bfda8..8914cd652 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -14,6 +14,7 @@ Bugfix: API Change: - A Builder has been added to create HomeServerConnectionConfig instances. - SentState.UNDELIVERABLE has been renamed to SentState.UNDELIVERED + - Extract patterns and corresponding methods from MXSession to a dedicated MXPatterns class. Translations: - diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java new file mode 100644 index 000000000..c299baaa0 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java @@ -0,0 +1,117 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk; + +import java.util.regex.Pattern; + +/** + * This class contains pattern to match the different Matrix ids + * TODO Add examples of values + */ +public class MXPatterns { + + private MXPatterns() { + // Cannot be instantiated + } + + // regex pattern to find matrix user ids in a string. + // See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids + private static final String MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; + private static final Pattern PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = Pattern.compile(MATRIX_USER_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + + // regex pattern to find room ids in a string. + private static final String MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; + private static final Pattern PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = Pattern.compile(MATRIX_ROOM_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + + // regex pattern to find room aliases in a string. + private static final String MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; + private static final Pattern PATTERN_CONTAIN_MATRIX_ALIAS = Pattern.compile(MATRIX_ROOM_ALIAS_REGEX, Pattern.CASE_INSENSITIVE); + + // regex pattern to find message ids in a string. + private static final String MATRIX_MESSAGE_IDENTIFIER_REGEX = "\\$[A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; + private static final Pattern PATTERN_CONTAIN_MATRIX_MESSAGE_IDENTIFIER = Pattern.compile(MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + + // regex pattern to find group ids in a string. + private static final String MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; + private static final Pattern PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER = Pattern.compile(MATRIX_GROUP_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + + // regex pattern to find permalink with message id. + // Android does not support in URL so extract it. + public static final Pattern PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID + = Pattern.compile("https:\\/\\/matrix\\.to\\/#\\/" + MATRIX_ROOM_IDENTIFIER_REGEX + "\\/" + + MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + public static final Pattern PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS + = Pattern.compile("https:\\/\\/matrix\\.to\\/#\\/" + MATRIX_ROOM_ALIAS_REGEX + "\\/" + + MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + + public static final Pattern PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID + = Pattern.compile("https:\\/\\/[A-Z0-9.-]+\\.[A-Z]{2,}\\/[A-Z]{3,}\\/#\\/room\\/" + MATRIX_ROOM_IDENTIFIER_REGEX + "\\/" + + MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + public static final Pattern PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = + Pattern.compile("https:\\/\\/[A-Z0-9.-]+\\.[A-Z]{2,}\\/[A-Z]{3,}\\/#\\/room\\/" + MATRIX_ROOM_ALIAS_REGEX + "\\/" + + MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + + /** + * Tells if a string is a valid user Id. + * + * @param anUserId the string to test + * @return true if the string is a valid user id + */ + public static boolean isUserId(String anUserId) { + return (null != anUserId) && PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER.matcher(anUserId).matches(); + } + + /** + * Tells if a string is a valid room id. + * + * @param aRoomId the string to test + * @return true if the string is a valid room Id + */ + public static boolean isRoomId(String aRoomId) { + return (null != aRoomId) && PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER.matcher(aRoomId).matches(); + } + + /** + * Tells if a string is a valid room alias. + * + * @param aRoomAlias the string to test + * @return true if the string is a valid room alias. + */ + public static boolean isRoomAlias(String aRoomAlias) { + return (null != aRoomAlias) && PATTERN_CONTAIN_MATRIX_ALIAS.matcher(aRoomAlias).matches(); + } + + /** + * Tells if a string is a valid message id. + * + * @param aMessageId the string to test + * @return true if the string is a valid message id. + */ + public static boolean isMessageId(String aMessageId) { + return (null != aMessageId) && PATTERN_CONTAIN_MATRIX_MESSAGE_IDENTIFIER.matcher(aMessageId).matches(); + } + + /** + * Tells if a string is a valid group id. + * + * @param aGroupId the string to test + * @return true if the string is a valid message id. + */ + public static boolean isGroupId(String aGroupId) { + return (null != aGroupId) && PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER.matcher(aGroupId).matches(); + } +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index d0de37efc..d50cbd152 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -177,43 +177,6 @@ public class MXSession { // load the crypto libs. public static OlmManager mOlmManager = new OlmManager(); - // regex pattern to find matrix user ids in a string. - // See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids - public static final String MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; - public static final Pattern PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = Pattern.compile(MATRIX_USER_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - - // regex pattern to find room aliases in a string. - public static final String MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; - public static final Pattern PATTERN_CONTAIN_MATRIX_ALIAS = Pattern.compile(MATRIX_ROOM_ALIAS_REGEX, Pattern.CASE_INSENSITIVE); - - // regex pattern to find room ids in a string. - public static final String MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; - public static final Pattern PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = Pattern.compile(MATRIX_ROOM_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - - // regex pattern to find message ids in a string. - public static final String MATRIX_MESSAGE_IDENTIFIER_REGEX = "\\$[A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; - public static final Pattern PATTERN_CONTAIN_MATRIX_MESSAGE_IDENTIFIER = Pattern.compile(MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - - // regex pattern to find group ids in a string. - public static final String MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; - public static final Pattern PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER = Pattern.compile(MATRIX_GROUP_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - - // regex pattern to find permalink with message id. - // Android does not support in URL so extract it. - public static final Pattern PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID - = Pattern.compile("https:\\/\\/matrix\\.to\\/#\\/" + MATRIX_ROOM_IDENTIFIER_REGEX + "\\/" - + MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - public static final Pattern PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS - = Pattern.compile("https:\\/\\/matrix\\.to\\/#\\/" + MATRIX_ROOM_ALIAS_REGEX + "\\/" - + MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - - public static final Pattern PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID - = Pattern.compile("https:\\/\\/[A-Z0-9.-]+\\.[A-Z]{2,}\\/[A-Z]{3,}\\/#\\/room\\/" + MATRIX_ROOM_IDENTIFIER_REGEX + "\\/" - + MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - public static final Pattern PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = - Pattern.compile("https:\\/\\/[A-Z0-9.-]+\\.[A-Z]{2,}\\/[A-Z]{3,}\\/#\\/room\\/" + MATRIX_ROOM_ALIAS_REGEX + "\\/" - + MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - /** * Create a basic session for direct API calls. * @@ -2400,56 +2363,6 @@ public void onMatrixError(MatrixError matrixError) { }); } - /** - * Tells if a string is a valid user Id. - * - * @param anUserId the string to test - * @return true if the string is a valid user id - */ - public static boolean isUserId(String anUserId) { - return (null != anUserId) && PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER.matcher(anUserId).matches(); - } - - /** - * Tells if a string is a valid room id. - * - * @param aRoomId the string to test - * @return true if the string is a valid room Id - */ - public static boolean isRoomId(String aRoomId) { - return (null != aRoomId) && PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER.matcher(aRoomId).matches(); - } - - /** - * Tells if a string is a valid room alias. - * - * @param aRoomAlias the string to test - * @return true if the string is a valid room alias. - */ - public static boolean isRoomAlias(String aRoomAlias) { - return (null != aRoomAlias) && PATTERN_CONTAIN_MATRIX_ALIAS.matcher(aRoomAlias).matches(); - } - - /** - * Tells if a string is a valid message id. - * - * @param aMessageId the string to test - * @return true if the string is a valid message id. - */ - public static boolean isMessageId(String aMessageId) { - return (null != aMessageId) && PATTERN_CONTAIN_MATRIX_MESSAGE_IDENTIFIER.matcher(aMessageId).matches(); - } - - /** - * Tells if a string is a valid group id. - * - * @param aGroupId the string to test - * @return true if the string is a valid message id. - */ - public static boolean isGroupId(String aGroupId) { - return (null != aGroupId) && PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER.matcher(aGroupId).matches(); - } - /** * Gets a bearer token from the homeserver that the user can * present to a third party in order to prove their ownership diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java index 3984cb068..98baca925 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java @@ -27,6 +27,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import org.matrix.androidsdk.MXPatterns; import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.crypto.MXCryptoError; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; @@ -1011,7 +1012,7 @@ public static boolean isConferenceUserId(String userId) { if (!TextUtils.isEmpty(userId) && userId.startsWith(prefix) && userId.endsWith(suffix)) { String roomIdBase64 = userId.substring(prefix.length(), userId.length() - suffix.length()); try { - res = MXSession.isRoomId((new String(Base64.decode(roomIdBase64, Base64.NO_WRAP | Base64.URL_SAFE), "UTF-8"))); + res = MXPatterns.isRoomId((new String(Base64.decode(roomIdBase64, Base64.NO_WRAP | Base64.URL_SAFE), "UTF-8"))); } catch (Exception e) { Log.e(LOG_TAG, "isConferenceUserId : failed " + e.getMessage(), e); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXDeviceList.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXDeviceList.java index 62d81dfc3..4905b2691 100755 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXDeviceList.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXDeviceList.java @@ -19,6 +19,7 @@ import android.text.TextUtils; +import org.matrix.androidsdk.MXPatterns; import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXUsersDevicesMap; @@ -174,7 +175,7 @@ private List addDownloadKeysPromise(List userIds, ApiCallback invalidUserIds = new ArrayList<>(); for (String userId : userIds) { - if (MXSession.isUserId(userId)) { + if (MXPatterns.isUserId(userId)) { filteredUserIds.add(userId); } else { Log.e(LOG_TAG, "## userId " + userId + "is not a valid user id"); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index bfa4acc63..2ec765efd 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -39,6 +39,7 @@ import com.google.gson.reflect.TypeToken; import org.matrix.androidsdk.MXDataHandler; +import org.matrix.androidsdk.MXPatterns; import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.call.MXCallsManager; import org.matrix.androidsdk.crypto.MXCryptoError; @@ -1442,7 +1443,7 @@ public boolean sendReadMarkers(final String aReadMarkerEventId, final String aRe String readMarkerEventId = aReadMarkerEventId; if (!TextUtils.isEmpty(aReadMarkerEventId)) { - if (!MXSession.isMessageId(aReadMarkerEventId)) { + if (!MXPatterns.isMessageId(aReadMarkerEventId)) { Log.e(LOG_TAG, "## sendReadMarkers() : invalid event id " + readMarkerEventId); // Read marker is invalid, ignore it readMarkerEventId = null; @@ -1502,8 +1503,8 @@ private void setReadMarkers(final String aReadMarkerEventId, final String aReadR Log.d(LOG_TAG, "## setReadMarkers(): readMarkerEventId " + aReadMarkerEventId + " readReceiptEventId " + aReadMarkerEventId); // check if the message ids are valid - final String readMarkerEventId = MXSession.isMessageId(aReadMarkerEventId) ? aReadMarkerEventId : null; - final String readReceiptEventId = MXSession.isMessageId(aReadReceiptEventId) ? aReadReceiptEventId : null; + final String readMarkerEventId = MXPatterns.isMessageId(aReadMarkerEventId) ? aReadMarkerEventId : null; + final String readReceiptEventId = MXPatterns.isMessageId(aReadReceiptEventId) ? aReadReceiptEventId : null; // if there is nothing to do if (TextUtils.isEmpty(readMarkerEventId) && TextUtils.isEmpty(readReceiptEventId)) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/groups/GroupsManager.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/groups/GroupsManager.java index e87bf5d50..e772f7e0b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/groups/GroupsManager.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/groups/GroupsManager.java @@ -22,7 +22,7 @@ import android.text.TextUtils; import org.matrix.androidsdk.MXDataHandler; -import org.matrix.androidsdk.MXSession; +import org.matrix.androidsdk.MXPatterns; import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.callback.SimpleApiCallback; @@ -566,7 +566,7 @@ public void getUserPublicisedGroups(final String userId, Log.d(LOG_TAG, "## getUserPublicisedGroups() : " + userId); // sanity check - if (!MXSession.isUserId(userId)) { + if (!MXPatterns.isUserId(userId)) { mUIHandler.post(new Runnable() { @Override public void run() { @@ -716,7 +716,7 @@ public void getGroupProfile(final String groupId, final ApiCallback pid.address = id; invite_3pid.add(pid); - } else if (MXSession.isUserId(id)) { + } else if (MXPatterns.isUserId(id)) { // do not invite oneself if (!TextUtils.equals(hsConfig.getCredentials().userId, id)) { if (null == invite) { From 025e5802e78df59de2e8b9df014149fe505740b1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 27 Sep 2018 11:46:01 +0200 Subject: [PATCH 060/236] better code --- .../main/java/org/matrix/androidsdk/MXPatterns.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java index c299baaa0..0e99668e3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java @@ -72,7 +72,7 @@ private MXPatterns() { * @return true if the string is a valid user id */ public static boolean isUserId(String anUserId) { - return (null != anUserId) && PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER.matcher(anUserId).matches(); + return anUserId != null && PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER.matcher(anUserId).matches(); } /** @@ -82,7 +82,7 @@ public static boolean isUserId(String anUserId) { * @return true if the string is a valid room Id */ public static boolean isRoomId(String aRoomId) { - return (null != aRoomId) && PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER.matcher(aRoomId).matches(); + return aRoomId != null && PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER.matcher(aRoomId).matches(); } /** @@ -92,7 +92,7 @@ public static boolean isRoomId(String aRoomId) { * @return true if the string is a valid room alias. */ public static boolean isRoomAlias(String aRoomAlias) { - return (null != aRoomAlias) && PATTERN_CONTAIN_MATRIX_ALIAS.matcher(aRoomAlias).matches(); + return aRoomAlias != null && PATTERN_CONTAIN_MATRIX_ALIAS.matcher(aRoomAlias).matches(); } /** @@ -102,7 +102,7 @@ public static boolean isRoomAlias(String aRoomAlias) { * @return true if the string is a valid message id. */ public static boolean isMessageId(String aMessageId) { - return (null != aMessageId) && PATTERN_CONTAIN_MATRIX_MESSAGE_IDENTIFIER.matcher(aMessageId).matches(); + return aMessageId != null && PATTERN_CONTAIN_MATRIX_MESSAGE_IDENTIFIER.matcher(aMessageId).matches(); } /** @@ -112,6 +112,6 @@ public static boolean isMessageId(String aMessageId) { * @return true if the string is a valid message id. */ public static boolean isGroupId(String aGroupId) { - return (null != aGroupId) && PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER.matcher(aGroupId).matches(); + return aGroupId != null && PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER.matcher(aGroupId).matches(); } } From 6cdb08892b21d76dedac03fd2d3e687e4e491f12 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 27 Sep 2018 12:05:23 +0200 Subject: [PATCH 061/236] Update after integration on Riot --- .../org/matrix/androidsdk/MXPatterns.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java index 0e99668e3..3c54223ca 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java @@ -16,6 +16,8 @@ package org.matrix.androidsdk; +import java.util.Arrays; +import java.util.List; import java.util.regex.Pattern; /** @@ -31,23 +33,23 @@ private MXPatterns() { // regex pattern to find matrix user ids in a string. // See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids private static final String MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; - private static final Pattern PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = Pattern.compile(MATRIX_USER_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + public static final Pattern PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = Pattern.compile(MATRIX_USER_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find room ids in a string. private static final String MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; - private static final Pattern PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = Pattern.compile(MATRIX_ROOM_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + public static final Pattern PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = Pattern.compile(MATRIX_ROOM_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find room aliases in a string. private static final String MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; - private static final Pattern PATTERN_CONTAIN_MATRIX_ALIAS = Pattern.compile(MATRIX_ROOM_ALIAS_REGEX, Pattern.CASE_INSENSITIVE); + public static final Pattern PATTERN_CONTAIN_MATRIX_ALIAS = Pattern.compile(MATRIX_ROOM_ALIAS_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find message ids in a string. private static final String MATRIX_MESSAGE_IDENTIFIER_REGEX = "\\$[A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; - private static final Pattern PATTERN_CONTAIN_MATRIX_MESSAGE_IDENTIFIER = Pattern.compile(MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + public static final Pattern PATTERN_CONTAIN_MATRIX_MESSAGE_IDENTIFIER = Pattern.compile(MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find group ids in a string. private static final String MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; - private static final Pattern PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER = Pattern.compile(MATRIX_GROUP_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + public static final Pattern PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER = Pattern.compile(MATRIX_GROUP_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find permalink with message id. // Android does not support in URL so extract it. @@ -65,6 +67,19 @@ private MXPatterns() { Pattern.compile("https:\\/\\/[A-Z0-9.-]+\\.[A-Z]{2,}\\/[A-Z]{3,}\\/#\\/room\\/" + MATRIX_ROOM_ALIAS_REGEX + "\\/" + MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + // list of patterns to find some matrix item. + public static final List MATRIX_PATTERNS = Arrays.asList( + MXPatterns.PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID, + MXPatterns.PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS, + MXPatterns.PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID, + MXPatterns.PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS, + MXPatterns.PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER, + MXPatterns.PATTERN_CONTAIN_MATRIX_ALIAS, + MXPatterns.PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER, + MXPatterns.PATTERN_CONTAIN_MATRIX_MESSAGE_IDENTIFIER, + MXPatterns.PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER + ); + /** * Tells if a string is a valid user Id. * From f7fd286923b548af13d27ba99de4a0385e52cba9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 27 Sep 2018 12:19:58 +0200 Subject: [PATCH 062/236] Create REGEX constants for clarity --- .../org/matrix/androidsdk/MXPatterns.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java index 3c54223ca..55ced2161 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java @@ -22,7 +22,6 @@ /** * This class contains pattern to match the different Matrix ids - * TODO Add examples of values */ public class MXPatterns { @@ -53,19 +52,21 @@ private MXPatterns() { // regex pattern to find permalink with message id. // Android does not support in URL so extract it. - public static final Pattern PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID - = Pattern.compile("https:\\/\\/matrix\\.to\\/#\\/" + MATRIX_ROOM_IDENTIFIER_REGEX + "\\/" - + MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - public static final Pattern PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS - = Pattern.compile("https:\\/\\/matrix\\.to\\/#\\/" + MATRIX_ROOM_ALIAS_REGEX + "\\/" - + MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - - public static final Pattern PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID - = Pattern.compile("https:\\/\\/[A-Z0-9.-]+\\.[A-Z]{2,}\\/[A-Z]{3,}\\/#\\/room\\/" + MATRIX_ROOM_IDENTIFIER_REGEX + "\\/" - + MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); - public static final Pattern PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = - Pattern.compile("https:\\/\\/[A-Z0-9.-]+\\.[A-Z]{2,}\\/[A-Z]{3,}\\/#\\/room\\/" + MATRIX_ROOM_ALIAS_REGEX + "\\/" - + MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + private static final String PERMALINK_BASE_REGEX = "https:\\/\\/matrix\\.to\\/#\\/"; + private static final String APP_BASE_REGEX = "https:\\/\\/[A-Z0-9.-]+\\.[A-Z]{2,}\\/[A-Z]{3,}\\/#\\/room\\/"; + private static final String SEP_REGEX = "\\/"; + + private static final String LINK_TO_ROOM_ID_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_MESSAGE_IDENTIFIER_REGEX; + public static final Pattern PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE); + + private static final String LINK_TO_ROOM_ALIAS_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_MESSAGE_IDENTIFIER_REGEX; + public static final Pattern PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE); + + private static final String LINK_TO_APP_ROOM_ID_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_MESSAGE_IDENTIFIER_REGEX; + public static final Pattern PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_APP_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE); + + private static final String LINK_TO_APP_ROOM_ALIAS_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_MESSAGE_IDENTIFIER_REGEX; + public static final Pattern PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_APP_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE); // list of patterns to find some matrix item. public static final List MATRIX_PATTERNS = Arrays.asList( From 2d79936ce682705c3d3517998a5f7f83dcdee1ef Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 27 Sep 2018 13:40:12 +0200 Subject: [PATCH 063/236] Rename 'message' to 'event' for ids --- .../org/matrix/androidsdk/MXPatterns.java | 26 +++++++++---------- .../java/org/matrix/androidsdk/data/Room.java | 7 +++-- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java index 55ced2161..8db636904 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java @@ -43,8 +43,8 @@ private MXPatterns() { public static final Pattern PATTERN_CONTAIN_MATRIX_ALIAS = Pattern.compile(MATRIX_ROOM_ALIAS_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find message ids in a string. - private static final String MATRIX_MESSAGE_IDENTIFIER_REGEX = "\\$[A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; - public static final Pattern PATTERN_CONTAIN_MATRIX_MESSAGE_IDENTIFIER = Pattern.compile(MATRIX_MESSAGE_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); + private static final String MATRIX_EVENT_IDENTIFIER_REGEX = "\\$[A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; + public static final Pattern PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER = Pattern.compile(MATRIX_EVENT_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find group ids in a string. private static final String MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; @@ -56,16 +56,16 @@ private MXPatterns() { private static final String APP_BASE_REGEX = "https:\\/\\/[A-Z0-9.-]+\\.[A-Z]{2,}\\/[A-Z]{3,}\\/#\\/room\\/"; private static final String SEP_REGEX = "\\/"; - private static final String LINK_TO_ROOM_ID_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_MESSAGE_IDENTIFIER_REGEX; + private static final String LINK_TO_ROOM_ID_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX; public static final Pattern PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE); - private static final String LINK_TO_ROOM_ALIAS_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_MESSAGE_IDENTIFIER_REGEX; + private static final String LINK_TO_ROOM_ALIAS_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX; public static final Pattern PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE); - private static final String LINK_TO_APP_ROOM_ID_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_MESSAGE_IDENTIFIER_REGEX; + private static final String LINK_TO_APP_ROOM_ID_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX; public static final Pattern PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_APP_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE); - private static final String LINK_TO_APP_ROOM_ALIAS_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_MESSAGE_IDENTIFIER_REGEX; + private static final String LINK_TO_APP_ROOM_ALIAS_REGEXP = APP_BASE_REGEX + MATRIX_ROOM_ALIAS_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX; public static final Pattern PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS = Pattern.compile(LINK_TO_APP_ROOM_ALIAS_REGEXP, Pattern.CASE_INSENSITIVE); // list of patterns to find some matrix item. @@ -77,7 +77,7 @@ private MXPatterns() { MXPatterns.PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER, MXPatterns.PATTERN_CONTAIN_MATRIX_ALIAS, MXPatterns.PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER, - MXPatterns.PATTERN_CONTAIN_MATRIX_MESSAGE_IDENTIFIER, + MXPatterns.PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER, MXPatterns.PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER ); @@ -112,20 +112,20 @@ public static boolean isRoomAlias(String aRoomAlias) { } /** - * Tells if a string is a valid message id. + * Tells if a string is a valid event id. * - * @param aMessageId the string to test - * @return true if the string is a valid message id. + * @param aEventId the string to test + * @return true if the string is a valid event id. */ - public static boolean isMessageId(String aMessageId) { - return aMessageId != null && PATTERN_CONTAIN_MATRIX_MESSAGE_IDENTIFIER.matcher(aMessageId).matches(); + public static boolean isEventId(String aEventId) { + return aEventId != null && PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER.matcher(aEventId).matches(); } /** * Tells if a string is a valid group id. * * @param aGroupId the string to test - * @return true if the string is a valid message id. + * @return true if the string is a valid group id. */ public static boolean isGroupId(String aGroupId) { return aGroupId != null && PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER.matcher(aGroupId).matches(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 2ec765efd..478c6407f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -40,7 +40,6 @@ import org.matrix.androidsdk.MXDataHandler; import org.matrix.androidsdk.MXPatterns; -import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.call.MXCallsManager; import org.matrix.androidsdk.crypto.MXCryptoError; import org.matrix.androidsdk.crypto.data.MXEncryptEventContentResult; @@ -1443,7 +1442,7 @@ public boolean sendReadMarkers(final String aReadMarkerEventId, final String aRe String readMarkerEventId = aReadMarkerEventId; if (!TextUtils.isEmpty(aReadMarkerEventId)) { - if (!MXPatterns.isMessageId(aReadMarkerEventId)) { + if (!MXPatterns.isEventId(aReadMarkerEventId)) { Log.e(LOG_TAG, "## sendReadMarkers() : invalid event id " + readMarkerEventId); // Read marker is invalid, ignore it readMarkerEventId = null; @@ -1503,8 +1502,8 @@ private void setReadMarkers(final String aReadMarkerEventId, final String aReadR Log.d(LOG_TAG, "## setReadMarkers(): readMarkerEventId " + aReadMarkerEventId + " readReceiptEventId " + aReadMarkerEventId); // check if the message ids are valid - final String readMarkerEventId = MXPatterns.isMessageId(aReadMarkerEventId) ? aReadMarkerEventId : null; - final String readReceiptEventId = MXPatterns.isMessageId(aReadReceiptEventId) ? aReadReceiptEventId : null; + final String readMarkerEventId = MXPatterns.isEventId(aReadMarkerEventId) ? aReadMarkerEventId : null; + final String readReceiptEventId = MXPatterns.isEventId(aReadReceiptEventId) ? aReadReceiptEventId : null; // if there is nothing to do if (TextUtils.isEmpty(readMarkerEventId) && TextUtils.isEmpty(readReceiptEventId)) { From 60a513b8ca4690aaf24eedecc5fcadf5c569994f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 27 Sep 2018 18:17:34 +0200 Subject: [PATCH 064/236] Fix crash on Android <= 19: do not enable TLS1.3 --- .../androidsdk/ssl/TLSSocketFactory.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java index fb73a023c..1c0147a9e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java @@ -16,6 +16,8 @@ package org.matrix.androidsdk.ssl; +import org.matrix.androidsdk.util.Log; + import java.io.IOException; import java.net.InetAddress; import java.net.Socket; @@ -23,6 +25,8 @@ import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.net.ssl.SSLContext; @@ -37,6 +41,7 @@ * Inspired from https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/ */ /*package*/ class TLSSocketFactory extends SSLSocketFactory { + private static final String LOG_TAG = TLSSocketFactory.class.getSimpleName(); private SSLSocketFactory internalSSLSocketFactory; @@ -105,7 +110,24 @@ public Socket createSocket(InetAddress address, int port, InetAddress localAddre private Socket enableTLSOnSocket(Socket socket) { if (socket != null && (socket instanceof SSLSocket)) { - ((SSLSocket) socket).setEnabledProtocols(enabledProtocol); + SSLSocket sslSocket = (SSLSocket) socket; + + List supportedProtocols = Arrays.asList(sslSocket.getSupportedProtocols()); + List filteredEnabledProtocols = new ArrayList<>(); + + for (String protocol : enabledProtocol) { + if (supportedProtocols.contains(protocol)) { + filteredEnabledProtocols.add(protocol); + } + } + + if (!filteredEnabledProtocols.isEmpty()) { + try { + sslSocket.setEnabledProtocols(filteredEnabledProtocols.toArray(new String[filteredEnabledProtocols.size()])); + } catch (Exception e) { + Log.e(LOG_TAG, "Exception: ", e); + } + } } return socket; } From 19ad63760fea8eea16dbbeb049f0980ae200d4a1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 28 Sep 2018 10:24:22 +0200 Subject: [PATCH 065/236] better name --- .../java/org/matrix/androidsdk/ssl/TLSSocketFactory.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java index 1c0147a9e..8aa75434d 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/ssl/TLSSocketFactory.java @@ -45,7 +45,7 @@ private SSLSocketFactory internalSSLSocketFactory; - private String[] enabledProtocol; + private String[] enabledProtocols; /** * Constructor @@ -60,10 +60,10 @@ context.init(null, trustPinned, new SecureRandom()); internalSSLSocketFactory = context.getSocketFactory(); - enabledProtocol = new String[acceptedTlsVersions.size()]; + enabledProtocols = new String[acceptedTlsVersions.size()]; int i = 0; for (TlsVersion tlsVersion : acceptedTlsVersions) { - enabledProtocol[i] = tlsVersion.javaName(); + enabledProtocols[i] = tlsVersion.javaName(); i++; } } @@ -115,7 +115,7 @@ private Socket enableTLSOnSocket(Socket socket) { List supportedProtocols = Arrays.asList(sslSocket.getSupportedProtocols()); List filteredEnabledProtocols = new ArrayList<>(); - for (String protocol : enabledProtocol) { + for (String protocol : enabledProtocols) { if (supportedProtocols.contains(protocol)) { filteredEnabledProtocols.add(protocol); } From 08a6cbbc9322674a1bcc64955d8acf42761955e3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 28 Sep 2018 10:29:40 +0200 Subject: [PATCH 066/236] rename parameters --- .../org/matrix/androidsdk/MXPatterns.java | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java index 8db636904..74fd0f6f6 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java @@ -16,6 +16,8 @@ package org.matrix.androidsdk; +import android.support.annotation.Nullable; + import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; @@ -84,50 +86,50 @@ private MXPatterns() { /** * Tells if a string is a valid user Id. * - * @param anUserId the string to test + * @param str the string to test * @return true if the string is a valid user id */ - public static boolean isUserId(String anUserId) { - return anUserId != null && PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER.matcher(anUserId).matches(); + public static boolean isUserId(@Nullable final String str) { + return str != null && PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER.matcher(str).matches(); } /** * Tells if a string is a valid room id. * - * @param aRoomId the string to test + * @param str the string to test * @return true if the string is a valid room Id */ - public static boolean isRoomId(String aRoomId) { - return aRoomId != null && PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER.matcher(aRoomId).matches(); + public static boolean isRoomId(@Nullable final String str) { + return str != null && PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER.matcher(str).matches(); } /** * Tells if a string is a valid room alias. * - * @param aRoomAlias the string to test + * @param str the string to test * @return true if the string is a valid room alias. */ - public static boolean isRoomAlias(String aRoomAlias) { - return aRoomAlias != null && PATTERN_CONTAIN_MATRIX_ALIAS.matcher(aRoomAlias).matches(); + public static boolean isRoomAlias(@Nullable final String str) { + return str != null && PATTERN_CONTAIN_MATRIX_ALIAS.matcher(str).matches(); } /** * Tells if a string is a valid event id. * - * @param aEventId the string to test + * @param str the string to test * @return true if the string is a valid event id. */ - public static boolean isEventId(String aEventId) { - return aEventId != null && PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER.matcher(aEventId).matches(); + public static boolean isEventId(@Nullable final String str) { + return str != null && PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER.matcher(str).matches(); } /** * Tells if a string is a valid group id. * - * @param aGroupId the string to test + * @param str the string to test * @return true if the string is a valid group id. */ - public static boolean isGroupId(String aGroupId) { - return aGroupId != null && PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER.matcher(aGroupId).matches(); + public static boolean isGroupId(@Nullable final String str) { + return str != null && PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER.matcher(str).matches(); } } From 5237435bde699d1619a53f76e976de576bd7455a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 28 Sep 2018 11:11:26 +0200 Subject: [PATCH 067/236] remove unnecessary escaping in REGEX --- .../java/org/matrix/androidsdk/MXPatterns.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java index 74fd0f6f6..526835971 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java @@ -33,30 +33,30 @@ private MXPatterns() { // regex pattern to find matrix user ids in a string. // See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids - private static final String MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; + private static final String MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(:[0-9]{2,})?"; public static final Pattern PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = Pattern.compile(MATRIX_USER_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find room ids in a string. - private static final String MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; + private static final String MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(:[0-9]{2,})?"; public static final Pattern PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = Pattern.compile(MATRIX_ROOM_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find room aliases in a string. - private static final String MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; + private static final String MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(:[0-9]{2,})?"; public static final Pattern PATTERN_CONTAIN_MATRIX_ALIAS = Pattern.compile(MATRIX_ROOM_ALIAS_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find message ids in a string. - private static final String MATRIX_EVENT_IDENTIFIER_REGEX = "\\$[A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; + private static final String MATRIX_EVENT_IDENTIFIER_REGEX = "\\$[A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(:[0-9]{2,})?"; public static final Pattern PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER = Pattern.compile(MATRIX_EVENT_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find group ids in a string. - private static final String MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(\\:[0-9]{2,})?"; + private static final String MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(:[0-9]{2,})?"; public static final Pattern PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER = Pattern.compile(MATRIX_GROUP_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find permalink with message id. // Android does not support in URL so extract it. - private static final String PERMALINK_BASE_REGEX = "https:\\/\\/matrix\\.to\\/#\\/"; - private static final String APP_BASE_REGEX = "https:\\/\\/[A-Z0-9.-]+\\.[A-Z]{2,}\\/[A-Z]{3,}\\/#\\/room\\/"; - private static final String SEP_REGEX = "\\/"; + private static final String PERMALINK_BASE_REGEX = "https://matrix\\.to/#/"; + private static final String APP_BASE_REGEX = "https://[A-Z0-9.-]+\\.[A-Z]{2,}/[A-Z]{3,}/#/room/"; + private static final String SEP_REGEX = "/"; private static final String LINK_TO_ROOM_ID_REGEXP = PERMALINK_BASE_REGEX + MATRIX_ROOM_IDENTIFIER_REGEX + SEP_REGEX + MATRIX_EVENT_IDENTIFIER_REGEX; public static final Pattern PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID = Pattern.compile(LINK_TO_ROOM_ID_REGEXP, Pattern.CASE_INSENSITIVE); From dbfd078658b2d63c9328e2b9f92132508f6ed04c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 28 Sep 2018 11:23:46 +0200 Subject: [PATCH 068/236] Write some tests --- .../org/matrix/androidsdk/TestMxPatterns.java | 229 ++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java new file mode 100644 index 000000000..f7031fd30 --- /dev/null +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java @@ -0,0 +1,229 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk; + +import junit.framework.Assert; + +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import java.util.Arrays; +import java.util.List; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestMxPatterns { + + private static final List validUserIds = Arrays.asList( + "@benoit:matrix.org", + "@benoit:matrix.org:1234" + ); + + private static final List validRoomIds = Arrays.asList( + "!fLXbhWnqiSoyBfgGgb:matrix.org", + "!fLXbhWnqiSoyBfgGgb:matrix.org:1234" + ); + + private static final List validRoomAliasIds = Arrays.asList( + "#linux:matrix.org", + "#linux:matrix.org:1234", + // Room alias can contain special char: ._%#@=+- + "#linux._%#@=+-:matrix.org:1234" + ); + + private static final List validEventIds = Arrays.asList( + "$1536732077213115wbNdt:matrix.org", + "$1536732077213115wbNdt:matrix.org:1234" + ); + + private static final List validGroupIds = Arrays.asList( + "+matrix:matrix.org", + "+matrix:matrix.org:1234", + // Group id special char + "+matrix=_-./:matrix.org:1234" + + ); + + /* ========================================================================================== + * Common error cases + * ========================================================================================== */ + + @Test + public void MxPatterns_common_error_null() { + testAllFalse(null); + } + + @Test + public void MxPatterns_common_error_empty() { + testAllFalse(""); + } + + @Test + public void MxPatterns_common_error_invalid() { + testAllFalse("a"); + testAllFalse("1"); + testAllFalse("test@example.org"); + testAllFalse("https://www.example.org"); + testAllFalse("benoit:matrix.org"); + } + + /* ========================================================================================== + * Common valid cases + * ========================================================================================== */ + + @Test + public void MxPatterns_common_ok() { + testAllTrueWithCorrectPrefix("id:matrix.org"); + testAllTrueWithCorrectPrefix("id:matrix.org:80"); + testAllTrueWithCorrectPrefix("id:matrix.org:808"); + testAllTrueWithCorrectPrefix("id:matrix.org:8080"); + } + + /* ========================================================================================== + * Common error cases using correct prefix + * ========================================================================================== */ + + @Test + public void MxPatterns_common_error_invalidChars() { + testAllFalseWithCorrectPrefix("idé:matrix.org"); + testAllFalseWithCorrectPrefix("id :matrix.org"); + } + + @Test + public void MxPatterns_common_error_noTwoPoint() { + testAllFalseWithCorrectPrefix("idmatrix.org"); + } + + @Test + public void MxPatterns_common_error_noId() { + testAllFalseWithCorrectPrefix(":matrix.org"); + } + + @Test + public void MxPatterns_common_error_noDomain() { + testAllFalseWithCorrectPrefix("id:.org"); + } + + @Test + public void MxPatterns_common_error_noTld() { + testAllFalseWithCorrectPrefix("id:matrix"); + testAllFalseWithCorrectPrefix("id:matrix."); + } + + @Test + public void MxPatterns_common_error_bad_port() { + testAllFalseWithCorrectPrefix("id:matrix.org:"); + testAllFalseWithCorrectPrefix("id:matrix.org:8"); + testAllFalseWithCorrectPrefix("id:matrix.org:abc"); + testAllFalseWithCorrectPrefix("id:matrix.org:8080a"); + } + + /* ========================================================================================== + * Valid cases + * ========================================================================================== */ + + @Test + public void MxPatterns_userId_ok() { + for (String value : validUserIds) { + Assert.assertTrue(MXPatterns.isUserId(value)); + + Assert.assertFalse(MXPatterns.isRoomId(value)); + Assert.assertFalse(MXPatterns.isRoomAlias(value)); + Assert.assertFalse(MXPatterns.isEventId(value)); + Assert.assertFalse(MXPatterns.isGroupId(value)); + } + } + + @Test + public void MxPatterns_roomId_ok() { + for (String value : validRoomIds) { + Assert.assertFalse(MXPatterns.isUserId(value)); + + Assert.assertTrue(MXPatterns.isRoomId(value)); + + Assert.assertFalse(MXPatterns.isRoomAlias(value)); + Assert.assertFalse(MXPatterns.isEventId(value)); + Assert.assertFalse(MXPatterns.isGroupId(value)); + } + } + + @Test + public void MxPatterns_roomAlias_ok() { + for (String value : validRoomAliasIds) { + Assert.assertFalse(MXPatterns.isUserId(value)); + Assert.assertFalse(MXPatterns.isRoomId(value)); + + Assert.assertTrue(MXPatterns.isRoomAlias(value)); + + Assert.assertFalse(MXPatterns.isEventId(value)); + Assert.assertFalse(MXPatterns.isGroupId(value)); + } + } + + @Test + public void MxPatterns_eventId_ok() { + for (String value : validEventIds) { + Assert.assertFalse(MXPatterns.isUserId(value)); + Assert.assertFalse(MXPatterns.isRoomId(value)); + Assert.assertFalse(MXPatterns.isRoomAlias(value)); + + Assert.assertTrue(MXPatterns.isEventId(value)); + + Assert.assertFalse(MXPatterns.isGroupId(value)); + } + } + + @Test + public void MxPatterns_groupId_ok() { + for (String value : validGroupIds) { + Assert.assertFalse(MXPatterns.isUserId(value)); + Assert.assertFalse(MXPatterns.isRoomId(value)); + Assert.assertFalse(MXPatterns.isRoomAlias(value)); + Assert.assertFalse(MXPatterns.isEventId(value)); + + Assert.assertTrue(MXPatterns.isGroupId(value)); + } + } + + /* ========================================================================================== + * Private methods + * ========================================================================================== */ + + private void testAllTrueWithCorrectPrefix(String value) { + Assert.assertTrue(MXPatterns.isUserId("@" + value)); + Assert.assertTrue(MXPatterns.isRoomId("!" + value)); + Assert.assertTrue(MXPatterns.isRoomAlias("#" + value)); + Assert.assertTrue(MXPatterns.isEventId("$" + value)); + Assert.assertTrue(MXPatterns.isGroupId("+" + value)); + } + + private void testAllFalseWithCorrectPrefix(String value) { + testAllFalse("@" + value); + testAllFalse("!" + value); + testAllFalse("#" + value); + testAllFalse("$" + value); + testAllFalse("+" + value); + } + + private void testAllFalse(String value) { + Assert.assertFalse(MXPatterns.isUserId(value)); + Assert.assertFalse(MXPatterns.isRoomId(value)); + Assert.assertFalse(MXPatterns.isRoomAlias(value)); + Assert.assertFalse(MXPatterns.isEventId(value)); + Assert.assertFalse(MXPatterns.isGroupId(value)); + } +} From 20e32b9c2a02eeb7238ada278cc253597f315905 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 28 Sep 2018 11:29:57 +0200 Subject: [PATCH 069/236] Avoid duplication of String part --- .../main/java/org/matrix/androidsdk/MXPatterns.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java index 526835971..91006ff40 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java @@ -31,25 +31,27 @@ private MXPatterns() { // Cannot be instantiated } + private static final String DOMAIN_REGEX = ":[A-Z0-9.-]+(\\.[A-Z]{2,})?+(:[0-9]{2,})?"; + // regex pattern to find matrix user ids in a string. // See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids - private static final String MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(:[0-9]{2,})?"; + private static final String MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+" + DOMAIN_REGEX; public static final Pattern PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = Pattern.compile(MATRIX_USER_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find room ids in a string. - private static final String MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(:[0-9]{2,})?"; + private static final String MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+" + DOMAIN_REGEX; public static final Pattern PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER = Pattern.compile(MATRIX_ROOM_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find room aliases in a string. - private static final String MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(:[0-9]{2,})?"; + private static final String MATRIX_ROOM_ALIAS_REGEX = "#[A-Z0-9._%#@=+-]+" + DOMAIN_REGEX; public static final Pattern PATTERN_CONTAIN_MATRIX_ALIAS = Pattern.compile(MATRIX_ROOM_ALIAS_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find message ids in a string. - private static final String MATRIX_EVENT_IDENTIFIER_REGEX = "\\$[A-Z0-9]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(:[0-9]{2,})?"; + private static final String MATRIX_EVENT_IDENTIFIER_REGEX = "\\$[A-Z0-9]+" + DOMAIN_REGEX; public static final Pattern PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER = Pattern.compile(MATRIX_EVENT_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find group ids in a string. - private static final String MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+:[A-Z0-9.-]+(\\.[A-Z]{2,})?+(:[0-9]{2,})?"; + private static final String MATRIX_GROUP_IDENTIFIER_REGEX = "\\+[A-Z0-9=_\\-./]+" + DOMAIN_REGEX; public static final Pattern PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER = Pattern.compile(MATRIX_GROUP_IDENTIFIER_REGEX, Pattern.CASE_INSENSITIVE); // regex pattern to find permalink with message id. From 10b1d7445ecb5b7e56c29d33975d40eaf8f5adea Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 28 Sep 2018 11:42:44 +0200 Subject: [PATCH 070/236] Add tests --- .../org/matrix/androidsdk/MXPatterns.java | 1 + .../org/matrix/androidsdk/TestMxPatterns.java | 27 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java index 91006ff40..435baf504 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java @@ -31,6 +31,7 @@ private MXPatterns() { // Cannot be instantiated } + // Note: TLD is not mandatory (localhost, IP address...) private static final String DOMAIN_REGEX = ":[A-Z0-9.-]+(\\.[A-Z]{2,})?+(:[0-9]{2,})?"; // regex pattern to find matrix user ids in a string. diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java index f7031fd30..f4631e296 100644 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java @@ -73,7 +73,7 @@ public void MxPatterns_common_error_empty() { } @Test - public void MxPatterns_common_error_invalid() { + public void MxPatterns_common_error_invalidPrefix() { testAllFalse("a"); testAllFalse("1"); testAllFalse("test@example.org"); @@ -93,6 +93,28 @@ public void MxPatterns_common_ok() { testAllTrueWithCorrectPrefix("id:matrix.org:8080"); } + @Test + public void MxPatterns_common_ok_dash() { + testAllTrueWithCorrectPrefix("id:matrix-new.org"); + testAllTrueWithCorrectPrefix("id:matrix-new.org:80"); + testAllTrueWithCorrectPrefix("id:matrix-new.org:808"); + testAllTrueWithCorrectPrefix("id:matrix-new.org:8080"); + } + + @Test + public void MxPatterns_common_ok_localhost() { + testAllTrueWithCorrectPrefix("id:localhost"); + testAllTrueWithCorrectPrefix("id:localhost:8080"); + } + + @Test + public void MxPatterns_common_ok_ipAddress() { + testAllTrueWithCorrectPrefix("id:1.1.1.1"); + testAllTrueWithCorrectPrefix("id:1.1.1.1:8080"); + testAllTrueWithCorrectPrefix("id:888.888.888.888"); + testAllTrueWithCorrectPrefix("id:888.888.888.888:8080"); + } + /* ========================================================================================== * Common error cases using correct prefix * ========================================================================================== */ @@ -120,7 +142,8 @@ public void MxPatterns_common_error_noDomain() { @Test public void MxPatterns_common_error_noTld() { - testAllFalseWithCorrectPrefix("id:matrix"); + // Tld is not mandatory + // testAllFalseWithCorrectPrefix("id:matrix"); testAllFalseWithCorrectPrefix("id:matrix."); } From 94a60b6209cbaab8e75f7dfb406e014c952c1c95 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 28 Sep 2018 11:47:20 +0200 Subject: [PATCH 071/236] Remove the TDL part from REGEX, because it is useless (already covered by the first part of the REGEX) --- .../java/org/matrix/androidsdk/MXPatterns.java | 2 +- .../java/org/matrix/androidsdk/TestMxPatterns.java | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java index 435baf504..5f0f43c0b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXPatterns.java @@ -32,7 +32,7 @@ private MXPatterns() { } // Note: TLD is not mandatory (localhost, IP address...) - private static final String DOMAIN_REGEX = ":[A-Z0-9.-]+(\\.[A-Z]{2,})?+(:[0-9]{2,})?"; + private static final String DOMAIN_REGEX = ":[A-Z0-9.-]+(:[0-9]{2,5})?"; // regex pattern to find matrix user ids in a string. // See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java index f4631e296..e38deaade 100644 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java @@ -91,6 +91,7 @@ public void MxPatterns_common_ok() { testAllTrueWithCorrectPrefix("id:matrix.org:80"); testAllTrueWithCorrectPrefix("id:matrix.org:808"); testAllTrueWithCorrectPrefix("id:matrix.org:8080"); + testAllTrueWithCorrectPrefix("id:matrix.org:65535"); } @Test @@ -99,12 +100,14 @@ public void MxPatterns_common_ok_dash() { testAllTrueWithCorrectPrefix("id:matrix-new.org:80"); testAllTrueWithCorrectPrefix("id:matrix-new.org:808"); testAllTrueWithCorrectPrefix("id:matrix-new.org:8080"); + testAllTrueWithCorrectPrefix("id:matrix-new.org:65535"); } @Test public void MxPatterns_common_ok_localhost() { testAllTrueWithCorrectPrefix("id:localhost"); testAllTrueWithCorrectPrefix("id:localhost:8080"); + testAllTrueWithCorrectPrefix("id:localhost:65535"); } @Test @@ -113,6 +116,7 @@ public void MxPatterns_common_ok_ipAddress() { testAllTrueWithCorrectPrefix("id:1.1.1.1:8080"); testAllTrueWithCorrectPrefix("id:888.888.888.888"); testAllTrueWithCorrectPrefix("id:888.888.888.888:8080"); + testAllTrueWithCorrectPrefix("id:888.888.888.888:65535"); } /* ========================================================================================== @@ -137,14 +141,7 @@ public void MxPatterns_common_error_noId() { @Test public void MxPatterns_common_error_noDomain() { - testAllFalseWithCorrectPrefix("id:.org"); - } - - @Test - public void MxPatterns_common_error_noTld() { - // Tld is not mandatory - // testAllFalseWithCorrectPrefix("id:matrix"); - testAllFalseWithCorrectPrefix("id:matrix."); + testAllFalseWithCorrectPrefix("id:"); } @Test @@ -153,6 +150,7 @@ public void MxPatterns_common_error_bad_port() { testAllFalseWithCorrectPrefix("id:matrix.org:8"); testAllFalseWithCorrectPrefix("id:matrix.org:abc"); testAllFalseWithCorrectPrefix("id:matrix.org:8080a"); + testAllFalseWithCorrectPrefix("id:matrix.org:808080"); } /* ========================================================================================== From 3d4c62c3b6c1a64b39c7cec55f0eda694833901e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 28 Sep 2018 11:54:08 +0200 Subject: [PATCH 072/236] Add test --- .../org/matrix/androidsdk/TestMxPatterns.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java index e38deaade..2a10f4856 100644 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java @@ -124,28 +124,33 @@ public void MxPatterns_common_ok_ipAddress() { * ========================================================================================== */ @Test - public void MxPatterns_common_error_invalidChars() { + public void MxPatterns_common_error_with_prefix_invalidChars() { testAllFalseWithCorrectPrefix("idé:matrix.org"); testAllFalseWithCorrectPrefix("id :matrix.org"); } @Test - public void MxPatterns_common_error_noTwoPoint() { + public void MxPatterns_common_error_with_prefix_empty() { + testAllFalseWithCorrectPrefix(""); + } + + @Test + public void MxPatterns_common_error_with_prefix_noTwoPoint() { testAllFalseWithCorrectPrefix("idmatrix.org"); } @Test - public void MxPatterns_common_error_noId() { + public void MxPatterns_common_error_with_prefix_noId() { testAllFalseWithCorrectPrefix(":matrix.org"); } @Test - public void MxPatterns_common_error_noDomain() { + public void MxPatterns_common_error_with_prefix_noDomain() { testAllFalseWithCorrectPrefix("id:"); } @Test - public void MxPatterns_common_error_bad_port() { + public void MxPatterns_common_error_with_prefix_bad_port() { testAllFalseWithCorrectPrefix("id:matrix.org:"); testAllFalseWithCorrectPrefix("id:matrix.org:8"); testAllFalseWithCorrectPrefix("id:matrix.org:abc"); From d640cc04dc090004d98eff9a59f195396046a128 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 28 Sep 2018 12:01:16 +0200 Subject: [PATCH 073/236] Rename class, else the test will not be executer by `gradlew test` --- .../androidsdk/{TestMxPatterns.java => MxPatternsTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename matrix-sdk/src/test/java/org/matrix/androidsdk/{TestMxPatterns.java => MxPatternsTest.java} (99%) diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/MxPatternsTest.java similarity index 99% rename from matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java rename to matrix-sdk/src/test/java/org/matrix/androidsdk/MxPatternsTest.java index 2a10f4856..5dcf9df2f 100644 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestMxPatterns.java +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/MxPatternsTest.java @@ -26,7 +26,7 @@ import java.util.List; @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class TestMxPatterns { +public class MxPatternsTest { private static final List validUserIds = Arrays.asList( "@benoit:matrix.org", From b1f7ea1690faa5fcc4ca020dccb7f7e8204aa00e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 28 Sep 2018 12:04:40 +0200 Subject: [PATCH 074/236] Rename private methods --- .../org/matrix/androidsdk/MxPatternsTest.java | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/MxPatternsTest.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/MxPatternsTest.java index 5dcf9df2f..5b88ffd69 100644 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/MxPatternsTest.java +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/MxPatternsTest.java @@ -64,21 +64,21 @@ public class MxPatternsTest { @Test public void MxPatterns_common_error_null() { - testAllFalse(null); + assertAllFalse(null); } @Test public void MxPatterns_common_error_empty() { - testAllFalse(""); + assertAllFalse(""); } @Test public void MxPatterns_common_error_invalidPrefix() { - testAllFalse("a"); - testAllFalse("1"); - testAllFalse("test@example.org"); - testAllFalse("https://www.example.org"); - testAllFalse("benoit:matrix.org"); + assertAllFalse("a"); + assertAllFalse("1"); + assertAllFalse("test@example.org"); + assertAllFalse("https://www.example.org"); + assertAllFalse("benoit:matrix.org"); } /* ========================================================================================== @@ -87,36 +87,36 @@ public void MxPatterns_common_error_invalidPrefix() { @Test public void MxPatterns_common_ok() { - testAllTrueWithCorrectPrefix("id:matrix.org"); - testAllTrueWithCorrectPrefix("id:matrix.org:80"); - testAllTrueWithCorrectPrefix("id:matrix.org:808"); - testAllTrueWithCorrectPrefix("id:matrix.org:8080"); - testAllTrueWithCorrectPrefix("id:matrix.org:65535"); + assertAllTrueWithCorrectPrefix("id:matrix.org"); + assertAllTrueWithCorrectPrefix("id:matrix.org:80"); + assertAllTrueWithCorrectPrefix("id:matrix.org:808"); + assertAllTrueWithCorrectPrefix("id:matrix.org:8080"); + assertAllTrueWithCorrectPrefix("id:matrix.org:65535"); } @Test public void MxPatterns_common_ok_dash() { - testAllTrueWithCorrectPrefix("id:matrix-new.org"); - testAllTrueWithCorrectPrefix("id:matrix-new.org:80"); - testAllTrueWithCorrectPrefix("id:matrix-new.org:808"); - testAllTrueWithCorrectPrefix("id:matrix-new.org:8080"); - testAllTrueWithCorrectPrefix("id:matrix-new.org:65535"); + assertAllTrueWithCorrectPrefix("id:matrix-new.org"); + assertAllTrueWithCorrectPrefix("id:matrix-new.org:80"); + assertAllTrueWithCorrectPrefix("id:matrix-new.org:808"); + assertAllTrueWithCorrectPrefix("id:matrix-new.org:8080"); + assertAllTrueWithCorrectPrefix("id:matrix-new.org:65535"); } @Test public void MxPatterns_common_ok_localhost() { - testAllTrueWithCorrectPrefix("id:localhost"); - testAllTrueWithCorrectPrefix("id:localhost:8080"); - testAllTrueWithCorrectPrefix("id:localhost:65535"); + assertAllTrueWithCorrectPrefix("id:localhost"); + assertAllTrueWithCorrectPrefix("id:localhost:8080"); + assertAllTrueWithCorrectPrefix("id:localhost:65535"); } @Test public void MxPatterns_common_ok_ipAddress() { - testAllTrueWithCorrectPrefix("id:1.1.1.1"); - testAllTrueWithCorrectPrefix("id:1.1.1.1:8080"); - testAllTrueWithCorrectPrefix("id:888.888.888.888"); - testAllTrueWithCorrectPrefix("id:888.888.888.888:8080"); - testAllTrueWithCorrectPrefix("id:888.888.888.888:65535"); + assertAllTrueWithCorrectPrefix("id:1.1.1.1"); + assertAllTrueWithCorrectPrefix("id:1.1.1.1:8080"); + assertAllTrueWithCorrectPrefix("id:888.888.888.888"); + assertAllTrueWithCorrectPrefix("id:888.888.888.888:8080"); + assertAllTrueWithCorrectPrefix("id:888.888.888.888:65535"); } /* ========================================================================================== @@ -125,37 +125,37 @@ public void MxPatterns_common_ok_ipAddress() { @Test public void MxPatterns_common_error_with_prefix_invalidChars() { - testAllFalseWithCorrectPrefix("idé:matrix.org"); - testAllFalseWithCorrectPrefix("id :matrix.org"); + assertAllFalseWithCorrectPrefix("idé:matrix.org"); + assertAllFalseWithCorrectPrefix("id :matrix.org"); } @Test public void MxPatterns_common_error_with_prefix_empty() { - testAllFalseWithCorrectPrefix(""); + assertAllFalseWithCorrectPrefix(""); } @Test public void MxPatterns_common_error_with_prefix_noTwoPoint() { - testAllFalseWithCorrectPrefix("idmatrix.org"); + assertAllFalseWithCorrectPrefix("idmatrix.org"); } @Test public void MxPatterns_common_error_with_prefix_noId() { - testAllFalseWithCorrectPrefix(":matrix.org"); + assertAllFalseWithCorrectPrefix(":matrix.org"); } @Test public void MxPatterns_common_error_with_prefix_noDomain() { - testAllFalseWithCorrectPrefix("id:"); + assertAllFalseWithCorrectPrefix("id:"); } @Test public void MxPatterns_common_error_with_prefix_bad_port() { - testAllFalseWithCorrectPrefix("id:matrix.org:"); - testAllFalseWithCorrectPrefix("id:matrix.org:8"); - testAllFalseWithCorrectPrefix("id:matrix.org:abc"); - testAllFalseWithCorrectPrefix("id:matrix.org:8080a"); - testAllFalseWithCorrectPrefix("id:matrix.org:808080"); + assertAllFalseWithCorrectPrefix("id:matrix.org:"); + assertAllFalseWithCorrectPrefix("id:matrix.org:8"); + assertAllFalseWithCorrectPrefix("id:matrix.org:abc"); + assertAllFalseWithCorrectPrefix("id:matrix.org:8080a"); + assertAllFalseWithCorrectPrefix("id:matrix.org:808080"); } /* ========================================================================================== @@ -229,7 +229,7 @@ public void MxPatterns_groupId_ok() { * Private methods * ========================================================================================== */ - private void testAllTrueWithCorrectPrefix(String value) { + private void assertAllTrueWithCorrectPrefix(String value) { Assert.assertTrue(MXPatterns.isUserId("@" + value)); Assert.assertTrue(MXPatterns.isRoomId("!" + value)); Assert.assertTrue(MXPatterns.isRoomAlias("#" + value)); @@ -237,15 +237,15 @@ private void testAllTrueWithCorrectPrefix(String value) { Assert.assertTrue(MXPatterns.isGroupId("+" + value)); } - private void testAllFalseWithCorrectPrefix(String value) { - testAllFalse("@" + value); - testAllFalse("!" + value); - testAllFalse("#" + value); - testAllFalse("$" + value); - testAllFalse("+" + value); + private void assertAllFalseWithCorrectPrefix(String value) { + assertAllFalse("@" + value); + assertAllFalse("!" + value); + assertAllFalse("#" + value); + assertAllFalse("$" + value); + assertAllFalse("+" + value); } - private void testAllFalse(String value) { + private void assertAllFalse(String value) { Assert.assertFalse(MXPatterns.isUserId(value)); Assert.assertFalse(MXPatterns.isRoomId(value)); Assert.assertFalse(MXPatterns.isRoomAlias(value)); From 754c539fa73de442b10f46e6a94e9ebd868b4b21 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 28 Sep 2018 12:07:00 +0200 Subject: [PATCH 075/236] Add missing test --- .../src/test/java/org/matrix/androidsdk/MxPatternsTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/MxPatternsTest.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/MxPatternsTest.java index 5b88ffd69..7d6718eb0 100644 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/MxPatternsTest.java +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/MxPatternsTest.java @@ -114,6 +114,8 @@ public void MxPatterns_common_ok_localhost() { public void MxPatterns_common_ok_ipAddress() { assertAllTrueWithCorrectPrefix("id:1.1.1.1"); assertAllTrueWithCorrectPrefix("id:1.1.1.1:8080"); + assertAllTrueWithCorrectPrefix("id:1.1.1.1:65535"); + assertAllTrueWithCorrectPrefix("id:888.888.888.888"); assertAllTrueWithCorrectPrefix("id:888.888.888.888:8080"); assertAllTrueWithCorrectPrefix("id:888.888.888.888:65535"); From 967169b9b34f4717f307b91b6569b035ad617fd3 Mon Sep 17 00:00:00 2001 From: Krombel Date: Fri, 24 Aug 2018 14:01:41 +0200 Subject: [PATCH 076/236] Add ability to use filter from server This adds Interfaces to create a Filter which can be send to the server. This especially handles the DataSaveMode. The Filter is therefore uploaded in lazy-load manner and used once the server responds with a filter_id. This also deprecates "setUseDataSaveMode" and now setSyncFilter should be used. This is because the app might store the filter-id so the call for the filter-id could be avoided if the app handles that directly Signed-Off-by: Matthias Kesler --- CHANGES.rst | 3 + .../java/org/matrix/androidsdk/MXSession.java | 47 +++++++++++--- .../matrix/androidsdk/rest/api/FilterApi.java | 49 +++++++++++++++ .../rest/client/FilterRestClient.java | 61 +++++++++++++++++++ .../androidsdk/rest/model/filter/Filter.java | 30 +++++++++ .../rest/model/filter/FilterBody.java | 61 +++++++++++++++++++ .../rest/model/filter/FilterResponse.java | 15 +++++ .../rest/model/filter/RoomEventFilter.java | 32 ++++++++++ .../rest/model/filter/RoomFilter.java | 29 +++++++++ .../matrix/androidsdk/sync/EventsThread.java | 27 ++++---- 10 files changed, 331 insertions(+), 23 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterResponse.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java diff --git a/CHANGES.rst b/CHANGES.rst index 8914cd652..620a8f846 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,6 +3,8 @@ Changes to Matrix Android SDK in 0.9.10 (2018-XX-XX) Features: - Handle m.room.pinned_events state event and ServerNoticeUsageLimitContent + - Manage server_notices tag and server quota notices (vector-im/riot-android#2440) + - Add handling of filters (#345) Improvements: - Encrypt local data (PR #305) @@ -21,6 +23,7 @@ Translations: Others: - Boolean deserialization is more permissive: "1" or 1 will be handle as a true value (#358) + - MXSession.setUseDataSaveMode(boolean) is now deprecated. Handle filter-id lookup in your app and use MXSession.setSyncFilter(String) Build: - diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index d50cbd152..1b1f3fc9e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -55,6 +55,7 @@ import org.matrix.androidsdk.rest.client.CallRestClient; import org.matrix.androidsdk.rest.client.CryptoRestClient; import org.matrix.androidsdk.rest.client.EventsRestClient; +import org.matrix.androidsdk.rest.client.FilterRestClient; import org.matrix.androidsdk.rest.client.GroupsRestClient; import org.matrix.androidsdk.rest.client.LoginRestClient; import org.matrix.androidsdk.rest.client.MediaScanRestClient; @@ -72,6 +73,8 @@ import org.matrix.androidsdk.rest.model.RoomMember; import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.bingrules.BingRule; +import org.matrix.androidsdk.rest.model.filter.FilterBody; +import org.matrix.androidsdk.rest.model.filter.FilterResponse; import org.matrix.androidsdk.rest.model.login.Credentials; import org.matrix.androidsdk.rest.model.login.LoginFlow; import org.matrix.androidsdk.rest.model.login.RegistrationFlowResponse; @@ -134,6 +137,7 @@ public class MXSession { private final LoginRestClient mLoginRestClient; private final GroupsRestClient mGroupsRestClient; private final MediaScanRestClient mMediaScanRestClient; + private final FilterRestClient mFilterRestClient; private ApiFailureCallback mFailureCallback; @@ -168,8 +172,7 @@ public class MXSession { // so, mEventsThread.start might be not ready private boolean mIsBgCatchupPending = false; - // tell if the data save mode is enabled - private boolean mUseDataSaveMode; + private String mFilterId; // the groups manager private GroupsManager mGroupsManager; @@ -199,6 +202,7 @@ private MXSession(HomeServerConnectionConfig hsConfig) { mLoginRestClient = new LoginRestClient(hsConfig); mGroupsRestClient = new GroupsRestClient(hsConfig); mMediaScanRestClient = new MediaScanRestClient(hsConfig); + mFilterRestClient = new FilterRestClient(hsConfig); } /** @@ -430,6 +434,11 @@ public PresenceRestClient getPresenceApiClient() { return mPresenceRestClient; } + public FilterRestClient getFilterRestClient() { + checkIfAlive(); + return mFilterRestClient; + } + /** * Refresh the presence info of a dedicated user. * @@ -837,6 +846,7 @@ public void startEventStream(final EventsThreadListener anEventsListener, final EventsThreadListener fEventsListener = (null == anEventsListener) ? new DefaultEventsThreadListener(mDataHandler) : anEventsListener; mEventsThread = new EventsThread(mAppContent, mEventsRestClient, fEventsListener, initialToken); + mEventsThread.setFilter(mFilterId); mEventsThread.setMetricsListener(mMetricsListener); mEventsThread.setNetworkConnectivityReceiver(networkConnectivityReceiver); mEventsThread.setIsOnline(mIsOnline); @@ -847,8 +857,6 @@ public void startEventStream(final EventsThreadListener anEventsListener, mEventsThread.setFailureCallback(mFailureCallback); } - mEventsThread.setUseDataSaveMode(mUseDataSaveMode); - if (mCredentials.accessToken != null && !mEventsThread.isAlive()) { // GA issue try { @@ -956,15 +964,38 @@ public int getSyncDelay() { return mSyncDelay; } - /** - * Update the data save mode + /** + * Update the data save mode. Deprecated by setSyncFilter() * * @param enabled true to enable the data save mode */ + @Deprecated public void setUseDataSaveMode(boolean enabled) { - mUseDataSaveMode = enabled; + if (enabled) { + Log.d(LOG_TAG, "Enable DataSyncMode # " + FilterBody.getDataSaveModeFilterBody()); + // enable the filter in JSON representation so do not block sync until the filter response is there + setSyncFilter(FilterBody.getDataSaveModeFilterBody().toJSONString()); + mFilterRestClient.uploadFilter(getMyUserId(), FilterBody.getDataSaveModeFilterBody(), new SimpleApiCallback() { + @Override + public void onSuccess(FilterResponse filter) { + setSyncFilter(filter.filterId); + } + }); + } else { + Log.d(LOG_TAG, "Disable DataSyncMode"); + setSyncFilter(null); + } + } + + /** + * Allows setting the filterId used by the EventsThread + * @param filterId + */ + public synchronized void setSyncFilter(String filterId) { + Log.d(LOG_TAG, "setSyncFilter ## " + filterId); + mFilterId = filterId; if (null != mEventsThread) { - mEventsThread.setUseDataSaveMode(enabled); + mEventsThread.setFilter(filterId); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java new file mode 100644 index 000000000..0772faa06 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java @@ -0,0 +1,49 @@ +/* + * Copyright 2015 OpenMarket Ltd + * + * 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 org.matrix.androidsdk.rest.api; + +import org.matrix.androidsdk.rest.model.filter.FilterBody; +import org.matrix.androidsdk.rest.model.filter.FilterResponse; + +import java.util.Map; + +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.POST; +import retrofit2.http.Path; + +public interface FilterApi { + + /** + * Set some account_data for the client. + * + * @param userId the user id + * @param body the Json representation of a FilterBody object + */ + @POST("user/{userId}/filter") + Call uploadFilter(@Path("userId") String userId, @Body Object body); + + /** + * Gets a filter with a given filterId from the homeserver + * + * @param userId the user id + * @param filterId the filterID + * @return Filter + */ + @GET("user/{userId}/filter/{filterId}") + Call getFilterById(@Path("userId") String userId, @Path("filterId") String filterId); +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java new file mode 100644 index 000000000..39d6c0664 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java @@ -0,0 +1,61 @@ +package org.matrix.androidsdk.rest.client; + +import com.google.gson.Gson; + +import org.matrix.androidsdk.HomeServerConnectionConfig; +import org.matrix.androidsdk.RestClient; +import org.matrix.androidsdk.rest.api.FilterApi; +import org.matrix.androidsdk.rest.callback.ApiCallback; +import org.matrix.androidsdk.rest.callback.RestAdapterCallback; +import org.matrix.androidsdk.rest.model.filter.FilterBody; +import org.matrix.androidsdk.rest.model.filter.FilterResponse; + +import retrofit2.Response; + +public class FilterRestClient extends RestClient{ + + /** + * {@inheritDoc} + */ + public FilterRestClient(HomeServerConnectionConfig hsConfig) { + super(hsConfig, FilterApi.class, RestClient.URI_API_PREFIX_PATH_R0, false); + } + + /** + * Uploads a FilterBody to homeserver + * + * @param userId the user id + * @param filterBody FilterBody which should be send to server + * @param callback on success callback containing a String with populated filterId + */ + public void uploadFilter(final String userId, final FilterBody filterBody, final ApiCallback callback) { + final String description = "uploadFilter userId : " + userId + " filter : " + filterBody; + + mApi.uploadFilter(userId, filterBody) + .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { + @Override + public void onRetry() { + uploadFilter(userId, filterBody, callback); + } + })); + } + + /** + * Get a user's filter by filterId + * + * @param userId the user id + * @param filterId the filter id + * @param callback on success callback containing a User object with populated filterbody + */ + public void getFilter(final String userId, final String filterId, final ApiCallback callback) { + final String description = "getFilter userId : " + userId + " filterId : " + filterId; + + mApi.getFilterById(userId, filterId) + .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { + @Override + public void onRetry() { + getFilter(userId, filterId, callback); + } + })); + } +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java new file mode 100644 index 000000000..f9cef529e --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java @@ -0,0 +1,30 @@ +package org.matrix.androidsdk.rest.model.filter; + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; +import java.util.List; + +/** + * Represents "Filter" as mentioned in the SPEC + * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter + */ +public class Filter implements Serializable { + + public Integer limit; + + public List senders; + + @SerializedName("not_senders") + public List notSenders; + + public List types; + + @SerializedName("not_types") + public List notTypes; + + public List rooms; + + @SerializedName("not_rooms") + public List notRooms; +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java new file mode 100644 index 000000000..c23913e72 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java @@ -0,0 +1,61 @@ +package org.matrix.androidsdk.rest.model.filter; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * Class which can be parsed to a filter json string. Used for POST and GET + * Have a look here for further information: + * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter + */ +public class FilterBody implements Serializable { + public static final String LOG_TAG = FilterBody.class.getSimpleName(); + + @SerializedName("event_fields") + public List eventFields; + + @SerializedName("event_format") + public String eventFormat; + + public Filter presence; + + @SerializedName("account_data") + public Filter accountData; + + public RoomFilter room; + + private static FilterBody dataSaveModeFilterBody; + + /** + * + * @return FilterBody which represents "{\"room\": {\"ephemeral\": {\"types\": [\"m.receipt\"]}}, \"presence\":{\"notTypes\": [\"*\"]}}" + */ + public static FilterBody getDataSaveModeFilterBody() { + if (dataSaveModeFilterBody == null) { + FilterBody result = new FilterBody(); + result.room = new RoomFilter(); + result.room.ephemeral = new RoomEventFilter(); + result.room.ephemeral.types = new ArrayList<>(); + result.room.ephemeral.types.add("m.receipt"); + + result.presence = new Filter(); + result.presence.notTypes = new ArrayList<>(); + result.presence.notTypes.add("*"); + dataSaveModeFilterBody = result; + } + return dataSaveModeFilterBody; + } + + @Override + public String toString() { + return LOG_TAG + toJSONString(); + } + + public String toJSONString() { + return new Gson().toJson(this); + } +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterResponse.java new file mode 100644 index 000000000..c48993b88 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterResponse.java @@ -0,0 +1,15 @@ +package org.matrix.androidsdk.rest.model.filter; + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; + +/** + * Represents the body which is the response when creating a filter on the server + * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter + */ +public class FilterResponse implements Serializable { + + @SerializedName("filter_id") + public String filterId; +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java new file mode 100644 index 000000000..23a433f0a --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java @@ -0,0 +1,32 @@ +package org.matrix.androidsdk.rest.model.filter; + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; +import java.util.List; + +/** + * Represents "RoomEventFilter" as mentioned in the SPEC + * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter + */ +public class RoomEventFilter implements Serializable { + + public Integer limit; + + @SerializedName("not_senders") + public List notSenders; + + @SerializedName("not_types") + public List notTypes; + + public List senders; + + public List types; + + public List rooms; + + @SerializedName("not_rooms") + public List notRooms; + + public Boolean contains_url; +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java new file mode 100644 index 000000000..79fc36659 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java @@ -0,0 +1,29 @@ +package org.matrix.androidsdk.rest.model.filter; + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; +import java.util.List; + +/** + * Represents "RoomFilter" as mentioned in the SPEC + * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter + */ +public class RoomFilter implements Serializable { + + public List not_rooms; + + public List rooms; + + public RoomEventFilter ephemeral; + + @SerializedName("include_leave") + public Boolean includeLeave; + + public RoomEventFilter state; + + public RoomEventFilter timeline; + + @SerializedName("account_data") + public RoomEventFilter accountData; +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java index a300b5b3e..3f9555c0e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java @@ -29,6 +29,8 @@ import android.os.PowerManager; import android.os.SystemClock; +import com.google.gson.Gson; + import org.matrix.androidsdk.data.metrics.MetricsListener; import org.matrix.androidsdk.listeners.IMXNetworkEventListener; import org.matrix.androidsdk.network.NetworkConnectivityReceiver; @@ -36,6 +38,7 @@ import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.client.EventsRestClient; import org.matrix.androidsdk.rest.model.MatrixError; +import org.matrix.androidsdk.rest.model.filter.FilterBody; import org.matrix.androidsdk.rest.model.sync.RoomsSyncResponse; import org.matrix.androidsdk.rest.model.sync.SyncResponse; import org.matrix.androidsdk.util.Log; @@ -56,8 +59,6 @@ public class EventsThread extends Thread { private static final int DEFAULT_SERVER_TIMEOUT_MS = 30000; private static final int DEFAULT_CLIENT_TIMEOUT_MS = 120000; - private static final String DATA_SAVE_MODE_FILTER = "{\"room\": {\"ephemeral\": {\"types\": [\"m.receipt\"]}}, \"presence\":{\"not_types\": [\"*\"]}}"; - private EventsRestClient mEventsRestClient; private EventsThreadListener mListener; private String mCurrentToken; @@ -95,6 +96,7 @@ public class EventsThread extends Thread { // use dedicated filter when enable private boolean mIsInDataSaveMode = false; + private String mFilterId; private final IMXNetworkEventListener mNetworkListener = new IMXNetworkEventListener() { @Override @@ -150,12 +152,12 @@ public String getCurrentSyncToken() { } /** - * Update the data save mode + * Set filterId used for /sync requests * - * @param enabled true to enable the data save mode + * @param filterId */ - public void setUseDataSaveMode(boolean enabled) { - mIsInDataSaveMode = enabled; + public void setFilter(String filterId) { + mFilterId = filterId; } /** @@ -409,9 +411,10 @@ private void resumeInitialSync() { private void executeInitialSync() { Log.d(LOG_TAG, "Requesting initial sync..."); long initialSyncStartTime = System.currentTimeMillis(); + final String initSyncFilter = new Gson().toJson(FilterBody.getDataSaveModeFilterBody()); while (!isInitialSyncDone()) { final CountDownLatch latch = new CountDownLatch(1); - mEventsRestClient.syncFromToken(null, 0, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", DATA_SAVE_MODE_FILTER, + mEventsRestClient.syncFromToken(null, 0, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", initSyncFilter, new SimpleApiCallback(mFailureCallback) { @Override public void onSuccess(SyncResponse syncResponse) { @@ -569,20 +572,14 @@ private void startSync() { long incrementalSyncStartTime = System.currentTimeMillis(); - String inlineFilter = mIsInDataSaveMode ? DATA_SAVE_MODE_FILTER : null; //"{\"room\":{\"timeline\":{\"limit\":250}}}"; - 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); - } + Log.d(LOG_TAG, "Get events from token " + mCurrentToken + " with filter " + mFilterId); final int fServerTimeout = serverTimeout; mNextServerTimeoutms = mDefaultServerTimeoutms; - mEventsRestClient.syncFromToken(mCurrentToken, serverTimeout, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", inlineFilter, + mEventsRestClient.syncFromToken(mCurrentToken, serverTimeout, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", mFilterId, new SimpleApiCallback(mFailureCallback) { @Override public void onSuccess(SyncResponse syncResponse) { From 142e26fea52204364d59b782cd84afdfcc62e2cf Mon Sep 17 00:00:00 2001 From: Krombel Date: Fri, 24 Aug 2018 15:40:57 +0200 Subject: [PATCH 077/236] incorporate review - add copyright header - remove `implements Serializable` - replace filter by filterOrFilterId - Object => FilterBody in FilterApi --- CHANGES.rst | 2 +- .../java/org/matrix/androidsdk/MXSession.java | 22 +++++++++---------- .../matrix/androidsdk/rest/api/FilterApi.java | 2 +- .../androidsdk/rest/model/filter/Filter.java | 18 ++++++++++++++- .../rest/model/filter/FilterBody.java | 18 ++++++++++++++- .../rest/model/filter/FilterResponse.java | 18 ++++++++++++++- .../rest/model/filter/RoomEventFilter.java | 18 ++++++++++++++- .../rest/model/filter/RoomFilter.java | 18 ++++++++++++++- .../matrix/androidsdk/sync/EventsThread.java | 14 ++++++------ 9 files changed, 105 insertions(+), 25 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 620a8f846..39b1e4977 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -23,7 +23,7 @@ Translations: Others: - Boolean deserialization is more permissive: "1" or 1 will be handle as a true value (#358) - - MXSession.setUseDataSaveMode(boolean) is now deprecated. Handle filter-id lookup in your app and use MXSession.setSyncFilter(String) + - MXSession.setUseDataSaveMode(boolean) is now deprecated. Handle filter-id lookup in your app and use MXSession.setSyncFilterOrFilterId(String) Build: - diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index 1b1f3fc9e..92d0332fd 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -172,7 +172,7 @@ public class MXSession { // so, mEventsThread.start might be not ready private boolean mIsBgCatchupPending = false; - private String mFilterId; + private String mFilterOrFilterId; // the groups manager private GroupsManager mGroupsManager; @@ -846,7 +846,7 @@ public void startEventStream(final EventsThreadListener anEventsListener, final EventsThreadListener fEventsListener = (null == anEventsListener) ? new DefaultEventsThreadListener(mDataHandler) : anEventsListener; mEventsThread = new EventsThread(mAppContent, mEventsRestClient, fEventsListener, initialToken); - mEventsThread.setFilter(mFilterId); + mEventsThread.setFilterOrFilterId(mFilterOrFilterId); mEventsThread.setMetricsListener(mMetricsListener); mEventsThread.setNetworkConnectivityReceiver(networkConnectivityReceiver); mEventsThread.setIsOnline(mIsOnline); @@ -965,7 +965,7 @@ public int getSyncDelay() { } /** - * Update the data save mode. Deprecated by setSyncFilter() + * Update the data save mode. Deprecated by setSyncFilterOrFilterId() * * @param enabled true to enable the data save mode */ @@ -974,28 +974,28 @@ public void setUseDataSaveMode(boolean enabled) { if (enabled) { Log.d(LOG_TAG, "Enable DataSyncMode # " + FilterBody.getDataSaveModeFilterBody()); // enable the filter in JSON representation so do not block sync until the filter response is there - setSyncFilter(FilterBody.getDataSaveModeFilterBody().toJSONString()); + setSyncFilterOrFilterId(FilterBody.getDataSaveModeFilterBody().toJSONString()); mFilterRestClient.uploadFilter(getMyUserId(), FilterBody.getDataSaveModeFilterBody(), new SimpleApiCallback() { @Override public void onSuccess(FilterResponse filter) { - setSyncFilter(filter.filterId); + setSyncFilterOrFilterId(filter.filterId); } }); } else { Log.d(LOG_TAG, "Disable DataSyncMode"); - setSyncFilter(null); + setSyncFilterOrFilterId(null); } } /** * Allows setting the filterId used by the EventsThread - * @param filterId + * @param filterOrFilterId the content of the filter param on sync requests */ - public synchronized void setSyncFilter(String filterId) { - Log.d(LOG_TAG, "setSyncFilter ## " + filterId); - mFilterId = filterId; + public synchronized void setSyncFilterOrFilterId(String filterOrFilterId) { + Log.d(LOG_TAG, "setSyncFilterOrFilterId ## " + filterOrFilterId); + mFilterOrFilterId = filterOrFilterId; if (null != mEventsThread) { - mEventsThread.setFilter(filterId); + mEventsThread.setFilterOrFilterId(filterOrFilterId); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java index 0772faa06..70e4be7a3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java @@ -35,7 +35,7 @@ public interface FilterApi { * @param body the Json representation of a FilterBody object */ @POST("user/{userId}/filter") - Call uploadFilter(@Path("userId") String userId, @Body Object body); + Call uploadFilter(@Path("userId") String userId, @Body FilterBody body); /** * Gets a filter with a given filterId from the homeserver diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java index f9cef529e..3596a25b8 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Matthias Kesler + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model.filter; import com.google.gson.annotations.SerializedName; @@ -9,7 +25,7 @@ * Represents "Filter" as mentioned in the SPEC * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter */ -public class Filter implements Serializable { +public class Filter { public Integer limit; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java index c23913e72..a9de59405 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Matthias Kesler + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model.filter; import com.google.gson.Gson; @@ -12,7 +28,7 @@ * Have a look here for further information: * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter */ -public class FilterBody implements Serializable { +public class FilterBody { public static final String LOG_TAG = FilterBody.class.getSimpleName(); @SerializedName("event_fields") diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterResponse.java index c48993b88..a3bbe821f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterResponse.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterResponse.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Matthias Kesler + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model.filter; import com.google.gson.annotations.SerializedName; @@ -8,7 +24,7 @@ * Represents the body which is the response when creating a filter on the server * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter */ -public class FilterResponse implements Serializable { +public class FilterResponse { @SerializedName("filter_id") public String filterId; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java index 23a433f0a..73ef56293 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Matthias Kesler + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model.filter; import com.google.gson.annotations.SerializedName; @@ -9,7 +25,7 @@ * Represents "RoomEventFilter" as mentioned in the SPEC * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter */ -public class RoomEventFilter implements Serializable { +public class RoomEventFilter { public Integer limit; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java index 79fc36659..4d71cefb0 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Matthias Kesler + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model.filter; import com.google.gson.annotations.SerializedName; @@ -9,7 +25,7 @@ * Represents "RoomFilter" as mentioned in the SPEC * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter */ -public class RoomFilter implements Serializable { +public class RoomFilter { public List not_rooms; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java index 3f9555c0e..bc89c34dc 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java @@ -96,7 +96,7 @@ public class EventsThread extends Thread { // use dedicated filter when enable private boolean mIsInDataSaveMode = false; - private String mFilterId; + private String mFilterOrFilterId; private final IMXNetworkEventListener mNetworkListener = new IMXNetworkEventListener() { @Override @@ -152,12 +152,12 @@ public String getCurrentSyncToken() { } /** - * Set filterId used for /sync requests + * Set filterOrFilterId used for /sync requests * - * @param filterId + * @param filterOrFilterId */ - public void setFilter(String filterId) { - mFilterId = filterId; + public void setFilterOrFilterId(String filterOrFilterId) { + mFilterOrFilterId = filterOrFilterId; } /** @@ -574,12 +574,12 @@ private void startSync() { final CountDownLatch latch = new CountDownLatch(1); - Log.d(LOG_TAG, "Get events from token " + mCurrentToken + " with filter " + mFilterId); + Log.d(LOG_TAG, "Get events from token " + mCurrentToken + " with filterOrFilterId " + mFilterOrFilterId); final int fServerTimeout = serverTimeout; mNextServerTimeoutms = mDefaultServerTimeoutms; - mEventsRestClient.syncFromToken(mCurrentToken, serverTimeout, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", mFilterId, + mEventsRestClient.syncFromToken(mCurrentToken, serverTimeout, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", mFilterOrFilterId, new SimpleApiCallback(mFailureCallback) { @Override public void onSuccess(SyncResponse syncResponse) { From a972ef9d43673cf168b7a89798ea60bd379a9f35 Mon Sep 17 00:00:00 2001 From: Krombel Date: Fri, 24 Aug 2018 17:10:53 +0200 Subject: [PATCH 078/236] incoorporate review take 2 - add/Fix header for copyright - fix docstring - snake_case => camelCase --- .../matrix/androidsdk/rest/api/FilterApi.java | 5 +++-- .../androidsdk/rest/client/FilterRestClient.java | 16 ++++++++++++++++ .../rest/model/filter/RoomEventFilter.java | 3 ++- .../androidsdk/rest/model/filter/RoomFilter.java | 3 ++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java index 70e4be7a3..64e76ef67 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java @@ -1,5 +1,6 @@ /* - * Copyright 2015 OpenMarket Ltd + * Copyright 2018 Matthias Kesler + * Copyright 2018 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +30,7 @@ public interface FilterApi { /** - * Set some account_data for the client. + * Upload FilterBody to get a filter_id which can be used for /sync requests * * @param userId the user id * @param body the Json representation of a FilterBody object diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java index 39d6c0664..88608e4f0 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Matthias Kesler + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.client; import com.google.gson.Gson; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java index 73ef56293..4e63ff076 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java @@ -44,5 +44,6 @@ public class RoomEventFilter { @SerializedName("not_rooms") public List notRooms; - public Boolean contains_url; + @SerializedName("contains_url") + public Boolean containsUrl; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java index 4d71cefb0..dbf7ba0ee 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java @@ -27,7 +27,8 @@ */ public class RoomFilter { - public List not_rooms; + @SerializedName("not_rooms") + public List notRooms; public List rooms; From 096d4a9431641cb2126b59eddcbd2d0fd6ca8fac Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 14 Aug 2018 16:48:49 +0200 Subject: [PATCH 079/236] LazyLoading WIP --- .../org/matrix/androidsdk/MXDataHandler.java | 23 + .../java/org/matrix/androidsdk/MXSession.java | 161 ++++--- .../androidsdk/call/MXCallsManager.java | 140 +++--- .../matrix/androidsdk/crypto/MXCrypto.java | 244 ++++++----- .../matrix/androidsdk/data/EventTimeline.java | 17 +- .../java/org/matrix/androidsdk/data/Room.java | 128 ++++-- .../org/matrix/androidsdk/data/RoomState.java | 128 +++--- .../matrix/androidsdk/data/RoomSummary.java | 80 ++++ .../androidsdk/data/store/IMXStore.java | 2 +- .../androidsdk/data/store/MXFileStore.java | 8 +- .../matrix/androidsdk/rest/api/RoomsApi.java | 17 +- .../rest/client/RoomsRestClient.java | 400 +++++++++--------- .../rest/model/RoomEventFilter.java | 47 ++ .../bingrules/RoomMemberCountCondition.java | 29 +- .../rest/model/group/GroupSyncProfile.java | 3 +- .../rest/model/group/GroupsSyncResponse.java | 3 +- .../rest/model/group/InvitedGroupSync.java | 3 +- .../DeviceOneTimeKeysCountSyncResponse.java | 5 +- .../rest/model/sync/PresenceSyncResponse.java | 7 +- .../androidsdk/rest/model/sync/RoomSync.java | 13 +- .../rest/model/sync/RoomSyncAccountData.java | 5 +- .../rest/model/sync/RoomSyncEphemeral.java | 7 +- .../rest/model/sync/RoomSyncState.java | 7 +- .../rest/model/sync/RoomSyncSummary.java | 52 +++ .../rest/model/sync/RoomSyncTimeline.java | 7 +- .../sync/RoomSyncUnreadNotifications.java | 9 +- .../rest/model/sync/RoomsSyncResponse.java | 5 +- .../rest/model/sync/SyncResponse.java | 3 +- .../rest/model/sync/ToDeviceSyncResponse.java | 5 +- .../matrix/androidsdk/sync/EventsThread.java | 6 + 30 files changed, 989 insertions(+), 575 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomEventFilter.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncSummary.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 8f7ba5913..4b737b5ef 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -33,6 +33,7 @@ import org.matrix.androidsdk.crypto.MXDecryptionException; import org.matrix.androidsdk.crypto.MXEventDecryptionResult; import org.matrix.androidsdk.data.DataRetriever; +import org.matrix.androidsdk.data.EventTimeline; import org.matrix.androidsdk.data.MyUser; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; @@ -58,6 +59,7 @@ import org.matrix.androidsdk.rest.model.ReceiptData; import org.matrix.androidsdk.rest.model.RoomAliasDescription; import org.matrix.androidsdk.rest.model.RoomMember; +import org.matrix.androidsdk.rest.model.TokensChunkResponse; import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.bingrules.BingRule; import org.matrix.androidsdk.rest.model.bingrules.Condition; @@ -932,6 +934,27 @@ public void onSuccess(RoomAliasDescription info) { } + /** + * Get the members of a Room with a request to the server + * + * @param roomId the id of the room + * @param callback the callback + */ + public void getMembersAsync(final String roomId, final ApiCallback> callback) { + mRoomsRestClient.getRoomMembers(roomId, new SimpleApiCallback>(callback) { + @Override + public void onSuccess(TokensChunkResponse info) { + Room room = getRoom(roomId); + + for (Event event : info.chunk) { + room.getState().applyState(getStore(), event, EventTimeline.Direction.FORWARDS); + } + + callback.onSuccess(room.getState().getLoadedMembers()); + } + }); + } + /** * Delete an event. * diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index 92d0332fd..bbe3f150e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -24,6 +24,7 @@ import android.os.AsyncTask; import android.os.Handler; import android.os.Looper; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; @@ -1683,93 +1684,86 @@ public Double tagOrderToBeAtIndex(int index, int originIndex, String tag) { * @param aParticipantUserId the participant user id * @param callback the asynchronous callback */ - public void toggleDirectChatRoom(String roomId, String aParticipantUserId, ApiCallback callback) { + public void toggleDirectChatRoom(final String roomId, String aParticipantUserId, final ApiCallback callback) { IMXStore store = getDataHandler().getStore(); Room room = store.getRoom(roomId); if (null != room) { - Map> params; - - if (null != store.getDirectChatRoomsDict()) { - params = new HashMap<>(store.getDirectChatRoomsDict()); - } else { - params = new HashMap<>(); - } - // if the room was not yet seen as direct chat if (!getDataHandler().getDirectChatRoomIdsList().contains(roomId)) { - List roomIdsList = new ArrayList<>(); - RoomMember directChatMember = null; - String chosenUserId; - if (null == aParticipantUserId) { - List members = new ArrayList<>(room.getActiveMembers()); - - // should never happen but it was reported by a GA issue - if (members.isEmpty()) { - return; - } + room.getActiveMembersAsync(new SimpleApiCallback>(callback) { + @Override + public void onSuccess(List members) { + // should never happen but it was reported by a GA issue + if (members.isEmpty()) { + return; + } - if (members.size() > 1) { - // sort algo: oldest join first, then oldest invited - Collections.sort(members, new Comparator() { - @Override - public int compare(RoomMember r1, RoomMember r2) { - int res; - long diff; - - if (RoomMember.MEMBERSHIP_JOIN.equals(r2.membership) && RoomMember.MEMBERSHIP_INVITE.equals(r1.membership)) { - res = 1; - } else if (r2.membership.equals(r1.membership)) { - diff = r1.getOriginServerTs() - r2.getOriginServerTs(); - res = (0 == diff) ? 0 : ((diff > 0) ? 1 : -1); + RoomMember directChatMember = null; + + if (members.size() > 1) { + // sort algo: oldest join first, then oldest invited + Collections.sort(members, new Comparator() { + @Override + public int compare(RoomMember r1, RoomMember r2) { + int res; + long diff; + + if (RoomMember.MEMBERSHIP_JOIN.equals(r2.membership) && RoomMember.MEMBERSHIP_INVITE.equals(r1.membership)) { + res = 1; + } else if (r2.membership.equals(r1.membership)) { + diff = r1.getOriginServerTs() - r2.getOriginServerTs(); + res = (0 == diff) ? 0 : ((diff > 0) ? 1 : -1); + } else { + res = -1; + } + return res; + } + }); + + int nextIndexSearch = 0; + + // take the oldest join member + if (!TextUtils.equals(members.get(0).getUserId(), getMyUserId())) { + if (RoomMember.MEMBERSHIP_JOIN.equals(members.get(0).membership)) { + directChatMember = members.get(0); + } } else { - res = -1; + nextIndexSearch = 1; + if (RoomMember.MEMBERSHIP_JOIN.equals(members.get(1).membership)) { + directChatMember = members.get(1); + } } - return res; - } - }); - int nextIndexSearch = 0; + // no join member found, test the oldest join member + if (null == directChatMember) { + if (RoomMember.MEMBERSHIP_INVITE.equals(members.get(nextIndexSearch).membership)) { + directChatMember = members.get(nextIndexSearch); + } + } + } - // take the oldest join member - if (!TextUtils.equals(members.get(0).getUserId(), getMyUserId())) { - if (RoomMember.MEMBERSHIP_JOIN.equals(members.get(0).membership)) { + // last option: get the logged user + if (null == directChatMember) { directChatMember = members.get(0); } - } else { - nextIndexSearch = 1; - if (RoomMember.MEMBERSHIP_JOIN.equals(members.get(1).membership)) { - directChatMember = members.get(1); - } - } - // no join member found, test the oldest join member - if (null == directChatMember) { - if (RoomMember.MEMBERSHIP_INVITE.equals(members.get(nextIndexSearch).membership)) { - directChatMember = members.get(nextIndexSearch); - } + toggleDirectChatRoomStep2(roomId, directChatMember.getUserId(), callback); } - } - - // last option: get the logged user - if (null == directChatMember) { - directChatMember = members.get(0); - } - - chosenUserId = directChatMember.getUserId(); + }); } else { - chosenUserId = aParticipantUserId; + toggleDirectChatRoomStep2(roomId, aParticipantUserId, callback); } + } else { + Map> params; - // search if there is an entry with the same user - if (params.containsKey(chosenUserId)) { - roomIdsList = new ArrayList<>(params.get(chosenUserId)); + if (null != store.getDirectChatRoomsDict()) { + params = new HashMap<>(store.getDirectChatRoomsDict()); + } else { + params = new HashMap<>(); } - roomIdsList.add(roomId); // update room list with the new room - params.put(chosenUserId, roomIdsList); - } else { // remove the current room from the direct chat list rooms if (null != store.getDirectChatRoomsDict()) { List keysList = new ArrayList<>(params.keySet()); @@ -1791,11 +1785,42 @@ public int compare(RoomMember r1, RoomMember r2) { Log.e(LOG_TAG, "## toggleDirectChatRoom(): failed to remove a direct chat room (not seen as direct chat room)"); return; } + + // Store and upload the updated map + getDataHandler().setDirectChatRoomsMap(params, callback); } + } + } + + /** + * @param roomId + * @param chosenUserId + * @param callback + */ + private void toggleDirectChatRoomStep2(String roomId, + @NonNull String chosenUserId, + ApiCallback callback) { + IMXStore store = getDataHandler().getStore(); + Map> params; + + if (null != store.getDirectChatRoomsDict()) { + params = new HashMap<>(store.getDirectChatRoomsDict()); + } else { + params = new HashMap<>(); + } + + List roomIdsList = new ArrayList<>(); - // Store and upload the updated map - getDataHandler().setDirectChatRoomsMap(params, callback); + // search if there is an entry with the same user + if (params.containsKey(chosenUserId)) { + roomIdsList = new ArrayList<>(params.get(chosenUserId)); } + + roomIdsList.add(roomId); // update room list with the new room + params.put(chosenUserId, roomIdsList); + + // Store and upload the updated map + getDataHandler().setDirectChatRoomsMap(params, callback); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java index 98baca925..9f9f32533 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java @@ -524,7 +524,7 @@ public void run() { if ((null != room) && room.isEncrypted() && mSession.getCrypto().warnOnUnknownDevices() && - (room.getJoinedMembers().size() == 2)) { + room.getNumberOfJoinedMembers() == 2) { // test if the encrypted events are sent only to the verified devices (any room) mSession.getCrypto().getGlobalBlacklistUnverifiedDevices(new SimpleApiCallback() { @@ -540,55 +540,75 @@ public void onSuccess(Boolean sendToVerifiedDevicesOnly) { if (sendToVerifiedDevicesOnly) { dispatchOnIncomingCall(call, null); } else { - List members = new ArrayList<>(room.getJoinedMembers()); - String userId1 = members.get(0).getUserId(); - String userId2 = members.get(1).getUserId(); + room.getJoinedMembersAsync(new ApiCallback>() { - Log.d(LOG_TAG, "## checkPendingIncomingCalls() : check the unknown devices"); - - // - mSession.getCrypto().checkUnknownDevices(Arrays.asList(userId1, userId2), new ApiCallback() { @Override - public void onSuccess(Void anything) { - Log.d(LOG_TAG, "## checkPendingIncomingCalls() : no unknown device"); + public void onNetworkError(Exception e) { dispatchOnIncomingCall(call, null); } @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## checkPendingIncomingCalls() : checkUnknownDevices failed " - + e.getMessage(), e); + public void onMatrixError(MatrixError e) { dispatchOnIncomingCall(call, null); } @Override - public void onMatrixError(MatrixError e) { - MXUsersDevicesMap unknownDevices = null; + public void onUnexpectedError(Exception e) { + dispatchOnIncomingCall(call, null); + } - if (e instanceof MXCryptoError) { - MXCryptoError cryptoError = (MXCryptoError) e; + @Override + public void onSuccess(List members) { + String userId1 = members.get(0).getUserId(); + String userId2 = members.get(1).getUserId(); + + Log.d(LOG_TAG, "## checkPendingIncomingCalls() : check the unknown devices"); + + // + mSession.getCrypto().checkUnknownDevices(Arrays.asList(userId1, userId2), new ApiCallback() { + @Override + public void onSuccess(Void anything) { + Log.d(LOG_TAG, "## checkPendingIncomingCalls() : no unknown device"); + dispatchOnIncomingCall(call, null); + } - if (MXCryptoError.UNKNOWN_DEVICES_CODE.equals(cryptoError.errcode)) { - unknownDevices = (MXUsersDevicesMap) cryptoError.mExceptionData; + @Override + public void onNetworkError(Exception e) { + Log.e(LOG_TAG, "## checkPendingIncomingCalls() : checkUnknownDevices failed " + + e.getMessage(), e); + dispatchOnIncomingCall(call, null); } - } - if (null != unknownDevices) { - Log.d(LOG_TAG, "## checkPendingIncomingCalls() :" + - " checkUnknownDevices found some unknown devices"); - } else { - Log.e(LOG_TAG, "## checkPendingIncomingCalls() :" + - " checkUnknownDevices failed " + e.getMessage()); - } + @Override + public void onMatrixError(MatrixError e) { + MXUsersDevicesMap unknownDevices = null; - dispatchOnIncomingCall(call, unknownDevices); - } + if (e instanceof MXCryptoError) { + MXCryptoError cryptoError = (MXCryptoError) e; - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## checkPendingIncomingCalls() :" + - " checkUnknownDevices failed " + e.getMessage(), e); - dispatchOnIncomingCall(call, null); + if (MXCryptoError.UNKNOWN_DEVICES_CODE.equals(cryptoError.errcode)) { + unknownDevices = (MXUsersDevicesMap) cryptoError.mExceptionData; + } + } + + if (null != unknownDevices) { + Log.d(LOG_TAG, "## checkPendingIncomingCalls() :" + + " checkUnknownDevices found some unknown devices"); + } else { + Log.e(LOG_TAG, "## checkPendingIncomingCalls() :" + + " checkUnknownDevices failed " + e.getMessage()); + } + + dispatchOnIncomingCall(call, unknownDevices); + } + + @Override + public void onUnexpectedError(Exception e) { + Log.e(LOG_TAG, "## checkPendingIncomingCalls() :" + + " checkUnknownDevices failed " + e.getMessage(), e); + dispatchOnIncomingCall(call, null); + } + }); } }); } @@ -628,7 +648,7 @@ public void createCallInRoom(final String roomId, final boolean isVideo, final A // sanity check if (null != room) { if (isSupported()) { - int joinedMembers = room.getJoinedMembers().size(); + int joinedMembers = room.getNumberOfJoinedMembers(); Log.d(LOG_TAG, "createCallInRoom : the room has " + joinedMembers + " joined members"); @@ -638,27 +658,37 @@ public void createCallInRoom(final String roomId, final boolean isVideo, final A // else the call will fail. // So it seems safer to reject the call creation it it will fail. if (room.isEncrypted() && mSession.getCrypto().warnOnUnknownDevices()) { - List members = new ArrayList<>(room.getJoinedMembers()); - String userId1 = members.get(0).getUserId(); - String userId2 = members.get(1).getUserId(); - - // force the refresh to ensure that the devices list is up-to-date - mSession.getCrypto().checkUnknownDevices(Arrays.asList(userId1, userId2), new SimpleApiCallback(callback) { + room.getJoinedMembersAsync(new SimpleApiCallback>(callback) { @Override - public void onSuccess(Void anything) { - final IMXCall call = getCallWithCallId(null, true); - call.setRooms(room, room); - call.setIsVideo(isVideo); - dispatchOnOutgoingCall(call); - - if (null != callback) { - mUIThreadHandler.post(new Runnable() { - @Override - public void run() { - callback.onSuccess(call); - } - }); + public void onSuccess(List members) { + if (members.size() != 2) { + // Safety check + callback.onUnexpectedError(new Exception("Wrong number of members")); + return; } + + String userId1 = members.get(0).getUserId(); + String userId2 = members.get(1).getUserId(); + + // force the refresh to ensure that the devices list is up-to-date + mSession.getCrypto().checkUnknownDevices(Arrays.asList(userId1, userId2), new SimpleApiCallback(callback) { + @Override + public void onSuccess(Void anything) { + final IMXCall call = getCallWithCallId(null, true); + call.setRooms(room, room); + call.setIsVideo(isVideo); + dispatchOnOutgoingCall(call); + + if (null != callback) { + mUIThreadHandler.post(new Runnable() { + @Override + public void run() { + callback.onSuccess(call); + } + }); + } + } + }); } }); } else { @@ -1062,7 +1092,7 @@ private void getConferenceUserRoom(final String roomId, final ApiCallback // Use an existing 1:1 with the conference user; else make one for (Room room : rooms) { - if (room.isConferenceUserRoom() && (2 == room.getMembers().size()) && (null != room.getMember(conferenceUserId))) { + if (room.isConferenceUserRoom() && room.getNumberOfMembers() == 2 && null != room.getMember(conferenceUserId)) { conferenceRoom = room; break; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java index 1686a2ea0..dcbbd2963 100755 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java @@ -61,7 +61,6 @@ import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -868,9 +867,10 @@ public void run() { * @param roomId the room id to enable encryption in. * @param algorithm the encryption config for the room. * @param inhibitDeviceQuery true to suppress device list query for users in the room (for now) + * @param members list of members to start tracking their devices * @return true if the operation succeeds. */ - private boolean setEncryptionInRoom(String roomId, String algorithm, boolean inhibitDeviceQuery) { + private boolean setEncryptionInRoom(String roomId, String algorithm, boolean inhibitDeviceQuery, List members) { if (hasBeenReleased()) { return false; } @@ -917,30 +917,16 @@ private boolean setEncryptionInRoom(String roomId, String algorithm, boolean inh if (null == existingAlgorithm) { Log.d(LOG_TAG, "Enabling encryption in " + roomId + " for the first time; invalidating device lists for all users therein"); - Room room = mSession.getDataHandler().getRoom(roomId); - if (null != room) { - // Check whether the event content must be encrypted for the invited members. - boolean encryptForInvitedMembers = mCryptoConfig.mEnableEncryptionForInvitedMembers - && room.shouldEncryptForInvitedMembers(); + List userIds = new ArrayList<>(); - Collection members; - if (encryptForInvitedMembers) { - members = room.getActiveMembers(); - } else { - members = room.getJoinedMembers(); - } - - List userIds = new ArrayList<>(); - - for (RoomMember m : members) { - userIds.add(m.getUserId()); - } + for (RoomMember m : members) { + userIds.add(m.getUserId()); + } - getDeviceList().startTrackingDeviceList(userIds); + getDeviceList().startTrackingDeviceList(userIds); - if (!inhibitDeviceQuery) { - getDeviceList().refreshOutdatedDeviceLists(); - } + if (!inhibitDeviceQuery) { + getDeviceList().refreshOutdatedDeviceLists(); } } @@ -1268,103 +1254,107 @@ public void onUnexpectedError(Exception e) { return; } - // just as you are sending a secret message? - final List userdIds = new ArrayList<>(); - - // Check whether the event content must be encrypted for the invited members. - boolean encryptForInvitedMembers = mCryptoConfig.mEnableEncryptionForInvitedMembers - && room.shouldEncryptForInvitedMembers(); - - Collection members; - if (encryptForInvitedMembers) { - members = room.getActiveMembers(); - } else { - members = room.getJoinedMembers(); - } - - for (RoomMember m : members) { - userdIds.add(m.getUserId()); - } - - getEncryptingThreadHandler().post(new Runnable() { + final ApiCallback> apiCallback = new SimpleApiCallback>(callback) { @Override - public void run() { - IMXEncrypting alg; + public void onSuccess(final List members) { + // just as you are sending a secret message? + final List userdIds = new ArrayList<>(); - synchronized (mRoomEncryptors) { - alg = mRoomEncryptors.get(room.getRoomId()); + for (RoomMember m : members) { + userdIds.add(m.getUserId()); } - if (null == alg) { - String algorithm = room.getState().encryptionAlgorithm(); + getEncryptingThreadHandler().post(new Runnable() { + @Override + public void run() { + IMXEncrypting alg; - if (null != algorithm) { - if (setEncryptionInRoom(room.getRoomId(), algorithm, false)) { - synchronized (mRoomEncryptors) { - alg = mRoomEncryptors.get(room.getRoomId()); - } + synchronized (mRoomEncryptors) { + alg = mRoomEncryptors.get(room.getRoomId()); } - } - } - if (null != alg) { - final long t0 = System.currentTimeMillis(); - Log.d(LOG_TAG, "## encryptEventContent() starts"); - - alg.encryptEventContent(eventContent, eventType, userdIds, new ApiCallback() { - @Override - public void onSuccess(final JsonElement encryptedContent) { - Log.d(LOG_TAG, "## encryptEventContent() : succeeds after " + (System.currentTimeMillis() - t0) + " ms"); + if (null == alg) { + String algorithm = room.getState().encryptionAlgorithm(); - if (null != callback) { - callback.onSuccess(new MXEncryptEventContentResult(encryptedContent, Event.EVENT_TYPE_MESSAGE_ENCRYPTED)); + if (null != algorithm) { + if (setEncryptionInRoom(room.getRoomId(), algorithm, false, members)) { + synchronized (mRoomEncryptors) { + alg = mRoomEncryptors.get(room.getRoomId()); + } + } } } - @Override - public void onNetworkError(final Exception e) { - Log.e(LOG_TAG, "## encryptEventContent() : onNetworkError " + e.getMessage(), e); + if (null != alg) { + final long t0 = System.currentTimeMillis(); + Log.d(LOG_TAG, "## encryptEventContent() starts"); - if (null != callback) { - callback.onNetworkError(e); - } - } + alg.encryptEventContent(eventContent, eventType, userdIds, new ApiCallback() { + @Override + public void onSuccess(final JsonElement encryptedContent) { + Log.d(LOG_TAG, "## encryptEventContent() : succeeds after " + (System.currentTimeMillis() - t0) + " ms"); - @Override - public void onMatrixError(final MatrixError e) { - Log.e(LOG_TAG, "## encryptEventContent() : onMatrixError " + e.getMessage()); + if (null != callback) { + callback.onSuccess(new MXEncryptEventContentResult(encryptedContent, Event.EVENT_TYPE_MESSAGE_ENCRYPTED)); + } + } - if (null != callback) { - callback.onMatrixError(e); - } - } + @Override + public void onNetworkError(final Exception e) { + Log.e(LOG_TAG, "## encryptEventContent() : onNetworkError " + e.getMessage(), e); - @Override - public void onUnexpectedError(final Exception e) { - Log.e(LOG_TAG, "## encryptEventContent() : onUnexpectedError " + e.getMessage(), e); + if (null != callback) { + callback.onNetworkError(e); + } + } + + @Override + public void onMatrixError(final MatrixError e) { + Log.e(LOG_TAG, "## encryptEventContent() : onMatrixError " + e.getMessage()); + + if (null != callback) { + callback.onMatrixError(e); + } + } + + @Override + public void onUnexpectedError(final Exception e) { + Log.e(LOG_TAG, "## encryptEventContent() : onUnexpectedError " + e.getMessage(), e); + + if (null != callback) { + callback.onUnexpectedError(e); + } + } + }); + } else { + final String algorithm = room.getState().encryptionAlgorithm(); + final String reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, + (null == algorithm) ? MXCryptoError.NO_MORE_ALGORITHM_REASON : algorithm); + Log.e(LOG_TAG, "## encryptEventContent() : " + reason); if (null != callback) { - callback.onUnexpectedError(e); + getUIHandler().post(new Runnable() { + @Override + public void run() { + callback.onMatrixError(new MXCryptoError(MXCryptoError.UNABLE_TO_ENCRYPT_ERROR_CODE, MXCryptoError.UNABLE_TO_ENCRYPT, reason)); + } + }); } } - }); - } else { - final String algorithm = room.getState().encryptionAlgorithm(); - final String reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON, - (null == algorithm) ? MXCryptoError.NO_MORE_ALGORITHM_REASON : algorithm); - Log.e(LOG_TAG, "## encryptEventContent() : " + reason); - - if (null != callback) { - getUIHandler().post(new Runnable() { - @Override - public void run() { - callback.onMatrixError(new MXCryptoError(MXCryptoError.UNABLE_TO_ENCRYPT_ERROR_CODE, MXCryptoError.UNABLE_TO_ENCRYPT, reason)); - } - }); } - } + }); } - }); + }; + + // Check whether the event content must be encrypted for the invited members. + boolean encryptForInvitedMembers = mCryptoConfig.mEnableEncryptionForInvitedMembers + && room.shouldEncryptForInvitedMembers(); + + if (encryptForInvitedMembers) { + room.getActiveMembersAsync(apiCallback); + } else { + room.getJoinedMembersAsync(apiCallback); + } } /** @@ -1741,12 +1731,60 @@ public void run() { private void onCryptoEvent(final Event event) { final EventContent eventContent = event.getWireEventContent(); - getEncryptingThreadHandler().post(new Runnable() { + final Room room = mSession.getDataHandler().getRoom(event.roomId); + + // Check whether the event content must be encrypted for the invited members. + boolean encryptForInvitedMembers = mCryptoConfig.mEnableEncryptionForInvitedMembers + && room.shouldEncryptForInvitedMembers(); + + ApiCallback> callback = new ApiCallback>() { @Override - public void run() { - setEncryptionInRoom(event.roomId, eventContent.algorithm, true); + public void onSuccess(final List info) { + getEncryptingThreadHandler().post(new Runnable() { + @Override + public void run() { + setEncryptionInRoom(event.roomId, eventContent.algorithm, true, info); + } + }); } - }); + + private void onError() { + // Ensure setEncryption in room is done, even if there is a failure to fetch the room members + getEncryptingThreadHandler().post(new Runnable() { + @Override + public void run() { + setEncryptionInRoom(event.roomId, eventContent.algorithm, true, room.getState().getLoadedMembers()); + } + }); + } + + @Override + public void onNetworkError(Exception e) { + Log.w(LOG_TAG, "[MXCrypto] onCryptoEvent: Warning: Unable to get all members from the HS. Fallback by using lazy-loaded members", e); + + onError(); + } + + @Override + public void onMatrixError(MatrixError e) { + Log.w(LOG_TAG, "[MXCrypto] onCryptoEvent: Warning: Unable to get all members from the HS. Fallback by using lazy-loaded members"); + + onError(); + } + + @Override + public void onUnexpectedError(Exception e) { + Log.w(LOG_TAG, "[MXCrypto] onCryptoEvent: Warning: Unable to get all members from the HS. Fallback by using lazy-loaded members", e); + + onError(); + } + }; + + if (encryptForInvitedMembers) { + room.getActiveMembersAsync(callback); + } else { + room.getJoinedMembersAsync(callback); + } } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index 9a76229bc..d98471030 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -447,7 +447,7 @@ public void handleJoinedRoomSync(RoomSync roomSync, boolean isGlobalInitialSync) // if it is an initial sync, the live state is initialized here // so the back state must also be initialized if (isRoomInitialSync) { - Log.d(LOG_TAG, "## handleJoinedRoomSync() : retrieve " + mState.getMembers().size() + " members for room " + mRoomId); + Log.d(LOG_TAG, "## handleJoinedRoomSync() : retrieve X " + mState.getLoadedMembers().size() + " members for room " + mRoomId); mBackState = mState.deepCopy(); } } @@ -523,7 +523,6 @@ public void handleJoinedRoomSync(RoomSync roomSync, boolean isGlobalInitialSync) } // Finalize initial sync else { - if ((null != roomSync.timeline) && roomSync.timeline.limited) { // The room has been synced with a limited timeline mDataHandler.onRoomFlush(mRoomId); @@ -636,6 +635,20 @@ else if ((null != roomSync.state) && (null != roomSync.state.events) && (roomSyn mDataHandler.onNotificationCountUpdate(mRoomId); } } + + if(roomSync.roomSyncSummary != null) { + RoomSummary summary = mStore.getSummary(mRoomId); + + if(summary == null) { + // Should never happen here + Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!! RoomSummary is null !!!!!!!!!!!!!!!!!!!!!"); + } else { + summary.setRoomSyncSummary(roomSync.roomSyncSummary); + + mStore.flushSummary(summary); + } + } + } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 478c6407f..9723844aa 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -80,7 +80,6 @@ import java.io.File; import java.lang.reflect.Type; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -430,8 +429,13 @@ public boolean isLeaving() { return mIsLeaving; } - public Collection getMembers() { - return getState().getMembers(); + public void getMembersAsync(@NonNull final ApiCallback> callback) { + getState().getMembersAsync(new SimpleApiCallback>(callback) { + @Override + public void onSuccess(List members) { + callback.onSuccess(members); + } + }); } public EventTimeline getLiveTimeLine() { @@ -453,20 +457,24 @@ public boolean isReady() { /** * @return the list of active members in a room ie joined or invited ones. */ - public Collection getActiveMembers() { - Collection members = getState().getMembers(); - List activeMembers = new ArrayList<>(); - String conferenceUserId = MXCallsManager.getConferenceUserId(getRoomId()); - - for (RoomMember member : members) { - if (!TextUtils.equals(member.getUserId(), conferenceUserId)) { - if (TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_JOIN) || TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_INVITE)) { - activeMembers.add(member); + public void getActiveMembersAsync(@NonNull final ApiCallback> callback) { + getMembersAsync(new SimpleApiCallback>(callback) { + @Override + public void onSuccess(List members) { + List activeMembers = new ArrayList<>(); + String conferenceUserId = MXCallsManager.getConferenceUserId(getRoomId()); + + for (RoomMember member : members) { + if (!TextUtils.equals(member.getUserId(), conferenceUserId)) { + if (TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_JOIN) || TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_INVITE)) { + activeMembers.add(member); + } + } } - } - } - return activeMembers; + callback.onSuccess(activeMembers); + } + }); } /** @@ -474,17 +482,21 @@ public Collection getActiveMembers() { * * @return the list the joined members of the room. */ - public Collection getJoinedMembers() { - Collection membersList = getState().getMembers(); - List joinedMembersList = new ArrayList<>(); + public void getJoinedMembersAsync(final ApiCallback> callback) { + getMembersAsync(new SimpleApiCallback>(callback) { + @Override + public void onSuccess(List members) { + List joinedMembersList = new ArrayList<>(); - for (RoomMember member : membersList) { - if (TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_JOIN)) { - joinedMembersList.add(member); - } - } + for (RoomMember member : members) { + if (TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_JOIN)) { + joinedMembersList.add(member); + } + } - return joinedMembersList; + callback.onSuccess(joinedMembersList); + } + }); } public RoomMember getMember(String userId) { @@ -993,16 +1005,23 @@ public String getAvatarUrl() { // detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat) if (null == res) { - List members = new ArrayList<>(getState().getMembers()); + RoomSummary summary = getStore().getSummary(getRoomId()); - if (members.size() == 1) { - res = members.get(0).getAvatarUrl(); - } else if (members.size() == 2) { - RoomMember m1 = members.get(0); - RoomMember m2 = members.get(1); + // TODO LazyLoading + // Do something like: + // res = summary.getAvatarUrl(); + throw new RuntimeException("Not yet implemented"); - res = TextUtils.equals(m1.getUserId(), mMyUserId) ? m2.getAvatarUrl() : m1.getAvatarUrl(); - } + //List members = new ArrayList<>(getState().getMembers()); + // + //if (members.size() == 1) { + // res = members.get(0).getAvatarUrl(); + //} else if (members.size() == 2) { + // RoomMember m1 = members.get(0); + // RoomMember m2 = members.get(1); + // + // res = TextUtils.equals(m1.getUserId(), mMyUserId) ? m2.getAvatarUrl() : m1.getAvatarUrl(); + //} } return res; @@ -1015,6 +1034,12 @@ public String getAvatarUrl() { * @return the call avatar URL. */ public String getCallAvatarUrl() { + // TODO LazyLoading + // Do something like: + // res = summary.getAvatarUrl(); + throw new RuntimeException("Not yet implemented"); + + /* String avatarURL; List joinedMembers = new ArrayList<>(getJoinedMembers()); @@ -1033,6 +1058,7 @@ public String getCallAvatarUrl() { } return avatarURL; + */ } /** @@ -1874,24 +1900,27 @@ public static void fillThumbnailInfo(Context context, ImageMessage imageMessage, * @return true if a call can be performed. */ public boolean canPerformCall() { - return getActiveMembers().size() > 1; + return getNumberOfMembers() > 1; } /** * @return a list of callable members. */ - public List callees() { - List res = new ArrayList<>(); + public void callees(final ApiCallback> callback) { + getMembersAsync(new SimpleApiCallback>(callback) { + @Override + public void onSuccess(List info) { + List res = new ArrayList<>(); - Collection members = getMembers(); + for (RoomMember m : info) { + if (RoomMember.MEMBERSHIP_JOIN.equals(m.membership) && !mMyUserId.equals(m.getUserId())) { + res.add(m); + } + } - for (RoomMember m : members) { - if (RoomMember.MEMBERSHIP_JOIN.equals(m.membership) && !mMyUserId.equals(m.getUserId())) { - res.add(m); + callback.onSuccess(res); } - } - - return res; + }); } //================================================================================ @@ -3073,4 +3102,19 @@ public boolean isDirect() { return mDataHandler.getDirectChatRoomIdsList().contains(getRoomId()); } + public RoomSummary getRoomSummary() { + return getDataHandler().getStore().getSummary(getRoomId()); + } + + public int getNumberOfMembers() { + return getRoomSummary().getNumberOfJoinedMembers() + getRoomSummary().getNumberOfInvitedMembers(); + } + + public int getNumberOfJoinedMembers() { + return getRoomSummary().getNumberOfJoinedMembers(); + } + + public int getNumberOfInvitedMembers() { + return getRoomSummary().getNumberOfInvitedMembers(); + } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 957b860b6..b0f3e92e9 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -94,7 +94,7 @@ public class RoomState implements Externalizable { private Map mRoomAliases = new HashMap<>(); // the aliases are defined for each home server url - private Map> mAliasesByDomain = new HashMap(); + private Map> mAliasesByDomain = new HashMap<>(); // merged from mAliasesByHomeServerUrl private List mMergedAliasesList; @@ -168,9 +168,12 @@ public class RoomState implements Externalizable { // the associated token private String token; - // the room members + // the room members. May be a partial list if all members are not loaded yet, due to lazy loading private final Map mMembers = new HashMap<>(); + // true if all members are loaded + private boolean mAllMembersAreLoaded; + // the third party invite members private final Map mThirdPartyInvites = new HashMap<>(); @@ -190,11 +193,6 @@ public class RoomState implements Externalizable { */ private boolean mIsLive; - /** - * Tell if the room is a user conference user one - */ - private Boolean mIsConferenceUserRoom = null; - // the unitary tests crash when MXDataHandler type is set. private transient Object mDataHandler = null; @@ -256,9 +254,9 @@ public List getRelatedGroups() { } /** - * @return a copy of the room members list. + * @return a copy of the room members list. May be incomplete if the full list is not loaded yet */ - public Collection getMembers() { + public List getLoadedMembers() { List res; synchronized (this) { @@ -269,6 +267,43 @@ public Collection getMembers() { return res; } + /** + * Get the list of all the room members. Fetch from server if the full list is not loaded yet. + */ + public void getMembersAsync(final ApiCallback> callback) { + if (mAllMembersAreLoaded) { + List res; + + synchronized (this) { + // make a copy to avoid concurrency modifications + res = new ArrayList<>(mMembers.values()); + } + + callback.onSuccess(res); + } else { + // Load members from server + getDataHandler().getMembersAsync(roomId, new SimpleApiCallback>(callback) { + @Override + public void onSuccess(List info) { + List res; + + synchronized (this) { + for (RoomMember member : info) { + setMember(member.getUserId(), member); + } + + // make a copy to avoid concurrency modifications + res = new ArrayList<>(mMembers.values()); + + mAllMembersAreLoaded = true; + } + + callback.onSuccess(res); + } + }); + } + } + /** * Provides the loaded states event list. * The room member events are NOT included. @@ -348,18 +383,22 @@ public void onSuccess(List events) { * * @return a copy of the displayable room members list. */ - public Collection getDisplayableMembers() { - Collection members = getMembers(); - - RoomMember conferenceUserId = getMember(MXCallsManager.getConferenceUserId(roomId)); - - if (null != conferenceUserId) { - List membersList = new ArrayList<>(members); - membersList.remove(conferenceUserId); - members = membersList; - } + public void getDisplayableMembers(final ApiCallback> callback) { + getMembersAsync(new SimpleApiCallback>(callback) { + @Override + public void onSuccess(List members) { + RoomMember conferenceUserId = getMember(MXCallsManager.getConferenceUserId(roomId)); + + if (null != conferenceUserId) { + List membersList = new ArrayList<>(members); + membersList.remove(conferenceUserId); + callback.onSuccess(membersList); + } else { + callback.onSuccess(members); + } + } + }); - return members; } /** @@ -369,25 +408,7 @@ public Collection getDisplayableMembers() { * @return true if it is a call conference room. */ public boolean isConferenceUserRoom() { - // test if it is not yet initialized - if (null == mIsConferenceUserRoom) { - - mIsConferenceUserRoom = false; - - Collection members = getMembers(); - - // works only with 1:1 room - if (2 == members.size()) { - for (RoomMember member : members) { - if (MXCallsManager.isConferenceUserId(member.getUserId())) { - mIsConferenceUserRoom = true; - break; - } - } - } - } - - return mIsConferenceUserRoom; + return getDataHandler().getStore().getSummary(roomId).isConferenceUserRoom(); } /** @@ -396,7 +417,7 @@ public boolean isConferenceUserRoom() { * @param isConferenceUserRoom true when it is an user conference room. */ public void setIsConferenceUserRoom(boolean isConferenceUserRoom) { - mIsConferenceUserRoom = isConferenceUserRoom; + getDataHandler().getStore().getSummary(roomId).setIsConferenceUserRoom(isConferenceUserRoom); } /** @@ -405,7 +426,7 @@ public void setIsConferenceUserRoom(boolean isConferenceUserRoom) { * @param userId the user id. * @param member the new member value. */ - public void setMember(String userId, RoomMember member) { + private void setMember(String userId, RoomMember member) { // Populate a basic user object if there is none if (member.getUserId() == null) { member.setUserId(userId); @@ -424,6 +445,7 @@ public void setMember(String userId, RoomMember member) { * @param userId the user id. * @return the linked member it exists. */ + // TODO Change this? Can return null if all members are not loaded yet public RoomMember getMember(String userId) { RoomMember member; @@ -431,6 +453,10 @@ public RoomMember getMember(String userId) { member = mMembers.get(userId); } + if (member == null) { + Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Null member !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } + return member; } @@ -440,6 +466,7 @@ public RoomMember getMember(String userId) { * @param eventId the event id. * @return the linked member it exists. */ + // TODO Change this? Can return null if all members are not loaded yet public RoomMember getMemberByEventId(String eventId) { RoomMember member = null; @@ -452,6 +479,10 @@ public RoomMember getMemberByEventId(String eventId) { } } + if (member == null) { + Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Null member !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } + return member; } @@ -612,7 +643,7 @@ public RoomState deepCopy() { copy.mDataHandler = mDataHandler; copy.mMembership = mMembership; copy.mIsLive = mIsLive; - copy.mIsConferenceUserRoom = mIsConferenceUserRoom; + copy.mAllMembersAreLoaded = mAllMembersAreLoaded; copy.algorithm = algorithm; copy.mRoomAliases = new HashMap<>(mRoomAliases); copy.mStateEvents = new HashMap<>(mStateEvents); @@ -743,6 +774,7 @@ public void addAlias(String alias) { * @param selfUserId this user's user id (to exclude from members) * @return the display name */ + // TODO Use RoomSummary public String getDisplayName(String selfUserId) { String displayName = null; String alias = getAlias(); @@ -837,7 +869,7 @@ public boolean isEncrypted() { /** * @return true if the room is versioned, it means that the room is obsolete. - * You can't interact with it anymore, but you can still browse the past messages. + * You can't interact with it anymore, but you can still browse the past messages. */ public boolean isVersioned() { return mRoomTombstoneContent != null; @@ -1238,9 +1270,7 @@ public void readExternal(ObjectInput input) throws IOException, ClassNotFoundExc mIsLive = input.readBoolean(); - if (input.readBoolean()) { - mIsConferenceUserRoom = input.readBoolean(); - } + mAllMembersAreLoaded = input.readBoolean(); if (input.readBoolean()) { groups = (List) input.readObject(); @@ -1249,7 +1279,6 @@ public void readExternal(ObjectInput input) throws IOException, ClassNotFoundExc if (input.readBoolean()) { mRoomTombstoneContent = (RoomTombstoneContent) input.readObject(); } - } @Override @@ -1364,10 +1393,7 @@ public void writeExternal(ObjectOutput output) throws IOException { output.writeBoolean(mIsLive); - output.writeBoolean(null != mIsConferenceUserRoom); - if (null != mIsConferenceUserRoom) { - output.writeBoolean(mIsConferenceUserRoom); - } + output.writeBoolean(mAllMembersAreLoaded); output.writeBoolean(null != groups); if (null != groups) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index 63e93a4bc..f9f75a4cc 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -18,18 +18,23 @@ package org.matrix.androidsdk.data; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import org.matrix.androidsdk.call.MXCallsManager; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.EventContent; import org.matrix.androidsdk.rest.model.RoomMember; import org.matrix.androidsdk.rest.model.message.Message; +import org.matrix.androidsdk.rest.model.sync.RoomSyncSummary; import org.matrix.androidsdk.util.Log; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -75,6 +80,19 @@ public class RoomSummary implements java.io.Serializable { private String mMatrixId = null; + /** + * Tell if the room is a user conference user one + */ + private Boolean mIsConferenceUserRoom = null; + + /** + * Data from RoomSyncSummary + */ + private List mHeroes = new ArrayList<>(); + + private int mJoinedMembersCountFromSyncRoomSummary; + + private int mInvitedMembersCountFromSyncRoomSummary; public RoomSummary() { } @@ -122,6 +140,10 @@ public RoomSummary(@Nullable RoomSummary fromSummary, setUnreadEventsCount(fromSummary.getUnreadEventsCount()); setHighlightCount(fromSummary.getHighlightCount()); setNotificationCount(fromSummary.getNotificationCount()); + + mHeroes.addAll(fromSummary.mHeroes); + mJoinedMembersCountFromSyncRoomSummary = fromSummary.mJoinedMembersCountFromSyncRoomSummary; + mInvitedMembersCountFromSyncRoomSummary = fromSummary.mInvitedMembersCountFromSyncRoomSummary; } } @@ -521,4 +543,62 @@ public void setRoomTags(final Set roomTags) { mRoomTags = new HashSet<>(); } } + + public boolean isConferenceUserRoom() { + // test if it is not yet initialized + if (null == mIsConferenceUserRoom) { + + mIsConferenceUserRoom = false; + + // FIXME Heroes does not contains me + // FIXME I'ms not sure this code will work anymore + + Collection membersId = getHeroes(); + + // works only with 1:1 room + if (2 == membersId.size()) { + for (String userId : membersId) { + if (MXCallsManager.isConferenceUserId(userId)) { + mIsConferenceUserRoom = true; + break; + } + } + } + } + + return mIsConferenceUserRoom; + } + + public void setIsConferenceUserRoom(boolean isConferenceUserRoom) { + mIsConferenceUserRoom = isConferenceUserRoom; + } + + public void setRoomSyncSummary(@NonNull RoomSyncSummary roomSyncSummary) { + if (roomSyncSummary.mHeroes != null) { + mHeroes.clear(); + mHeroes.addAll(roomSyncSummary.mHeroes); + } + + if (roomSyncSummary.mJoinedMembersCount != null) { + // Update the value + mJoinedMembersCountFromSyncRoomSummary = roomSyncSummary.mJoinedMembersCount; + } + + if (roomSyncSummary.mInvitedMembersCount != null) { + // Update the value + mInvitedMembersCountFromSyncRoomSummary = roomSyncSummary.mInvitedMembersCount; + } + } + + public List getHeroes() { + return mHeroes; + } + + public int getNumberOfJoinedMembers() { + return mJoinedMembersCountFromSyncRoomSummary; + } + + public int getNumberOfInvitedMembers() { + return mInvitedMembersCountFromSyncRoomSummary; + } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java index a9f466b7d..dc350c3dd 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java @@ -404,7 +404,7 @@ public interface IMXStore { void flushSummary(RoomSummary summary); /** - * Flush the room summmaries + * Flush the room summaries */ void flushSummaries(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java index eabbb7cda..8726f6428 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java @@ -402,7 +402,7 @@ public void run() { Collection rooms = getRooms(); for (Room room : rooms) { - Collection members = room.getState().getMembers(); + Collection members = room.getState().getLoadedMembers(); for (RoomMember member : members) { updateUserWithRoomMemberEvent(member); } @@ -501,10 +501,10 @@ public void run() { Room room = getRoom(roomId); if ((null != room) && (null != room.getState())) { - int membersCount = room.getState().getMembers().size(); + int membersCount = room.getState().getLoadedMembers().size(); int eventsCount = mRoomEvents.get(roomId).size(); - Log.d(LOG_TAG, " room " + roomId + " : membersCount " + membersCount + " - eventsCount " + eventsCount); + Log.d(LOG_TAG, " room " + roomId + " : (lazy loaded) membersCount " + membersCount + " - eventsCount " + eventsCount); } } @@ -1574,7 +1574,7 @@ private void saveRoomState(final String roomId) { if (null != room) { long start1 = System.currentTimeMillis(); writeObject("saveRoomsState " + roomId, roomStateFile, room.getState()); - Log.d(LOG_TAG, "saveRoomsState " + room.getState().getMembers().size() + " members : " + (System.currentTimeMillis() - start1) + " ms"); + Log.d(LOG_TAG, "saveRoomsState " + room.getNumberOfMembers() + " members : " + (System.currentTimeMillis() - start1) + " ms"); } else { Log.d(LOG_TAG, "saveRoomsState : delete the room state"); deleteRoomStateFile(roomId); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index db606d5a2..f7459ad06 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -150,10 +150,10 @@ public interface RoomsApi { /** * Send a generic state events * - * @param roomId the room id. + * @param roomId the room id. * @param stateEventType the state event type * @param stateKey the state keys - * @param params the request parameters + * @param params the request parameters */ @PUT("rooms/{roomId}/state/{state_event_type}/{stateKey}") Call sendStateEvent(@Path("roomId") String roomId, @@ -370,8 +370,8 @@ Call> getRoomMessagesFrom(@Path("roomId") String room /** * Send read markers. * - * @param roomId the room id - * @param markers the read markers + * @param roomId the room id + * @param markers the read markers */ @POST("rooms/{roomId}/read_markers") Call sendReadMarker(@Path("roomId") String roomId, @Body Map markers); @@ -453,4 +453,13 @@ Call updateAccountData(@Path("userId") String userId, */ @GET("directory/list/room/{roomId}") Call getRoomDirectoryVisibility(@Path("roomId") String roomId); + + /** + * Get all members of a room + * TODO handle the token id as a parameter + * + * @param roomId the room id where to get the members + */ + @GET("directory/list/room/{roomId}") + Call> getMembers(@Path("roomId") String roomId); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index eca9603d2..60f7e4001 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -87,11 +87,11 @@ public void sendMessage(final String transactionId, final String roomId, final M // the messages have their dedicated method in MXSession to be resent if there is no available network mApi.sendMessage(transactionId, roomId, message) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - sendMessage(transactionId, roomId, message, callback); - } - })); + @Override + public void onRetry() { + sendMessage(transactionId, roomId, message, callback); + } + })); } /** @@ -117,11 +117,11 @@ public void sendEventToRoom(final String transactionId, if (!TextUtils.equals(eventType, Event.EVENT_TYPE_CALL_INVITE)) { mApi.send(transactionId, roomId, eventType, content) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - sendEventToRoom(transactionId, roomId, eventType, content, callback); - } - })); + @Override + public void onRetry() { + sendEventToRoom(transactionId, roomId, eventType, content, callback); + } + })); } else { mApi.send(transactionId, roomId, eventType, content) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, null)); @@ -148,11 +148,11 @@ public void getRoomMessagesFrom(final String roomId, mApi.getRoomMessagesFrom(roomId, (direction == EventTimeline.Direction.BACKWARDS) ? "b" : "f", fromToken, limit) .enqueue(new RestAdapterCallback>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getRoomMessagesFrom(roomId, fromToken, direction, limit, callback); - } - })); + @Override + public void onRetry() { + getRoomMessagesFrom(roomId, fromToken, direction, limit, callback); + } + })); } /** @@ -170,11 +170,11 @@ public void inviteUserToRoom(final String roomId, final String userId, final Api mApi.invite(roomId, user) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - inviteUserToRoom(roomId, userId, callback); - } - })); + @Override + public void onRetry() { + inviteUserToRoom(roomId, userId, callback); + } + })); } /** @@ -217,11 +217,11 @@ private void inviteThreePidToRoom(final String medium, final String address, fin mApi.invite(roomId, parameters) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - inviteThreePidToRoom(medium, address, roomId, callback); - } - })); + @Override + public void onRetry() { + inviteThreePidToRoom(medium, address, roomId, callback); + } + })); } /** @@ -246,11 +246,11 @@ public void joinRoom(final String roomIdOrAlias, final Map param mApi.joinRoomByAliasOrId(roomIdOrAlias, (null == params) ? new HashMap() : params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - joinRoom(roomIdOrAlias, params, callback); - } - })); + @Override + public void onRetry() { + joinRoom(roomIdOrAlias, params, callback); + } + })); } /** @@ -264,11 +264,11 @@ public void leaveRoom(final String roomId, final ApiCallback callback) { mApi.leave(roomId, new JsonObject()) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - leaveRoom(roomId, callback); - } - })); + @Override + public void onRetry() { + leaveRoom(roomId, callback); + } + })); } /** @@ -282,11 +282,11 @@ public void forgetRoom(final String roomId, final ApiCallback callback) { mApi.forget(roomId, new JsonObject()) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - forgetRoom(roomId, callback); - } - })); + @Override + public void onRetry() { + forgetRoom(roomId, callback); + } + })); } /** @@ -305,11 +305,11 @@ public void kickFromRoom(final String roomId, final String userId, final ApiCall mApi.updateRoomMember(roomId, userId, member) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - kickFromRoom(roomId, userId, callback); - } - })); + @Override + public void onRetry() { + kickFromRoom(roomId, userId, callback); + } + })); } /** @@ -324,11 +324,11 @@ public void banFromRoom(final String roomId, final BannedUser user, final ApiCal mApi.ban(roomId, user) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - banFromRoom(roomId, user, callback); - } - })); + @Override + public void onRetry() { + banFromRoom(roomId, user, callback); + } + })); } /** @@ -343,11 +343,11 @@ public void unbanFromRoom(final String roomId, final BannedUser user, final ApiC mApi.unban(roomId, user) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - unbanFromRoom(roomId, user, callback); - } - })); + @Override + public void onRetry() { + unbanFromRoom(roomId, user, callback); + } + })); } /** @@ -364,11 +364,11 @@ public void createRoom(final CreateRoomParams params, final ApiCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - createRoom(params, callback); - } - })); + @Override + public void onRetry() { + createRoom(params, callback); + } + })); } /** @@ -446,11 +446,11 @@ private void getEventFromRoomIdEventId(final String roomId, final String eventId mApi.getEvent(roomId, eventId) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getEventFromRoomIdEventId(roomId, eventId, callback); - } - })); + @Override + public void onRetry() { + getEventFromRoomIdEventId(roomId, eventId, callback); + } + })); } /** @@ -464,11 +464,11 @@ private void getEventFromEventId(final String eventId, final ApiCallback mApi.getEvent(eventId) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getEventFromEventId(eventId, callback); - } - })); + @Override + public void onRetry() { + getEventFromEventId(eventId, callback); + } + })); } @@ -485,11 +485,11 @@ public void getContextOfEvent(final String roomId, final String eventId, final i mApi.getContextOfEvent(roomId, eventId, limit) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getContextOfEvent(roomId, eventId, limit, callback); - } - })); + @Override + public void onRetry() { + getContextOfEvent(roomId, eventId, limit, callback); + } + })); } /** @@ -507,11 +507,11 @@ public void updateRoomName(final String roomId, final String name, final ApiCall mApi.setRoomName(roomId, roomState) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateRoomName(roomId, name, callback); - } - })); + @Override + public void onRetry() { + updateRoomName(roomId, name, callback); + } + })); } /** @@ -529,11 +529,11 @@ public void updateCanonicalAlias(final String roomId, final String canonicalAlia mApi.setCanonicalAlias(roomId, roomState) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateCanonicalAlias(roomId, canonicalAlias, callback); - } - })); + @Override + public void onRetry() { + updateCanonicalAlias(roomId, canonicalAlias, callback); + } + })); } /** @@ -551,11 +551,11 @@ public void updateHistoryVisibility(final String roomId, final String aVisibilit mApi.setHistoryVisibility(roomId, roomState) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateHistoryVisibility(roomId, aVisibility, callback); - } - })); + @Override + public void onRetry() { + updateHistoryVisibility(roomId, aVisibility, callback); + } + })); } /** @@ -573,11 +573,11 @@ public void updateDirectoryVisibility(final String aRoomId, final String aDirect mApi.setRoomDirectoryVisibility(aRoomId, roomState) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateDirectoryVisibility(aRoomId, aDirectoryVisibility, callback); - } - })); + @Override + public void onRetry() { + updateDirectoryVisibility(aRoomId, aDirectoryVisibility, callback); + } + })); } @@ -588,15 +588,31 @@ public void onRetry() { * @param callback on success callback containing a RoomState object populated with the directory visibility */ public void getDirectoryVisibility(final String aRoomId, final ApiCallback callback) { - final String description = "getRoomDirectoryVisibility userId=" + aRoomId; + final String description = "getDirectoryVisibility roomId=" + aRoomId; mApi.getRoomDirectoryVisibility(aRoomId) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getDirectoryVisibility(aRoomId, callback); - } - })); + @Override + public void onRetry() { + getDirectoryVisibility(aRoomId, callback); + } + })); + } + + /** + * Get the room members + * // TODO Add token as a parameter + */ + public void getRoomMembers(final String roomId, final ApiCallback> callback) { + final String description = "getRoomMembers roomId=" + roomId; + + mApi.getMembers(roomId) + .enqueue(new RestAdapterCallback>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { + @Override + public void onRetry() { + getRoomMembers(roomId, callback); + } + })); } /** @@ -614,11 +630,11 @@ public void updateTopic(final String roomId, final String topic, final ApiCallba mApi.setRoomTopic(roomId, roomState) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateTopic(roomId, topic, callback); - } - })); + @Override + public void onRetry() { + updateTopic(roomId, topic, callback); + } + })); } /** @@ -633,11 +649,11 @@ public void redactEvent(final String roomId, final String eventId, final ApiCall mApi.redactEvent(roomId, eventId, new JsonObject()) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - redactEvent(roomId, eventId, callback); - } - })); + @Override + public void onRetry() { + redactEvent(roomId, eventId, callback); + } + })); } /** @@ -659,11 +675,11 @@ public void reportEvent(final String roomId, final String eventId, final int sco mApi.reportEvent(roomId, eventId, content) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - reportEvent(roomId, eventId, score, reason, callback); - } - })); + @Override + public void onRetry() { + reportEvent(roomId, eventId, score, reason, callback); + } + })); } /** @@ -678,11 +694,11 @@ public void updatePowerLevels(final String roomId, final PowerLevels powerLevels mApi.setPowerLevels(roomId, powerLevels) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updatePowerLevels(roomId, powerLevels, callback); - } - })); + @Override + public void onRetry() { + updatePowerLevels(roomId, powerLevels, callback); + } + })); } /** @@ -704,19 +720,19 @@ public void sendStateEvent(final String roomId, if (null != stateKey) { mApi.sendStateEvent(roomId, eventType, stateKey, params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - sendStateEvent(roomId, eventType, stateKey, params, callback); - } - })); + @Override + public void onRetry() { + sendStateEvent(roomId, eventType, stateKey, params, callback); + } + })); } else { mApi.sendStateEvent(roomId, eventType, params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - sendStateEvent(roomId, eventType, null, params, callback); - } - })); + @Override + public void onRetry() { + sendStateEvent(roomId, eventType, null, params, callback); + } + })); } } @@ -732,11 +748,11 @@ public void getStateEvent(final String roomId, final String eventType, final Api mApi.getStateEvent(roomId, eventType) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getStateEvent(roomId, eventType, callback); - } - })); + @Override + public void onRetry() { + getStateEvent(roomId, eventType, callback); + } + })); } /** @@ -752,11 +768,11 @@ public void getStateEvent(final String roomId, final String eventType, final Str mApi.getStateEvent(roomId, eventType, stateKey) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getStateEvent(roomId, eventType, stateKey, callback); - } - })); + @Override + public void onRetry() { + getStateEvent(roomId, eventType, stateKey, callback); + } + })); } /** @@ -798,11 +814,11 @@ public void updateAvatarUrl(final String roomId, final String avatarUrl, final A mApi.setRoomAvatarUrl(roomId, params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateAvatarUrl(roomId, avatarUrl, callback); - } - })); + @Override + public void onRetry() { + updateAvatarUrl(roomId, avatarUrl, callback); + } + })); } /** @@ -827,12 +843,12 @@ public void sendReadMarker(final String roomId, final String rmEventId, final St mApi.sendReadMarker(roomId, params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, true, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - sendReadMarker(roomId, rmEventId, rrEventId, callback); - } - })); + new RestAdapterCallback.RequestRetryCallBack() { + @Override + public void onRetry() { + sendReadMarker(roomId, rmEventId, rrEventId, callback); + } + })); } /** @@ -852,11 +868,11 @@ public void addTag(final String roomId, final String tag, final Double order, fi mApi.addTag(mCredentials.userId, roomId, tag, hashMap) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - addTag(roomId, tag, order, callback); - } - })); + @Override + public void onRetry() { + addTag(roomId, tag, order, callback); + } + })); } /** @@ -871,11 +887,11 @@ public void removeTag(final String roomId, final String tag, final ApiCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - removeTag(roomId, tag, callback); - } - })); + @Override + public void onRetry() { + removeTag(roomId, tag, callback); + } + })); } /** @@ -893,11 +909,11 @@ public void updateURLPreviewStatus(final String roomId, final boolean status, fi mApi.updateAccountData(mCredentials.userId, roomId, Event.EVENT_TYPE_URL_PREVIEW, params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateURLPreviewStatus(roomId, status, callback); - } - })); + @Override + public void onRetry() { + updateURLPreviewStatus(roomId, status, callback); + } + })); } /** @@ -912,11 +928,11 @@ public void getRoomIdByAlias(final String roomAlias, final ApiCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getRoomIdByAlias(roomAlias, callback); - } - })); + @Override + public void onRetry() { + getRoomIdByAlias(roomAlias, callback); + } + })); } /** @@ -934,11 +950,11 @@ public void setRoomIdByAlias(final String roomId, final String roomAlias, final mApi.setRoomIdByAlias(roomAlias, roomAliasDescription) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - setRoomIdByAlias(roomId, roomAlias, callback); - } - })); + @Override + public void onRetry() { + setRoomIdByAlias(roomId, roomAlias, callback); + } + })); } /** @@ -952,11 +968,11 @@ public void removeRoomAlias(final String roomAlias, final ApiCallback call mApi.removeRoomAlias(roomAlias) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - removeRoomAlias(roomAlias, callback); - } - })); + @Override + public void onRetry() { + removeRoomAlias(roomAlias, callback); + } + })); } /** @@ -976,11 +992,11 @@ public void updateJoinRules(final String aRoomId, final String aJoinRule, final mApi.setJoinRules(aRoomId, roomStateParam) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateJoinRules(aRoomId, aJoinRule, callback); - } - })); + @Override + public void onRetry() { + updateJoinRules(aRoomId, aJoinRule, callback); + } + })); } /** @@ -1000,10 +1016,10 @@ public void updateGuestAccess(final String aRoomId, final String aGuestAccessRul mApi.setGuestAccess(aRoomId, roomStateParam) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - updateGuestAccess(aRoomId, aGuestAccessRule, callback); - } - })); + @Override + public void onRetry() { + updateGuestAccess(aRoomId, aGuestAccessRule, callback); + } + })); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomEventFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomEventFilter.java new file mode 100644 index 000000000..132ad280f --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomEventFilter.java @@ -0,0 +1,47 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class RoomEventFilter { + @SerializedName("limit") + Integer maxNumberOfEvents; + + @SerializedName("not_senders") + List mSenderIdsToExclude; + + @SerializedName("not_types") + List mTypesToExclude; + + @SerializedName("senders") + List mSenderIds; + + @SerializedName("types") + List mTypes; + + @SerializedName("not_rooms") + List mRoomIdsToExclude; + + @SerializedName("rooms") + List mRooms; + + @SerializedName("contains_url") + String mContainsUrl; +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/bingrules/RoomMemberCountCondition.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/bingrules/RoomMemberCountCondition.java index 948e83f70..70d9e8b0c 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/bingrules/RoomMemberCountCondition.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/bingrules/RoomMemberCountCondition.java @@ -1,6 +1,7 @@ /* * Copyright 2014 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -17,9 +18,6 @@ import org.matrix.androidsdk.util.Log; import org.matrix.androidsdk.data.Room; -import org.matrix.androidsdk.rest.model.RoomMember; - -import java.util.Collection; public class RoomMemberCountCondition extends Condition { @@ -42,6 +40,7 @@ public String toString() { return "RoomMemberCountCondition{" + "is='" + is + "'}'"; } + @SuppressWarnings("SimplifiableIfStatement") public boolean isSatisfied(Room room) { // sanity check if (room == null) return false; @@ -54,7 +53,8 @@ public boolean isSatisfied(Room room) { if (parseError) return false; } - int numMembers = getNumberOfMembers(room); + int numMembers = room.getNumberOfJoinedMembers(); + if ("==".equals(comparisonPrefix) || "".equals(comparisonPrefix)) { return numMembers == limit; } @@ -70,25 +70,8 @@ public boolean isSatisfied(Room room) { if (">=".equals(comparisonPrefix)) { return numMembers >= limit; } - return false; - } - /** - * Count joined room members in the room. - * - * @param room the room - * @return the number of joined members - */ - private int getNumberOfMembers(Room room) { - Collection members = room.getMembers(); - int n = 0; - - for (RoomMember member : members) { - if (RoomMember.MEMBERSHIP_JOIN.equals(member.membership)) { - n++; - } - } - return n; + return false; } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupSyncProfile.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupSyncProfile.java index db1b2a32d..725d42e50 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupSyncProfile.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupSyncProfile.java @@ -1,5 +1,6 @@ /* * Copyright 2014 OpenMarket Ltd + * Copyright 2018 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +21,7 @@ /** * Group sync profile */ -public class GroupSyncProfile implements Serializable { +public class GroupSyncProfile { /** * The name of the group, if any. May be nil. */ diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupsSyncResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupsSyncResponse.java index d72e97607..b511fb33d 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupsSyncResponse.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupsSyncResponse.java @@ -1,5 +1,6 @@ /* * Copyright 2014 OpenMarket Ltd + * Copyright 2018 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +22,7 @@ /** * Group sync response */ -public class GroupsSyncResponse implements Serializable { +public class GroupsSyncResponse { /** * Joined groups: An array of groups ids. */ diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/InvitedGroupSync.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/InvitedGroupSync.java index 32ef63e72..b9fc524f2 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/InvitedGroupSync.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/InvitedGroupSync.java @@ -1,5 +1,6 @@ /* * Copyright 2014 OpenMarket Ltd + * Copyright 2018 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +21,7 @@ /** * invited group sync */ -public class InvitedGroupSync implements Serializable { +public class InvitedGroupSync { /** * The identifier of the inviter. */ diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/DeviceOneTimeKeysCountSyncResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/DeviceOneTimeKeysCountSyncResponse.java index c18f48cfc..ccef05a2b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/DeviceOneTimeKeysCountSyncResponse.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/DeviceOneTimeKeysCountSyncResponse.java @@ -1,6 +1,7 @@ /* * Copyright 2016 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -16,7 +17,7 @@ package org.matrix.androidsdk.rest.model.sync; -public class DeviceOneTimeKeysCountSyncResponse implements java.io.Serializable { +public class DeviceOneTimeKeysCountSyncResponse { public Integer signed_curve25519; } \ No newline at end of file diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/PresenceSyncResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/PresenceSyncResponse.java index d6c8d3b5f..6d95ef8c8 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/PresenceSyncResponse.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/PresenceSyncResponse.java @@ -1,6 +1,7 @@ /* * Copyright 2016 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -19,8 +20,8 @@ import java.util.List; -// PresenceSyncResponse represents the updates to the presence status of other users during server sync v2. -public class PresenceSyncResponse implements java.io.Serializable { +// PresenceSyncResponse represents the updates to the presence status of other users during server sync v2. +public class PresenceSyncResponse { /** * List of presence events (array of Event with type m.presence). diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSync.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSync.java index 3010962bb..cb9b2c959 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSync.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSync.java @@ -1,6 +1,7 @@ /* * Copyright 2016 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -15,8 +16,10 @@ */ package org.matrix.androidsdk.rest.model.sync; +import com.google.gson.annotations.SerializedName; + // RoomSync represents the response for a room during server sync v2. -public class RoomSync implements java.io.Serializable { +public class RoomSync { /** * The state updates for the room. */ @@ -42,4 +45,10 @@ public class RoomSync implements java.io.Serializable { */ public RoomSyncUnreadNotifications unreadNotifications; + /** + * The room summary + */ + @SerializedName("summary") + public RoomSyncSummary roomSyncSummary; + } \ No newline at end of file diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncAccountData.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncAccountData.java index 4575f1ae7..f7c2aa088 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncAccountData.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncAccountData.java @@ -1,6 +1,7 @@ /* * Copyright 2016 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -20,7 +21,7 @@ import java.util.List; // RoomSyncAccountData represents the account data events for a room. -public class RoomSyncAccountData implements java.io.Serializable { +public class RoomSyncAccountData { /** * List of account data events (array of Event). */ diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncEphemeral.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncEphemeral.java index 8af568f76..9507de443 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncEphemeral.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncEphemeral.java @@ -1,6 +1,7 @@ /* * Copyright 2016 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -20,9 +21,9 @@ import java.util.List; // RoomSyncEphemeral represents the ephemeral events in the room that aren't recorded in the timeline or state of the room (e.g. typing). -public class RoomSyncEphemeral implements java.io.Serializable { +public class RoomSyncEphemeral { /** - * List of ephemeral events (array of Event). + * List of ephemeral events. */ public List events; } \ No newline at end of file diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncState.java index 8009d6e49..1f535d6ae 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncState.java @@ -1,6 +1,7 @@ /* * Copyright 2016 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -20,10 +21,10 @@ import java.util.List; // RoomSyncState represents the state updates for a room during server sync v2. -public class RoomSyncState implements java.io.Serializable { +public class RoomSyncState { /** - * List of state events (array of Event). The resulting state corresponds to the *start* of the timeline. + * List of state events. The resulting state corresponds to the *start* of the timeline. */ public List events; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncSummary.java new file mode 100644 index 000000000..451a035f7 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncSummary.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model.sync; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +/** + * See https://docs.google.com/document/d/11i14UI1cUz-OJ0knD5BFu7fmT6Fo327zvMYqfSAR7xs + */ +public class RoomSyncSummary { + + /** + * Present only if the room has no m.room.name or m.room.canonical_alias. + *

+ * Lists the mxids of the first 5 members in the room who are currently joined or invited (ordered by stream ordering as seen on the server, + * to avoid it jumping around if/when topological order changes). As the heroes’ membership status changes, the list changes appropriately + * (sending the whole new list in the next /sync response). This list always excludes the current logged in user. If there are no joined or + * invited users, it lists the parted and banned ones instead. Servers can choose to send more or less than 5 members if they must, but 5 + * seems like a good enough number for most naming purposes. Clients should use all the provided members to name the room, but may truncate + * the list if helpful for UX + */ + @SerializedName("m.heroes") + public List mHeroes; + + /** + * The number of m.room.members in state 'joined' (including the syncing user) (can be null) + */ + @SerializedName("m.joined_member_count") + public Integer mJoinedMembersCount; + + /** + * The number of m.room.members in state 'invited' (can be null) + */ + @SerializedName("m.invited_member_count") + public Integer mInvitedMembersCount; +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncTimeline.java index 293de7c9f..e7ea2418a 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncTimeline.java @@ -1,6 +1,7 @@ /* * Copyright 2016 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -20,10 +21,10 @@ import java.util.List; // RoomSyncTimeline represents the timeline of messages and state changes for a room during server sync v2. -public class RoomSyncTimeline implements java.io.Serializable { +public class RoomSyncTimeline { /** - * List of events (array of Event). + * List of events. */ public List events; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncUnreadNotifications.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncUnreadNotifications.java index 9cae33c2e..d9cf25605 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncUnreadNotifications.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncUnreadNotifications.java @@ -1,6 +1,7 @@ /* * Copyright 2016 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -22,19 +23,19 @@ /** `MXRoomSyncUnreadNotifications` represents the unread counts for a room. */ -public class RoomSyncUnreadNotifications implements java.io.Serializable { +public class RoomSyncUnreadNotifications { /** * List of account data events (array of Event). */ public List events; /** - The number of unread messages that match the push notification rules. + * The number of unread messages that match the push notification rules. */ public Integer notificationCount; /** - The number of highlighted unread messages (subset of notifications). + * The number of highlighted unread messages (subset of notifications). */ public Integer highlightCount; } \ No newline at end of file diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomsSyncResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomsSyncResponse.java index d6c9500bb..5cefdb298 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomsSyncResponse.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomsSyncResponse.java @@ -1,6 +1,7 @@ /* * Copyright 2016 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -18,7 +19,7 @@ import java.util.Map; // RoomsSyncResponse represents the rooms list in server sync v2 response. -public class RoomsSyncResponse implements java.io.Serializable { +public class RoomsSyncResponse { /** * Joined rooms: keys are rooms ids. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/SyncResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/SyncResponse.java index 52348741d..81dc6dd8e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/SyncResponse.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/SyncResponse.java @@ -1,6 +1,7 @@ /* * Copyright 2016 OpenMarket Ltd * Copyright 2017 Vector Creations Ltd + * Copyright 2018 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +23,7 @@ import java.util.Map; // SyncResponse represents the request response for server sync v2. -public class SyncResponse implements java.io.Serializable { +public class SyncResponse { /** * The user private data. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/ToDeviceSyncResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/ToDeviceSyncResponse.java index 2bed8f576..4e71e440c 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/ToDeviceSyncResponse.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/ToDeviceSyncResponse.java @@ -1,6 +1,7 @@ /* * Copyright 2016 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -21,7 +22,7 @@ import java.util.List; // ToDeviceSyncResponse represents the data directly sent to one of user's devices. -public class ToDeviceSyncResponse implements java.io.Serializable { +public class ToDeviceSyncResponse { /** * List of direct-to-device events. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java index bc89c34dc..4d7f6420a 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java @@ -59,6 +59,12 @@ public class EventsThread extends Thread { private static final int DEFAULT_SERVER_TIMEOUT_MS = 30000; private static final int DEFAULT_CLIENT_TIMEOUT_MS = 120000; + // TODO LazyLoading + // private static final String DATA_SAVE_MODE_FILTER = "{\"room\": {\"ephemeral\": {\"types\": [\"m.receipt\"]}}, \"presence\":{\"not_types\": [\"*\"]}}"; + // TODO filter to get RoomSyncSummary + private static final String DATA_SAVE_MODE_FILTER = "{\"room\": {\"state\":{\"lazy_load_members\":true}, \"ephemeral\": {\"types\": [\"m.receipt\"]}}, \"presence\":{\"not_types\": [\"*\"]}}"; + private static final String LAZY_LOADING_FILTER = "{\"room\":{\"state\":{\"lazy_load_members\":true}}}"; + private EventsRestClient mEventsRestClient; private EventsThreadListener mListener; private String mCurrentToken; From 4e4e7893941961fea6dde21e2072641754761e6b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 14 Aug 2018 17:09:18 +0200 Subject: [PATCH 080/236] LazyLoading WIP --- .../src/main/java/org/matrix/androidsdk/MXDataHandler.java | 6 ++++-- .../main/java/org/matrix/androidsdk/rest/api/RoomsApi.java | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 4b737b5ef..1b4da40b1 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -946,8 +946,10 @@ public void getMembersAsync(final String roomId, final ApiCallback info) { Room room = getRoom(roomId); - for (Event event : info.chunk) { - room.getState().applyState(getStore(), event, EventTimeline.Direction.FORWARDS); + if (info.chunk != null) { + for (Event event : info.chunk) { + room.getState().applyState(getStore(), event, EventTimeline.Direction.FORWARDS); + } } callback.onSuccess(room.getState().getLoadedMembers()); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index f7459ad06..8fc464b7f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -460,6 +460,6 @@ Call updateAccountData(@Path("userId") String userId, * * @param roomId the room id where to get the members */ - @GET("directory/list/room/{roomId}") + @GET("rooms/{roomId}/members") Call> getMembers(@Path("roomId") String roomId); } From b46eb63da8c76a33cdf68f58e52cacbeab3e3622 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 23 Aug 2018 09:48:47 +0200 Subject: [PATCH 081/236] Stack callbacks to avoid requested several times the room members --- .../org/matrix/androidsdk/data/RoomState.java | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index b0f3e92e9..dfdd3693b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -174,6 +174,8 @@ public class RoomState implements Externalizable { // true if all members are loaded private boolean mAllMembersAreLoaded; + private List>> mGetAllMembersCallbacks = new ArrayList<>(); + // the third party invite members private final Map mThirdPartyInvites = new HashMap<>(); @@ -270,7 +272,7 @@ public List getLoadedMembers() { /** * Get the list of all the room members. Fetch from server if the full list is not loaded yet. */ - public void getMembersAsync(final ApiCallback> callback) { + public void getMembersAsync(ApiCallback> callback) { if (mAllMembersAreLoaded) { List res; @@ -281,26 +283,42 @@ public void getMembersAsync(final ApiCallback> callback) { callback.onSuccess(res); } else { - // Load members from server - getDataHandler().getMembersAsync(roomId, new SimpleApiCallback>(callback) { - @Override - public void onSuccess(List info) { - List res; + boolean doTheRequest; + + synchronized (mGetAllMembersCallbacks) { + mGetAllMembersCallbacks.add(callback); + + doTheRequest = mGetAllMembersCallbacks.size() == 1; + } + + if (doTheRequest) { + // Load members from server + getDataHandler().getMembersAsync(roomId, new SimpleApiCallback>(callback) { + @Override + public void onSuccess(List info) { + List res; - synchronized (this) { for (RoomMember member : info) { setMember(member.getUserId(), member); } - // make a copy to avoid concurrency modifications - res = new ArrayList<>(mMembers.values()); + synchronized (mGetAllMembersCallbacks) { + for (ApiCallback> apiCallback : mGetAllMembersCallbacks) { + synchronized (this) { + // make a copy to avoid concurrency modifications + res = new ArrayList<>(mMembers.values()); + } + + apiCallback.onSuccess(res); + } + + mGetAllMembersCallbacks.clear(); + } mAllMembersAreLoaded = true; } - - callback.onSuccess(res); - } - }); + }); + } } } @@ -381,7 +399,7 @@ public void onSuccess(List events) { * Provides a list of displayable members. * Some dummy members are created to internal stuff. * - * @return a copy of the displayable room members list. + * @param callback The callback to get a copy of the displayable room members list. */ public void getDisplayableMembers(final ApiCallback> callback) { getMembersAsync(new SimpleApiCallback>(callback) { @@ -398,7 +416,6 @@ public void onSuccess(List members) { } } }); - } /** From 08141164fc8c6b53933ce7b5952be78856e196ad Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 23 Aug 2018 16:07:00 +0200 Subject: [PATCH 082/236] Get AvatarUrl from lazy loaded members --- .../java/org/matrix/androidsdk/data/Room.java | 44 +++++++------------ 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 9723844aa..eddfd3821 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -1000,28 +1000,20 @@ public void onSuccess(Void info) { /** * @return the room avatar URL. If there is no defined one, use the members one (1:1 chat only). */ + @Nullable public String getAvatarUrl() { String res = getState().getAvatarUrl(); // detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat) if (null == res) { - RoomSummary summary = getStore().getSummary(getRoomId()); + if (getNumberOfMembers() == 1 && !getState().getLoadedMembers().isEmpty()) { + res = getState().getLoadedMembers().get(0).getAvatarUrl(); + } else if (getNumberOfMembers() == 2 && getState().getLoadedMembers().size() > 1) { + RoomMember m1 = getState().getLoadedMembers().get(0); + RoomMember m2 = getState().getLoadedMembers().get(1); - // TODO LazyLoading - // Do something like: - // res = summary.getAvatarUrl(); - throw new RuntimeException("Not yet implemented"); - - //List members = new ArrayList<>(getState().getMembers()); - // - //if (members.size() == 1) { - // res = members.get(0).getAvatarUrl(); - //} else if (members.size() == 2) { - // RoomMember m1 = members.get(0); - // RoomMember m2 = members.get(1); - // - // res = TextUtils.equals(m1.getUserId(), mMyUserId) ? m2.getAvatarUrl() : m1.getAvatarUrl(); - //} + res = TextUtils.equals(m1.getUserId(), mMyUserId) ? m2.getAvatarUrl() : m1.getAvatarUrl(); + } } return res; @@ -1033,24 +1025,19 @@ public String getAvatarUrl() { * * @return the call avatar URL. */ + @Nullable public String getCallAvatarUrl() { - // TODO LazyLoading - // Do something like: - // res = summary.getAvatarUrl(); - throw new RuntimeException("Not yet implemented"); - - /* String avatarURL; - List joinedMembers = new ArrayList<>(getJoinedMembers()); + if (getNumberOfMembers() == 2 && getState().getLoadedMembers().size() > 1) { + RoomMember m1 = getState().getLoadedMembers().get(0); + RoomMember m2 = getState().getLoadedMembers().get(1); - // 2 joined members case - if (2 == joinedMembers.size()) { // use other member avatar. - if (TextUtils.equals(mMyUserId, joinedMembers.get(0).getUserId())) { - avatarURL = joinedMembers.get(1).getAvatarUrl(); + if (TextUtils.equals(mMyUserId, m1.getUserId())) { + avatarURL = m2.getAvatarUrl(); } else { - avatarURL = joinedMembers.get(0).getAvatarUrl(); + avatarURL = m1.getAvatarUrl(); } } else { // @@ -1058,7 +1045,6 @@ public String getCallAvatarUrl() { } return avatarURL; - */ } /** From 3a1ffa3a4999b86a9a98c7b2e14fb3b61122cfa4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 23 Aug 2018 18:19:48 +0200 Subject: [PATCH 083/236] Add GET /versions request to the LoginRestClient --- CHANGES.rst | 1 + .../org/matrix/androidsdk/RestClient.java | 1 + .../matrix/androidsdk/rest/api/LoginApi.java | 17 ++++++-- .../rest/client/LoginRestClient.java | 17 +++++++- .../androidsdk/rest/model/Versions.java | 36 ++++++++++++++++ .../matrix/androidsdk/util/VersionsUtil.java | 42 +++++++++++++++++++ 6 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Versions.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/util/VersionsUtil.java diff --git a/CHANGES.rst b/CHANGES.rst index 39b1e4977..df4992807 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,6 +8,7 @@ Features: Improvements: - Encrypt local data (PR #305) + - Add GET /versions request to the LoginRestClient Bugfix: - Fix excessive whitespace on quoted messages (#348) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/RestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/RestClient.java index 627f875fe..beae75665 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/RestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/RestClient.java @@ -63,6 +63,7 @@ public class RestClient { public static final String URI_API_PREFIX_PATH_MEDIA_R0 = "_matrix/media/r0/"; public static final String URI_API_PREFIX_PATH_MEDIA_PROXY_UNSTABLE = "_matrix/media_proxy/unstable/"; + public static final String URI_API_PREFIX_PATH = "_matrix/client/"; public static final String URI_API_PREFIX_PATH_R0 = "_matrix/client/r0/"; public static final String URI_API_PREFIX_PATH_UNSTABLE = "_matrix/client/unstable/"; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/LoginApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/LoginApi.java index 6ba2eab41..f79d23f9c 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/LoginApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/LoginApi.java @@ -1,5 +1,6 @@ /* * Copyright 2014 OpenMarket Ltd + * Copyright 2018 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +18,8 @@ import com.google.gson.JsonObject; +import org.matrix.androidsdk.RestClient; +import org.matrix.androidsdk.rest.model.Versions; import org.matrix.androidsdk.rest.model.login.LoginFlowResponse; import org.matrix.androidsdk.rest.model.login.LoginParams; import org.matrix.androidsdk.rest.model.login.RegistrationParams; @@ -34,7 +37,13 @@ public interface LoginApi { /** * Get the different login flows supported by the server. */ - @GET("login") + @GET(RestClient.URI_API_PREFIX_PATH + "versions") + Call versions(); + + /** + * Get the different login flows supported by the server. + */ + @GET(RestClient.URI_API_PREFIX_PATH_R0 + "login") Call login(); /** @@ -42,7 +51,7 @@ public interface LoginApi { * * @param params the registration params */ - @POST("register") + @POST(RestClient.URI_API_PREFIX_PATH_R0 + "register") Call register(@Body RegistrationParams params); /** @@ -50,12 +59,12 @@ public interface LoginApi { * * @param loginParams the login parameters */ - @POST("login") + @POST(RestClient.URI_API_PREFIX_PATH_R0 + "login") Call login(@Body LoginParams loginParams); /** * Invalidate the access token, so that it can no longer be used for authorization. */ - @POST("logout") + @POST(RestClient.URI_API_PREFIX_PATH_R0 + "logout") Call logout(); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/LoginRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/LoginRestClient.java index b63ab0f48..cdb6fb8be 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/LoginRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/LoginRestClient.java @@ -28,6 +28,7 @@ import org.matrix.androidsdk.rest.api.LoginApi; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.callback.RestAdapterCallback; +import org.matrix.androidsdk.rest.model.Versions; import org.matrix.androidsdk.rest.model.login.Credentials; import org.matrix.androidsdk.rest.model.login.LoginFlow; import org.matrix.androidsdk.rest.model.login.LoginFlowResponse; @@ -61,7 +62,19 @@ public class LoginRestClient extends RestClient { * @param hsConfig the home server connection config */ public LoginRestClient(HomeServerConnectionConfig hsConfig) { - super(hsConfig, LoginApi.class, RestClient.URI_API_PREFIX_PATH_R0, false); + super(hsConfig, LoginApi.class, "", false); + } + + /** + * Get Versions supported by the server and other server capabilities + * + * @param callback the callback + */ + public void getVersions(final ApiCallback callback) { + final String description = "getVersions"; + + mApi.versions() + .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, null)); } /** @@ -93,7 +106,7 @@ public void success(LoginFlowResponse loginFlowResponse, Response response) { * Request an account creation * * @param params the registration parameters - * @param callback the callbacks + * @param callback the callback */ public void register(final RegistrationParams params, final ApiCallback callback) { final String description = "register"; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Versions.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Versions.java new file mode 100644 index 000000000..be0b8fb64 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Versions.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; +import java.util.Map; + +/** + * Model for https://matrix.org/docs/spec/client_server/r0.3.0.html#get-matrix-client-versions + *

+ * Ex: {"unstable_features": {"m.lazy_load_members": true}, "versions": ["r0.0.1", "r0.1.0", "r0.2.0", "r0.3.0"]} + */ +public class Versions { + + @SerializedName("versions") + public List supportedVersions; + + @SerializedName("unstable_features") + public Map unstableFeatures; +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/VersionsUtil.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/VersionsUtil.java new file mode 100644 index 000000000..a57c0dfa9 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/VersionsUtil.java @@ -0,0 +1,42 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.util; + +import android.support.annotation.Nullable; + +import org.matrix.androidsdk.rest.model.Versions; + +/** + * Companion for class {@link Versions} + */ +public class VersionsUtil { + + private static final String FEATURE_LAZY_LOAD_MEMBERS = "m.lazy_load_members"; + + /** + * Return true if the server support the lazy loading of room members + * + * @param versions the Versions object from the server request + * @return true if the server support the lazy loading of room members + */ + public static boolean supportLazyLoadMembers(@Nullable Versions versions) { + return versions != null + && versions.unstableFeatures != null + && versions.unstableFeatures.containsKey(FEATURE_LAZY_LOAD_MEMBERS) + && versions.unstableFeatures.get(FEATURE_LAZY_LOAD_MEMBERS); + } +} From 4abaeb583ba7a817bd4eb3d450d6e7f70bd285be Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 24 Aug 2018 12:10:04 +0200 Subject: [PATCH 084/236] Add methods to enable Lazy Loading of room members --- .../java/org/matrix/androidsdk/MXSession.java | 37 +++++++++++++++++++ .../matrix/androidsdk/sync/EventsThread.java | 13 ++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index bbe3f150e..3f7a1d40e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -73,6 +73,7 @@ import org.matrix.androidsdk.rest.model.ReceiptData; import org.matrix.androidsdk.rest.model.RoomMember; import org.matrix.androidsdk.rest.model.User; +import org.matrix.androidsdk.rest.model.Versions; import org.matrix.androidsdk.rest.model.bingrules.BingRule; import org.matrix.androidsdk.rest.model.filter.FilterBody; import org.matrix.androidsdk.rest.model.filter.FilterResponse; @@ -96,6 +97,7 @@ import org.matrix.androidsdk.util.JsonUtils; import org.matrix.androidsdk.util.Log; import org.matrix.androidsdk.util.UnsentEventsManager; +import org.matrix.androidsdk.util.VersionsUtil; import org.matrix.olm.OlmManager; import java.io.File; @@ -175,6 +177,9 @@ public class MXSession { private String mFilterOrFilterId; + // tell if the lazy loading is enabled + private boolean mUseLazyLoading; + // the groups manager private GroupsManager mGroupsManager; @@ -858,6 +863,8 @@ public void startEventStream(final EventsThreadListener anEventsListener, mEventsThread.setFailureCallback(mFailureCallback); } + mEventsThread.setUseLazyLoading(mUseLazyLoading); + if (mCredentials.accessToken != null && !mEventsThread.isAlive()) { // GA issue try { @@ -1000,6 +1007,19 @@ public synchronized void setSyncFilterOrFilterId(String filterOrFilterId) { } } + /** + * Update the lazy loading mode + * Do not use this method to enable the lazy laoding. Use {@link #canEnableLazyLoading(ApiCallback)} + * + * @param enabled true to enable the lazy loading + */ + public void setUseLazyLoading(boolean enabled) { + mUseLazyLoading = enabled; + if (null != mEventsThread) { + mEventsThread.setUseLazyLoading(enabled); + } + } + /** * Refresh the network connection information. * On android version older than 6.0, the doze mode might have killed the network connection. @@ -1935,6 +1955,23 @@ public NetworkConnectivityReceiver getNetworkConnectivityReceiver() { return mNetworkConnectivityReceiver; } + + /** + * Ask the home server if the lazy loading of room members is supported. + * + * @param callback the callback, to be notified if the server actually support the lazy loading. True if supported + */ + public void canEnableLazyLoading(final ApiCallback callback) { + // Check that the server support the lazy loading + mLoginRestClient.getVersions(new SimpleApiCallback(callback) { + @Override + public void onSuccess(Versions info) { + // Check if we can enable lazyLoading + callback.onSuccess(VersionsUtil.supportLazyLoadMembers(info)); + } + }); + } + /** * Invalidate the access token, so that it can no longer be used for authorization. * diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java index 4d7f6420a..9593ed2e7 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java @@ -101,9 +101,11 @@ public class EventsThread extends Thread { private boolean mbIsConnected = true; // use dedicated filter when enable - private boolean mIsInDataSaveMode = false; private String mFilterOrFilterId; + // TODO Lazy Loading: Use this + private boolean mUseLazyLoading; + private final IMXNetworkEventListener mNetworkListener = new IMXNetworkEventListener() { @Override public void onNetworkConnectionUpdate(boolean isConnected) { @@ -166,6 +168,15 @@ public void setFilterOrFilterId(String filterOrFilterId) { mFilterOrFilterId = filterOrFilterId; } + /** + * Update the lazy loading + * + * @param enabled true to enable the lazy loading + */ + public void setUseLazyLoading(boolean enabled) { + mUseLazyLoading = enabled; + } + /** * Update the long poll timeout. * From ede8bca3a4182f62f7fd6f8089d89a0340f6ca8f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 27 Aug 2018 09:48:40 +0200 Subject: [PATCH 085/236] Remove unused import --- .../java/org/matrix/androidsdk/rest/model/filter/Filter.java | 1 - .../org/matrix/androidsdk/rest/model/filter/FilterBody.java | 2 -- .../org/matrix/androidsdk/rest/model/filter/FilterResponse.java | 2 -- .../matrix/androidsdk/rest/model/filter/RoomEventFilter.java | 1 - .../org/matrix/androidsdk/rest/model/filter/RoomFilter.java | 1 - 5 files changed, 7 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java index 3596a25b8..f1d27a4fc 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java @@ -18,7 +18,6 @@ import com.google.gson.annotations.SerializedName; -import java.io.Serializable; import java.util.List; /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java index a9de59405..3f2a2d83a 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java @@ -19,7 +19,6 @@ import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; -import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -47,7 +46,6 @@ public class FilterBody { private static FilterBody dataSaveModeFilterBody; /** - * * @return FilterBody which represents "{\"room\": {\"ephemeral\": {\"types\": [\"m.receipt\"]}}, \"presence\":{\"notTypes\": [\"*\"]}}" */ public static FilterBody getDataSaveModeFilterBody() { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterResponse.java index a3bbe821f..f74361131 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterResponse.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterResponse.java @@ -18,8 +18,6 @@ import com.google.gson.annotations.SerializedName; -import java.io.Serializable; - /** * Represents the body which is the response when creating a filter on the server * https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-user-userid-filter diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java index 4e63ff076..6f236bde8 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java @@ -18,7 +18,6 @@ import com.google.gson.annotations.SerializedName; -import java.io.Serializable; import java.util.List; /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java index dbf7ba0ee..82c41f2d7 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java @@ -18,7 +18,6 @@ import com.google.gson.annotations.SerializedName; -import java.io.Serializable; import java.util.List; /** From 68d31823392de2bbfa025e42b3e91b485f0e8bca Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 27 Aug 2018 09:49:01 +0200 Subject: [PATCH 086/236] Add lazy loading filter in model --- .../matrix/androidsdk/rest/model/filter/RoomEventFilter.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java index 6f236bde8..735a08932 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java @@ -45,4 +45,7 @@ public class RoomEventFilter { @SerializedName("contains_url") public Boolean containsUrl; + + @SerializedName("lazy_load_members") + public Boolean lazyLoadMembers; } From 58e3793ac5634c72cc9cf0b9582d0bcf60ce3e76 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 27 Aug 2018 15:18:36 +0200 Subject: [PATCH 087/236] Sdk is not able to cache filter/filterId --- .../java/org/matrix/androidsdk/MXSession.java | 99 ++++++++----- .../androidsdk/data/store/IMXStore.java | 10 ++ .../androidsdk/data/store/MXFileStore.java | 6 + .../data/store/MXFileStoreMetaData.java | 6 + .../androidsdk/data/store/MXMemoryStore.java | 10 ++ .../matrix/androidsdk/rest/api/FilterApi.java | 2 - .../rest/client/FilterRestClient.java | 2 - .../androidsdk/rest/model/filter/Filter.java | 10 ++ .../rest/model/filter/FilterBody.java | 22 --- .../rest/model/filter/RoomEventFilter.java | 12 ++ .../rest/model/filter/RoomFilter.java | 10 ++ .../matrix/androidsdk/sync/EventsThread.java | 21 +-- .../matrix/androidsdk/util/FilterUtil.java | 133 ++++++++++++++++++ 13 files changed, 264 insertions(+), 79 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/util/FilterUtil.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index 3f7a1d40e..7abeb691a 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -94,6 +94,7 @@ import org.matrix.androidsdk.util.BingRulesManager; import org.matrix.androidsdk.util.ContentManager; import org.matrix.androidsdk.util.ContentUtils; +import org.matrix.androidsdk.util.FilterUtil; import org.matrix.androidsdk.util.JsonUtils; import org.matrix.androidsdk.util.Log; import org.matrix.androidsdk.util.UnsentEventsManager; @@ -175,7 +176,10 @@ public class MXSession { // so, mEventsThread.start might be not ready private boolean mIsBgCatchupPending = false; - private String mFilterOrFilterId; + private FilterBody mCurrentFilter = new FilterBody(); + + // tell if the data save mode is enabled + private boolean mUseDataSaveMode; // tell if the lazy loading is enabled private boolean mUseLazyLoading; @@ -852,7 +856,7 @@ public void startEventStream(final EventsThreadListener anEventsListener, final EventsThreadListener fEventsListener = (null == anEventsListener) ? new DefaultEventsThreadListener(mDataHandler) : anEventsListener; mEventsThread = new EventsThread(mAppContent, mEventsRestClient, fEventsListener, initialToken); - mEventsThread.setFilterOrFilterId(mFilterOrFilterId); + setSyncFilter(mCurrentFilter); mEventsThread.setMetricsListener(mMetricsListener); mEventsThread.setNetworkConnectivityReceiver(networkConnectivityReceiver); mEventsThread.setIsOnline(mIsOnline); @@ -863,8 +867,6 @@ public void startEventStream(final EventsThreadListener anEventsListener, mEventsThread.setFailureCallback(mFailureCallback); } - mEventsThread.setUseLazyLoading(mUseLazyLoading); - if (mCredentials.accessToken != null && !mEventsThread.isAlive()) { // GA issue try { @@ -972,51 +974,82 @@ public int getSyncDelay() { return mSyncDelay; } - /** + /** * Update the data save mode. Deprecated by setSyncFilterOrFilterId() * * @param enabled true to enable the data save mode */ - @Deprecated + @Deprecated public void setUseDataSaveMode(boolean enabled) { - if (enabled) { - Log.d(LOG_TAG, "Enable DataSyncMode # " + FilterBody.getDataSaveModeFilterBody()); - // enable the filter in JSON representation so do not block sync until the filter response is there - setSyncFilterOrFilterId(FilterBody.getDataSaveModeFilterBody().toJSONString()); - mFilterRestClient.uploadFilter(getMyUserId(), FilterBody.getDataSaveModeFilterBody(), new SimpleApiCallback() { - @Override - public void onSuccess(FilterResponse filter) { - setSyncFilterOrFilterId(filter.filterId); - } - }); - } else { - Log.d(LOG_TAG, "Disable DataSyncMode"); - setSyncFilterOrFilterId(null); - } - } + mUseDataSaveMode = enabled; - /** - * Allows setting the filterId used by the EventsThread - * @param filterOrFilterId the content of the filter param on sync requests - */ - public synchronized void setSyncFilterOrFilterId(String filterOrFilterId) { - Log.d(LOG_TAG, "setSyncFilterOrFilterId ## " + filterOrFilterId); - mFilterOrFilterId = filterOrFilterId; - if (null != mEventsThread) { - mEventsThread.setFilterOrFilterId(filterOrFilterId); + if (mEventsThread != null) { + setSyncFilter(mCurrentFilter); } } /** * Update the lazy loading mode - * Do not use this method to enable the lazy laoding. Use {@link #canEnableLazyLoading(ApiCallback)} + * Do not use this method to enable the lazy loading. Use {@link #canEnableLazyLoading(ApiCallback)} * * @param enabled true to enable the lazy loading */ public void setUseLazyLoading(boolean enabled) { mUseLazyLoading = enabled; - if (null != mEventsThread) { - mEventsThread.setUseLazyLoading(enabled); + + if (mEventsThread != null) { + setSyncFilter(mCurrentFilter); + } + } + + /** + * Allows setting the filter used by the EventsThread + * + * @param filter the content of the filter param on sync requests + */ + public synchronized void setSyncFilter(FilterBody filter) { + Log.d(LOG_TAG, "setSyncFilter ## " + filter); + mCurrentFilter = filter; + + // Enable Data save mode and/or LazyLoading + FilterUtil.enableDataSaveMode(mCurrentFilter, mUseDataSaveMode); + FilterUtil.enableLazyLoading(mCurrentFilter, mUseLazyLoading); + + convertFilterToFilterId(); + } + + /** + * Convert a filter to a filterId + * Either it is already known to the server, or send the filter to the server to get a filterId + */ + private void convertFilterToFilterId() { + // Ensure mCurrentFilter has not been updated in the same time + final String wantedJsonFilter = mCurrentFilter.toJSONString(); + + // Check if the current filter is known by the server, to directly use the filterId + String filterId = getDataHandler().getStore().getFilters().get(wantedJsonFilter); + + if (TextUtils.isEmpty(filterId)) { + // enable the filter in JSON representation so do not block sync until the filter response is there + mEventsThread.setFilterOrFilterId(wantedJsonFilter); + + // Send the filter to the server + mFilterRestClient.uploadFilter(getMyUserId(), mCurrentFilter, new SimpleApiCallback() { + @Override + public void onSuccess(FilterResponse filter) { + // Store the couple filter/filterId + getDataHandler().getStore().addFilter(wantedJsonFilter, filter.filterId); + + // Ensure the filter is still corresponding to the current filter + if (TextUtils.equals(wantedJsonFilter, mCurrentFilter.toJSONString())) { + // Tell the event thread to use the id now + mEventsThread.setFilterOrFilterId(filter.filterId); + } + } + }); + } else { + // Tell the event thread to use the id now + mEventsThread.setFilterOrFilterId(filterId); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java index dc350c3dd..bdcdb3cd5 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java @@ -610,6 +610,16 @@ public interface IMXStore { */ Set getRoomsWithoutURLPreviews(); + /** + * Add a couple Json filter / filterId + */ + void addFilter(String jsonFilter, String filterId); + + /** + * Get the Map of all filters configured server side (note: only by this current instance of Riot) + */ + Map getFilters(); + /** * Set the public key of the antivirus server */ diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java index 8726f6428..dc10226fd 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java @@ -2592,6 +2592,12 @@ public void setUserWidgets(Map contentDict) { mMetaDataHasChanged = true; } + @Override + public void addFilter(String jsonFilter, String filterId) { + super.addFilter(jsonFilter, filterId); + mMetaDataHasChanged = true; + } + @Override public void setAntivirusServerPublicKey(@Nullable String key) { super.setAntivirusServerPublicKey(key); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStoreMetaData.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStoreMetaData.java index e6ae4938e..4bbb20e30 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStoreMetaData.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStoreMetaData.java @@ -50,6 +50,10 @@ public class MXFileStoreMetaData implements java.io.Serializable { public Map mUserWidgets = new HashMap<>(); public Set mRoomsListWithoutURLPrevew = new HashSet<>(); + // To store known filters by the server. Keys are the filter as a Json String, Values are the filterId returned by the server + // Mainly used to store a filterId related to a corresponding Json string. + public Map mKnownFilters = new HashMap<>(); + // crypto public boolean mEndToEndDeviceAnnounced = false; @@ -80,6 +84,8 @@ public MXFileStoreMetaData deepCopy() { copy.mUserWidgets = mUserWidgets; copy.mRoomsListWithoutURLPrevew = mRoomsListWithoutURLPrevew; + copy.mKnownFilters = new HashMap<>(mKnownFilters); + return copy; } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java index 0809cc6be..ed79a5701 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java @@ -1608,6 +1608,16 @@ public Set getRoomsWithoutURLPreviews() { return (null != mMetadata.mRoomsListWithoutURLPrevew) ? mMetadata.mRoomsListWithoutURLPrevew : new HashSet(); } + @Override + public void addFilter(String jsonFilter, String filterId) { + mMetadata.mKnownFilters.put(jsonFilter, filterId); + } + + @Override + public Map getFilters() { + return new HashMap<>(mMetadata.mKnownFilters); + } + @Override public void setAntivirusServerPublicKey(@Nullable String key) { mMetadata.mAntivirusServerPublicKey = key; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java index 64e76ef67..191fd33c3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/FilterApi.java @@ -19,8 +19,6 @@ import org.matrix.androidsdk.rest.model.filter.FilterBody; import org.matrix.androidsdk.rest.model.filter.FilterResponse; -import java.util.Map; - import retrofit2.Call; import retrofit2.http.Body; import retrofit2.http.GET; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java index 88608e4f0..70ef46d88 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java @@ -26,8 +26,6 @@ import org.matrix.androidsdk.rest.model.filter.FilterBody; import org.matrix.androidsdk.rest.model.filter.FilterResponse; -import retrofit2.Response; - public class FilterRestClient extends RestClient{ /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java index f1d27a4fc..65dd473d0 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/Filter.java @@ -42,4 +42,14 @@ public class Filter { @SerializedName("not_rooms") public List notRooms; + + public boolean hasData() { + return limit != null + || senders != null + || notSenders != null + || types != null + || notTypes != null + || rooms != null + || notRooms != null; + } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java index 3f2a2d83a..060537194 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java @@ -19,7 +19,6 @@ import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; -import java.util.ArrayList; import java.util.List; /** @@ -43,27 +42,6 @@ public class FilterBody { public RoomFilter room; - private static FilterBody dataSaveModeFilterBody; - - /** - * @return FilterBody which represents "{\"room\": {\"ephemeral\": {\"types\": [\"m.receipt\"]}}, \"presence\":{\"notTypes\": [\"*\"]}}" - */ - public static FilterBody getDataSaveModeFilterBody() { - if (dataSaveModeFilterBody == null) { - FilterBody result = new FilterBody(); - result.room = new RoomFilter(); - result.room.ephemeral = new RoomEventFilter(); - result.room.ephemeral.types = new ArrayList<>(); - result.room.ephemeral.types.add("m.receipt"); - - result.presence = new Filter(); - result.presence.notTypes = new ArrayList<>(); - result.presence.notTypes.add("*"); - dataSaveModeFilterBody = result; - } - return dataSaveModeFilterBody; - } - @Override public String toString() { return LOG_TAG + toJSONString(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java index 735a08932..60969d617 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java @@ -48,4 +48,16 @@ public class RoomEventFilter { @SerializedName("lazy_load_members") public Boolean lazyLoadMembers; + + public boolean hasData() { + return limit != null + || notSenders != null + || notTypes != null + || senders != null + || types != null + || rooms != null + || notRooms != null + || containsUrl != null + || lazyLoadMembers != null; + } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java index 82c41f2d7..f6fd31a8b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomFilter.java @@ -42,4 +42,14 @@ public class RoomFilter { @SerializedName("account_data") public RoomEventFilter accountData; + + public boolean hasData() { + return notRooms != null + || rooms != null + || ephemeral != null + || includeLeave != null + || state != null + || timeline != null + || accountData != null; + } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java index 9593ed2e7..983f30063 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java @@ -59,12 +59,6 @@ public class EventsThread extends Thread { private static final int DEFAULT_SERVER_TIMEOUT_MS = 30000; private static final int DEFAULT_CLIENT_TIMEOUT_MS = 120000; - // TODO LazyLoading - // private static final String DATA_SAVE_MODE_FILTER = "{\"room\": {\"ephemeral\": {\"types\": [\"m.receipt\"]}}, \"presence\":{\"not_types\": [\"*\"]}}"; - // TODO filter to get RoomSyncSummary - private static final String DATA_SAVE_MODE_FILTER = "{\"room\": {\"state\":{\"lazy_load_members\":true}, \"ephemeral\": {\"types\": [\"m.receipt\"]}}, \"presence\":{\"not_types\": [\"*\"]}}"; - private static final String LAZY_LOADING_FILTER = "{\"room\":{\"state\":{\"lazy_load_members\":true}}}"; - private EventsRestClient mEventsRestClient; private EventsThreadListener mListener; private String mCurrentToken; @@ -103,9 +97,6 @@ public class EventsThread extends Thread { // use dedicated filter when enable private String mFilterOrFilterId; - // TODO Lazy Loading: Use this - private boolean mUseLazyLoading; - private final IMXNetworkEventListener mNetworkListener = new IMXNetworkEventListener() { @Override public void onNetworkConnectionUpdate(boolean isConnected) { @@ -168,15 +159,6 @@ public void setFilterOrFilterId(String filterOrFilterId) { mFilterOrFilterId = filterOrFilterId; } - /** - * Update the lazy loading - * - * @param enabled true to enable the lazy loading - */ - public void setUseLazyLoading(boolean enabled) { - mUseLazyLoading = enabled; - } - /** * Update the long poll timeout. * @@ -428,10 +410,9 @@ private void resumeInitialSync() { private void executeInitialSync() { Log.d(LOG_TAG, "Requesting initial sync..."); long initialSyncStartTime = System.currentTimeMillis(); - final String initSyncFilter = new Gson().toJson(FilterBody.getDataSaveModeFilterBody()); while (!isInitialSyncDone()) { final CountDownLatch latch = new CountDownLatch(1); - mEventsRestClient.syncFromToken(null, 0, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", initSyncFilter, + mEventsRestClient.syncFromToken(null, 0, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", mFilterOrFilterId, new SimpleApiCallback(mFailureCallback) { @Override public void onSuccess(SyncResponse syncResponse) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/FilterUtil.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/FilterUtil.java new file mode 100644 index 000000000..bfde52c22 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/FilterUtil.java @@ -0,0 +1,133 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.util; + +import android.support.annotation.NonNull; + +import org.matrix.androidsdk.rest.model.filter.Filter; +import org.matrix.androidsdk.rest.model.filter.FilterBody; +import org.matrix.androidsdk.rest.model.filter.RoomEventFilter; +import org.matrix.androidsdk.rest.model.filter.RoomFilter; + +import java.util.ArrayList; + +public class FilterUtil { + + /** + * Patch the filterBody to enable or disable the data save mode + *

+ * If data save mode is on, FilterBody will contains + * "{\"room\": {\"ephemeral\": {\"types\": [\"m.receipt\"]}}, \"presence\":{\"notTypes\": [\"*\"]}}" + * + * @param filterBody filterBody to patch + * @param useDataSaveMode true to enable data save mode + */ + public static void enableDataSaveMode(@NonNull FilterBody filterBody, boolean useDataSaveMode) { + if (useDataSaveMode) { + // Enable data save mode + if (filterBody.room == null) { + filterBody.room = new RoomFilter(); + } + if (filterBody.room.ephemeral == null) { + filterBody.room.ephemeral = new RoomEventFilter(); + } + if (filterBody.room.ephemeral.types == null) { + filterBody.room.ephemeral.types = new ArrayList<>(); + } + if (!filterBody.room.ephemeral.types.contains("m.receipt")) { + filterBody.room.ephemeral.types.add("m.receipt"); + } + + if (filterBody.presence == null) { + filterBody.presence = new Filter(); + } + if (filterBody.presence.notTypes == null) { + filterBody.presence.notTypes = new ArrayList<>(); + } + if (!filterBody.presence.notTypes.contains("*")) { + filterBody.presence.notTypes.add("*"); + } + } else { + if (filterBody.room != null + && filterBody.room.ephemeral != null + && filterBody.room.ephemeral.types != null) { + filterBody.room.ephemeral.types.remove("m.receipt"); + + if (filterBody.room.ephemeral.types.isEmpty()) { + filterBody.room.ephemeral.types = null; + } + + if (!filterBody.room.ephemeral.hasData()) { + filterBody.room.ephemeral = null; + } + + if (!filterBody.room.hasData()) { + filterBody.room = null; + } + } + + if (filterBody.presence != null + && filterBody.presence.notTypes != null) { + filterBody.presence.notTypes.remove("*"); + + if (filterBody.presence.notTypes.isEmpty()) { + filterBody.presence.notTypes = null; + } + + if (!filterBody.presence.hasData()) { + filterBody.presence = null; + } + } + } + } + + /** + * Patch the filterBody to enable or disable the lazy loading + *

+ * If lazy loading is on, the filterBody will looks like + * {"room":{"state":{"lazy_load_members":true})} + * + * @param filterBody filterBody to patch + * @param useLazyLoading true to enable lazy loading + */ + public static void enableLazyLoading(FilterBody filterBody, boolean useLazyLoading) { + if (useLazyLoading) { + // Enable lazy loading + if (filterBody.room == null) { + filterBody.room = new RoomFilter(); + } + if (filterBody.room.state == null) { + filterBody.room.state = new RoomEventFilter(); + } + + filterBody.room.state.lazyLoadMembers = true; + } else { + if (filterBody.room != null + && filterBody.room.state != null) { + filterBody.room.state.lazyLoadMembers = null; + + if (!filterBody.room.state.hasData()) { + filterBody.room.state = null; + } + + if (!filterBody.room.hasData()) { + filterBody.room = null; + } + } + } + } +} From e836200b577855900e6205e4aab63eb5d0725184 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 31 Aug 2018 10:53:20 +0200 Subject: [PATCH 088/236] Fix compilation issue --- .../src/main/java/org/matrix/androidsdk/data/RoomSummary.java | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index f9f75a4cc..b590b93d2 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -36,6 +36,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Set; /** From 9816cef44bb0829b248413e125df1f6e601e71e2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 31 Aug 2018 12:50:39 +0200 Subject: [PATCH 089/236] Add cURL interceptor, to log http requests as cURL command --- .../interceptors/CurlLoggingInterceptor.java | 108 ++++++++++++++++++ .../FormattedJsonHttpLogger.java | 3 +- .../org/matrix/androidsdk/RestClient.java | 21 ++-- .../interceptors/CurlLoggingInterceptor.java | 33 ++++++ .../interceptors/FormattedJsonHttpLogger.java | 31 +++++ 5 files changed, 188 insertions(+), 8 deletions(-) create mode 100644 matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java rename matrix-sdk/src/{main/java/org/matrix/androidsdk/util => debug/java/org/matrix/androidsdk/interceptors}/FormattedJsonHttpLogger.java (96%) create mode 100644 matrix-sdk/src/release/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java create mode 100644 matrix-sdk/src/release/java/org/matrix/androidsdk/interceptors/FormattedJsonHttpLogger.java diff --git a/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java b/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java new file mode 100644 index 000000000..128388535 --- /dev/null +++ b/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2016 Jeff Gilfelt. + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.interceptors; + +import java.io.IOException; +import java.nio.charset.Charset; + +import okhttp3.Headers; +import okhttp3.Interceptor; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.logging.HttpLoggingInterceptor; +import okio.Buffer; + +/** + * An OkHttp interceptor that logs requests as curl shell commands. They can then + * be copied, pasted and executed inside a terminal environment. This might be + * useful for troubleshooting client/server API interaction during development, + * making it easy to isolate and share requests made by the app.

Warning: The + * logs generated by this interceptor have the potential to leak sensitive + * information. It should only be used in a controlled manner or in a + * non-production environment. + */ +public class CurlLoggingInterceptor implements Interceptor { + + private static final Charset UTF8 = Charset.forName("UTF-8"); + + private final HttpLoggingInterceptor.Logger logger; + private String curlOptions; + + public CurlLoggingInterceptor() { + this(HttpLoggingInterceptor.Logger.DEFAULT); + } + + public CurlLoggingInterceptor(HttpLoggingInterceptor.Logger logger) { + this.logger = logger; + } + + /** + * Set any additional curl command options (see 'curl --help'). + */ + public void setCurlOptions(String curlOptions) { + this.curlOptions = curlOptions; + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + + boolean compressed = false; + + String curlCmd = "curl"; + if (curlOptions != null) { + curlCmd += " " + curlOptions; + } + curlCmd += " -X " + request.method(); + + RequestBody requestBody = request.body(); + if (requestBody != null) { + Buffer buffer = new Buffer(); + requestBody.writeTo(buffer); + Charset charset = UTF8; + MediaType contentType = requestBody.contentType(); + if (contentType != null) { + charset = contentType.charset(UTF8); + } + // try to keep to a single line and use a subshell to preserve any line breaks + curlCmd += " --data $'" + buffer.readString(charset).replace("\n", "\\n") + "'"; + } + + Headers headers = request.headers(); + for (int i = 0, count = headers.size(); i < count; i++) { + String name = headers.name(i); + String value = headers.value(i); + if ("Accept-Encoding".equalsIgnoreCase(name) && "gzip".equalsIgnoreCase(value)) { + compressed = true; + } + curlCmd += " -H " + "\"" + name + ": " + value + "\""; + } + + curlCmd += ((compressed) ? " --compressed " : " ") + request.url(); + + // Add Json formatting + curlCmd += " | python -m json.tool"; + + logger.log("--- cURL (" + request.url() + ")"); + logger.log(curlCmd); + + return chain.proceed(request); + } +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/FormattedJsonHttpLogger.java b/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/FormattedJsonHttpLogger.java similarity index 96% rename from matrix-sdk/src/main/java/org/matrix/androidsdk/util/FormattedJsonHttpLogger.java rename to matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/FormattedJsonHttpLogger.java index 5e893704a..2787b54ec 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/FormattedJsonHttpLogger.java +++ b/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/FormattedJsonHttpLogger.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.matrix.androidsdk.util; +package org.matrix.androidsdk.interceptors; import android.support.annotation.NonNull; @@ -22,6 +22,7 @@ import org.json.JSONException; import org.json.JSONObject; import org.matrix.androidsdk.BuildConfig; +import org.matrix.androidsdk.util.Log; import okhttp3.internal.platform.Platform; import okhttp3.logging.HttpLoggingInterceptor; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/RestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/RestClient.java index beae75665..656c8c657 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/RestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/RestClient.java @@ -29,12 +29,13 @@ import com.facebook.stetho.okhttp3.StethoInterceptor; import com.google.gson.Gson; +import org.matrix.androidsdk.interceptors.CurlLoggingInterceptor; +import org.matrix.androidsdk.interceptors.FormattedJsonHttpLogger; import org.matrix.androidsdk.listeners.IMXNetworkEventListener; import org.matrix.androidsdk.network.NetworkConnectivityReceiver; import org.matrix.androidsdk.rest.client.MXRestExecutorService; import org.matrix.androidsdk.rest.model.login.Credentials; import org.matrix.androidsdk.ssl.CertUtil; -import org.matrix.androidsdk.util.FormattedJsonHttpLogger; import org.matrix.androidsdk.util.JsonUtils; import org.matrix.androidsdk.util.Log; import org.matrix.androidsdk.util.PolymorphicRequestBodyConverter; @@ -159,6 +160,7 @@ public Response intercept(Chain chain) throws IOException { } }; + // TODO Remove this, seems so useless Interceptor connectivityInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { @@ -171,17 +173,22 @@ public Response intercept(Chain chain) throws IOException { } }; - HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new FormattedJsonHttpLogger()); - loggingInterceptor.setLevel(BuildConfig.OKHTTP_LOGGING_LEVEL); - OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient().newBuilder() .connectTimeout(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS) .readTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS) .writeTimeout(WRITE_TIMEOUT_MS, TimeUnit.MILLISECONDS) .addInterceptor(authentInterceptor) - .addInterceptor(connectivityInterceptor) - .addInterceptor(loggingInterceptor) - .addNetworkInterceptor(new StethoInterceptor()); + .addInterceptor(connectivityInterceptor); + + if (BuildConfig.DEBUG) { + HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new FormattedJsonHttpLogger()); + loggingInterceptor.setLevel(BuildConfig.OKHTTP_LOGGING_LEVEL); + + okHttpClientBuilder + .addInterceptor(loggingInterceptor) + .addNetworkInterceptor(new StethoInterceptor()) + .addInterceptor(new CurlLoggingInterceptor()); + } if (mUseMXExecutor) { diff --git a/matrix-sdk/src/release/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java b/matrix-sdk/src/release/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java new file mode 100644 index 000000000..ffc013674 --- /dev/null +++ b/matrix-sdk/src/release/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.interceptors; + +import java.io.IOException; + +import okhttp3.Interceptor; +import okhttp3.Response; + +/** + * No op interceptor + */ +public class CurlLoggingInterceptor implements Interceptor { + + @Override + public Response intercept(Chain chain) throws IOException { + return chain.proceed(chain.request()); + } +} diff --git a/matrix-sdk/src/release/java/org/matrix/androidsdk/interceptors/FormattedJsonHttpLogger.java b/matrix-sdk/src/release/java/org/matrix/androidsdk/interceptors/FormattedJsonHttpLogger.java new file mode 100644 index 000000000..44d5224ea --- /dev/null +++ b/matrix-sdk/src/release/java/org/matrix/androidsdk/interceptors/FormattedJsonHttpLogger.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.interceptors; + +import android.support.annotation.NonNull; + +import okhttp3.logging.HttpLoggingInterceptor; + +/** + * No op logger + */ +public class FormattedJsonHttpLogger implements HttpLoggingInterceptor.Logger { + + @Override + public synchronized void log(@NonNull String message) { + } +} From 0eca4e9f5bc2940a158f99db93b8157a8128f3f3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 31 Aug 2018 16:12:42 +0200 Subject: [PATCH 090/236] Add a FIXME --- .../java/org/matrix/androidsdk/rest/client/RoomsRestClient.java | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index 60f7e4001..466940848 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -524,6 +524,7 @@ public void onRetry() { public void updateCanonicalAlias(final String roomId, final String canonicalAlias, final ApiCallback callback) { final String description = "updateCanonicalAlias : roomId " + roomId + " canonicalAlias " + canonicalAlias; + // FIXME Do not use a RoomState object to do this request, create a new object (same for all other next method) RoomState roomState = new RoomState(); roomState.alias = canonicalAlias; From 20eec77b6fca91dc96258e1b8a214457018f855d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 31 Aug 2018 16:13:46 +0200 Subject: [PATCH 091/236] Use LazyLoading boolean is now managed in DataHandler --- .../org/matrix/androidsdk/MXDataHandler.java | 11 ++++++ .../java/org/matrix/androidsdk/MXSession.java | 37 +++++++------------ 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 1b4da40b1..d503e3789 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -177,6 +177,9 @@ public interface RequestNetworkErrorListener { @Nullable private MatrixError mResourceLimitExceededError; + // tell if the lazy loading is enabled + private boolean mIsLazyLoadingEnabled; + /** * Default constructor. * @@ -196,6 +199,14 @@ public MXDataHandler(IMXStore store, Credentials credentials) { mLeftRoomsStore = new MXMemoryStore(credentials, store.getContext()); } + public void setLazyLoadingEnabled(boolean enabled) { + mIsLazyLoadingEnabled = enabled; + } + + public boolean isLazyLoadingEnabled() { + return mIsLazyLoadingEnabled; + } + /** * Set the network error listener. * diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index 7abeb691a..6b0fa8e43 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -181,9 +181,6 @@ public class MXSession { // tell if the data save mode is enabled private boolean mUseDataSaveMode; - // tell if the lazy loading is enabled - private boolean mUseLazyLoading; - // the groups manager private GroupsManager mGroupsManager; @@ -975,11 +972,10 @@ public int getSyncDelay() { } /** - * Update the data save mode. Deprecated by setSyncFilterOrFilterId() + * Update the data save mode. * * @param enabled true to enable the data save mode */ - @Deprecated public void setUseDataSaveMode(boolean enabled) { mUseDataSaveMode = enabled; @@ -988,20 +984,6 @@ public void setUseDataSaveMode(boolean enabled) { } } - /** - * Update the lazy loading mode - * Do not use this method to enable the lazy loading. Use {@link #canEnableLazyLoading(ApiCallback)} - * - * @param enabled true to enable the lazy loading - */ - public void setUseLazyLoading(boolean enabled) { - mUseLazyLoading = enabled; - - if (mEventsThread != null) { - setSyncFilter(mCurrentFilter); - } - } - /** * Allows setting the filter used by the EventsThread * @@ -1013,7 +995,7 @@ public synchronized void setSyncFilter(FilterBody filter) { // Enable Data save mode and/or LazyLoading FilterUtil.enableDataSaveMode(mCurrentFilter, mUseDataSaveMode); - FilterUtil.enableLazyLoading(mCurrentFilter, mUseLazyLoading); + FilterUtil.enableLazyLoading(mCurrentFilter, mDataHandler.isLazyLoadingEnabled()); convertFilterToFilterId(); } @@ -2527,7 +2509,7 @@ public Builder withFileEncryption(boolean enableFileEncryption) { * Create a pusher rest client, overriding the push server url if necessary * * @param pushServerUrl the push server url, or null or empty to use the default PushersRestClient - * @return + * @return this builder, to chain calls */ public Builder withPushServerUrl(@Nullable String pushServerUrl) { // If not empty, create a special PushersRestClient @@ -2554,14 +2536,23 @@ public Builder withPushServerUrl(@Nullable String pushServerUrl) { return this; } + /** + * Set the metrics listener of this session + * + * @param metricsListener the metrics listener + * @return this builder, to chain calls + */ public Builder withMetricsListener(@Nullable MetricsListener metricsListener) { mxSession.mMetricsListener = metricsListener; return this; } - // TODO LazyLoading: add useLazyLoading() method to this builder - + /** + * Build the session + * + * @return the build session + */ public MXSession build() { return mxSession; } From 67c0f9c0268b81c28778186ad21452cb70303565 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 31 Aug 2018 16:14:06 +0200 Subject: [PATCH 092/236] Stronger code --- .../java/org/matrix/androidsdk/data/Room.java | 19 ++++++++++++++++--- .../org/matrix/androidsdk/data/RoomState.java | 17 +++++++++++++++-- .../matrix/androidsdk/data/RoomSummary.java | 2 +- .../androidsdk/data/store/IMXStore.java | 3 ++- .../androidsdk/data/store/MXMemoryStore.java | 2 ++ 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index eddfd3821..64c5e4a57 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -3088,19 +3088,32 @@ public boolean isDirect() { return mDataHandler.getDirectChatRoomIdsList().contains(getRoomId()); } + @Nullable public RoomSummary getRoomSummary() { return getDataHandler().getStore().getSummary(getRoomId()); } public int getNumberOfMembers() { - return getRoomSummary().getNumberOfJoinedMembers() + getRoomSummary().getNumberOfInvitedMembers(); + return getNumberOfJoinedMembers() + getNumberOfInvitedMembers(); } public int getNumberOfJoinedMembers() { - return getRoomSummary().getNumberOfJoinedMembers(); + RoomSummary roomSummary = getRoomSummary(); + + if (roomSummary != null) { + return roomSummary.getNumberOfJoinedMembers(); + } else { + return 0; + } } public int getNumberOfInvitedMembers() { - return getRoomSummary().getNumberOfInvitedMembers(); + RoomSummary roomSummary = getRoomSummary(); + + if (roomSummary != null) { + return roomSummary.getNumberOfInvitedMembers(); + } else { + return 0; + } } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index dfdd3693b..f09604b80 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -273,7 +273,7 @@ public List getLoadedMembers() { * Get the list of all the room members. Fetch from server if the full list is not loaded yet. */ public void getMembersAsync(ApiCallback> callback) { - if (mAllMembersAreLoaded) { + if (areAllMembersLoaded()) { List res; synchronized (this) { @@ -322,6 +322,17 @@ public void onSuccess(List info) { } } + /** + * Tell if all members has been loaded + * + * @return true is LazyLoading is Off, or if all members has been loaded + */ + // TODO LazyLoading maybe compare size of mMembers with number of users instead of using mAllMembersAreLoaded + private boolean areAllMembersLoaded() { + return mDataHandler != null + && (!((MXDataHandler) mDataHandler).isLazyLoadingEnabled() || mAllMembersAreLoaded); + } + /** * Provides the loaded states event list. * The room member events are NOT included. @@ -471,6 +482,7 @@ public RoomMember getMember(String userId) { } if (member == null) { + // TODO LazyLoading Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Null member !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } @@ -497,6 +509,7 @@ public RoomMember getMemberByEventId(String eventId) { } if (member == null) { + // TODO LazyLoading Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Null member !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } @@ -791,7 +804,7 @@ public void addAlias(String alias) { * @param selfUserId this user's user id (to exclude from members) * @return the display name */ - // TODO Use RoomSummary + // TODO LazyLoading Use RoomSummary public String getDisplayName(String selfUserId) { String displayName = null; String alias = getAlias(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index b590b93d2..376c146da 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -551,7 +551,7 @@ public boolean isConferenceUserRoom() { mIsConferenceUserRoom = false; - // FIXME Heroes does not contains me + // FIXME LazyLoading Heroes does not contains me // FIXME I'ms not sure this code will work anymore Collection membersId = getHeroes(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java index bdcdb3cd5..a9a1f5900 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java @@ -392,8 +392,9 @@ public interface IMXStore { * Get the stored summary for the given room. * * @param roomId the room id - * @return the summary for the room + * @return the summary for the room, or null in case of error */ + @Nullable RoomSummary getSummary(String roomId); /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java index ed79a5701..d751c187e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java @@ -1014,6 +1014,7 @@ public Collection getSummaries() { Room room = mRooms.get(roomId); if (null != room) { if (null == room.getMember(mCredentials.userId)) { + // TODO it happens with LazyLoading, fix this Log.e(LOG_TAG, "## getSummaries() : a summary exists for the roomId " + roomId + " but the user is not anymore a member"); } else { summaries.add(mRoomSummaries.get(roomId)); @@ -1026,6 +1027,7 @@ public Collection getSummaries() { return summaries; } + @Nullable @Override public RoomSummary getSummary(String roomId) { // sanity check From 6d92d49ee24151595693530fbaec15884650dc00 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 31 Aug 2018 17:02:11 +0200 Subject: [PATCH 093/236] Compute room name (LazyLoading disabled) --- .../org/matrix/androidsdk/data/RoomState.java | 21 ++++++++++++++++++- .../matrix/androidsdk/data/RoomSummary.java | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index f09604b80..1f405159c 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -103,9 +103,11 @@ public class RoomState implements Externalizable { private Map> mStateEvents = new HashMap<>(); // Informs which alias is the canonical one. + // TODO LazyLoading Manu: Alias what is this? public String alias; // The canonical alias of the room, if any. + // TODO LazyLoading Manu: Alias what is this? public String canonical_alias; // The name of the room as provided by the home server. @@ -140,6 +142,7 @@ public class RoomState implements Externalizable { public String history_visibility; // the public room alias / name + // TODO LazyLoading Manu: Alias what is this? public String roomAliasName; /** @@ -406,13 +409,29 @@ public void onSuccess(List events) { } } + /** + * @return a copy of the displayable members list. May be incomplete if the full list is not loaded yet + */ + public List getDisplayableLoadedMembers() { + List res = getLoadedMembers(); + + RoomMember conferenceUserId = getMember(MXCallsManager.getConferenceUserId(roomId)); + + if (null != conferenceUserId) { + res.remove(conferenceUserId); + } + + return res; + } + + /** * Provides a list of displayable members. * Some dummy members are created to internal stuff. * * @param callback The callback to get a copy of the displayable room members list. */ - public void getDisplayableMembers(final ApiCallback> callback) { + public void getDisplayableMembersAsync(final ApiCallback> callback) { getMembersAsync(new SimpleApiCallback>(callback) { @Override public void onSuccess(List members) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index 376c146da..552aedd82 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -591,6 +591,7 @@ public void setRoomSyncSummary(@NonNull RoomSyncSummary roomSyncSummary) { } } + @NonNull public List getHeroes() { return mHeroes; } From b30596489d41fe1bdfe936a97bc7fa3666f65421 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 31 Aug 2018 17:39:26 +0200 Subject: [PATCH 094/236] RoomSummary does not handle room name anymore. It's up to the client to compute room name --- .../matrix/androidsdk/data/EventTimeline.java | 24 ----- .../java/org/matrix/androidsdk/data/Room.java | 4 - .../androidsdk/data/RoomPreviewData.java | 4 +- .../org/matrix/androidsdk/data/RoomState.java | 89 ------------------- .../matrix/androidsdk/data/RoomSummary.java | 43 --------- 5 files changed, 2 insertions(+), 162 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index d98471030..807569680 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -578,19 +578,6 @@ else if ((null != roomSync.state) && (null != roomSync.state.events) && (roomSyn } mStore.storeSummary(summary); - String eventType = event.getType(); - - // Watch for potential room name changes - if (Event.EVENT_TYPE_STATE_ROOM_NAME.equals(eventType) - || Event.EVENT_TYPE_STATE_ROOM_ALIASES.equals(eventType) - || Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(eventType)) { - - - if (null != summary) { - summary.setName(mRoom.getName(myUserId)); - } - } - mStore.commit(); break; } @@ -689,17 +676,6 @@ private void storeEvent(Event event) { } mStore.storeSummary(summary); - - String eventType = event.getType(); - - // Watch for potential room name changes - if (Event.EVENT_TYPE_STATE_ROOM_NAME.equals(eventType) - || Event.EVENT_TYPE_STATE_ROOM_ALIASES.equals(eventType) - || Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(eventType)) { - if (null != summary) { - summary.setName(mRoom.getName(myUserId)); - } - } } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 64c5e4a57..ffa5dc67f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -541,10 +541,6 @@ public String getTopic() { return getState().topic; } - public String getName(String selfUserId) { - return getState().getDisplayName(selfUserId); - } - public String getVisibility() { return getState().visibility; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomPreviewData.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomPreviewData.java index ecc338fdc..0b1d6c491 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomPreviewData.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomPreviewData.java @@ -21,7 +21,6 @@ import android.text.TextUtils; import org.matrix.androidsdk.MXSession; - import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.MatrixError; @@ -199,7 +198,8 @@ protected Void doInBackground(Void... params) { mRoomState.applyState(null, event, EventTimeline.Direction.FORWARDS); } - mRoomName = mRoomState.getDisplayName(mSession.getMyUserId()); + // TODO LazyLoading handle case where room has no name + mRoomName = mRoomState.name; mRoomAvatarUrl = mRoomState.getAvatarUrl(); return null; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 1f405159c..2f72e9afc 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -817,95 +817,6 @@ public void addAlias(String alias) { } } - /** - * Build and return the room's display name. - * - * @param selfUserId this user's user id (to exclude from members) - * @return the display name - */ - // TODO LazyLoading Use RoomSummary - public String getDisplayName(String selfUserId) { - String displayName = null; - String alias = getAlias(); - - synchronized (this) { - if (name != null) { - displayName = name; - } else if (!TextUtils.isEmpty(alias)) { - displayName = getAlias(); - } - // compute a name - else if (mMembers.size() > 0) { - Iterator it = mMembers.entrySet().iterator(); - Map.Entry otherUserPair = null; - - if ((mMembers.size() >= 3) && (selfUserId != null)) { - // this is a group chat and should have the names of participants - // according to "( , , ..." - int count = 0; - - displayName = ""; - - while (it.hasNext()) { - Map.Entry pair = (Map.Entry) it.next(); - - if (!selfUserId.equals(pair.getKey())) { - otherUserPair = pair; - - if (count > 0) { - displayName += ", "; - } - - if (otherUserPair.getValue().getName() != null) { - displayName += getMemberName(otherUserPair.getValue().getUserId()); // The member name - } else { - displayName += getMemberName(otherUserPair.getKey()); // The user id - } - count++; - } - } - displayName = "(" + count + ") " + displayName; - } else { - // by default, it is oneself name - displayName = getMemberName(selfUserId); - - // A One2One private room can default to being called like the other guy - if (selfUserId != null) { - while (it.hasNext()) { - Map.Entry pair = (Map.Entry) it.next(); - if (!selfUserId.equals(pair.getKey())) { - otherUserPair = pair; - break; - } - } - } - - if (otherUserPair != null) { - if (otherUserPair.getValue().getName() != null) { - displayName = getMemberName(otherUserPair.getValue().getUserId()); // The member name - } else { - displayName = getMemberName(otherUserPair.getKey()); // The user id - } - } - } - } - } - - if ((displayName != null) && (alias != null) && !displayName.equals(alias)) { - if (TextUtils.isEmpty(displayName)) { - displayName = alias; - } else { - displayName += " (" + alias + ")"; - } - } - - if (displayName == null) { - displayName = roomId; - } - - return displayName; - } - /** * @return true if the room is encrypted */ diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index 552aedd82..908bb7857 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -48,7 +48,6 @@ public class RoomSummary implements java.io.Serializable { private static final long serialVersionUID = -3683013938626566489L; private String mRoomId = null; - private String mName = null; private String mTopic = null; private Event mLatestReceivedEvent = null; @@ -260,36 +259,6 @@ public String getRoomId() { return mRoomId; } - /** - * Compute the room summary display name. - * - * @return the room summary display name. - */ - public String getRoomName() { - String name = mName; - - // when invited, the only received message should be the invitation one - if (isInvited()) { - if (null != mLatestReceivedEvent) { - String inviterName; - - // try to retrieve a display name - if (null != mLatestRoomState) { - inviterName = mLatestRoomState.getMemberName(mLatestReceivedEvent.getSender()); - } else { - // use the stored one - inviterName = mInviterName; - } - - if (null != inviterName) { - name = inviterName; - } - } - } - - return name; - } - /** * @return the topic. */ @@ -345,17 +314,6 @@ public RoomSummary setTopic(String topic) { return this; } - /** - * Set the room's {@link org.matrix.androidsdk.rest.model.Event#EVENT_TYPE_STATE_ROOM_NAME}. - * - * @param name The name - * @return This summary for chaining calls. - */ - public RoomSummary setName(String name) { - mName = name; - return this; - } - /** * Set the room's ID.. * @@ -379,7 +337,6 @@ public RoomSummary setLatestReceivedEvent(Event event, RoomState roomState) { setLatestRoomState(roomState); if (null != roomState) { - setName(roomState.getDisplayName(getMatrixId())); setTopic(roomState.topic); } return this; From d8b887e59cd177972c43fb860328df6f57051afc Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 10:46:19 +0200 Subject: [PATCH 095/236] Escape '!' --- .../matrix/androidsdk/interceptors/CurlLoggingInterceptor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java b/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java index 128388535..c25ab87f1 100644 --- a/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java +++ b/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java @@ -95,7 +95,7 @@ public Response intercept(Chain chain) throws IOException { curlCmd += " -H " + "\"" + name + ": " + value + "\""; } - curlCmd += ((compressed) ? " --compressed " : " ") + request.url(); + curlCmd += ((compressed) ? " --compressed " : " ") + request.url().toString().replaceAll("!", "\\!"); // Add Json formatting curlCmd += " | python -m json.tool"; From a62bb70c507a8c6776e4e9678db71e95fa1e87c9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 16:06:19 +0200 Subject: [PATCH 096/236] getMembers with `at` parameter --- .../java/org/matrix/androidsdk/MXDataHandler.java | 9 +++++++-- .../main/java/org/matrix/androidsdk/data/Room.java | 2 ++ .../org/matrix/androidsdk/rest/api/RoomsApi.java | 12 +++++++++--- .../androidsdk/rest/client/RoomsRestClient.java | 11 +++++++---- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index d503e3789..f3f4570fe 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -180,6 +180,9 @@ public interface RequestNetworkErrorListener { // tell if the lazy loading is enabled private boolean mIsLazyLoadingEnabled; + // Current sync token + private String mSyncToken; + /** * Default constructor. * @@ -952,7 +955,7 @@ public void onSuccess(RoomAliasDescription info) { * @param callback the callback */ public void getMembersAsync(final String roomId, final ApiCallback> callback) { - mRoomsRestClient.getRoomMembers(roomId, new SimpleApiCallback>(callback) { + mRoomsRestClient.getRoomMembers(roomId, mSyncToken, null, null, new SimpleApiCallback>(callback) { @Override public void onSuccess(TokensChunkResponse info) { Room room = getRoom(roomId); @@ -1284,6 +1287,8 @@ private void handlePresenceEvent(Event presenceEvent) { * @param isCatchingUp true when there is a pending catch-up */ public void onSyncResponse(final SyncResponse syncResponse, final String fromToken, final boolean isCatchingUp) { + mSyncToken = syncResponse.nextBatch; + // perform the sync in background // to avoid UI thread lags. mSyncHandler.post(new Runnable() { @@ -1342,7 +1347,7 @@ public void deleteRoom(String roomId) { } /** - * Manage the sync response in the UI thread. + * Manage the sync response in a background thread. * * @param syncResponse the syncResponse to manage. * @param fromToken the start sync token diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index ffa5dc67f..2e9efe465 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -3093,6 +3093,7 @@ public int getNumberOfMembers() { return getNumberOfJoinedMembers() + getNumberOfInvitedMembers(); } + // FIXME It returns 0 when LL is off (it will fix avatar issue) public int getNumberOfJoinedMembers() { RoomSummary roomSummary = getRoomSummary(); @@ -3103,6 +3104,7 @@ public int getNumberOfJoinedMembers() { } } + // FIXME It returns 0 when LL is off (it will fix avatar issue) public int getNumberOfInvitedMembers() { RoomSummary roomSummary = getRoomSummary(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index 8fc464b7f..9bd23ea75 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -456,10 +456,16 @@ Call updateAccountData(@Path("userId") String userId, /** * Get all members of a room - * TODO handle the token id as a parameter * - * @param roomId the room id where to get the members + * @param roomId the room id where to get the members + * @param syncToken + * @param membership + * @param notMembership */ + // TODO LazyLoading check that the "at" param has an effect... @GET("rooms/{roomId}/members") - Call> getMembers(@Path("roomId") String roomId); + Call> getMembers(@Path("roomId") String roomId, + @Query("at") String syncToken, + @Query("membership") String membership, + @Query("not_membership") String notMembership); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index 466940848..5a22c47b0 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -602,16 +602,19 @@ public void onRetry() { /** * Get the room members - * // TODO Add token as a parameter */ - public void getRoomMembers(final String roomId, final ApiCallback> callback) { + public void getRoomMembers(final String roomId, + final String syncToken, + final String membership, + final String notMembership, + final ApiCallback> callback) { final String description = "getRoomMembers roomId=" + roomId; - mApi.getMembers(roomId) + mApi.getMembers(roomId, syncToken, membership, notMembership) .enqueue(new RestAdapterCallback>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { - getRoomMembers(roomId, callback); + getRoomMembers(roomId, syncToken, membership, notMembership, callback); } })); } From a1b196865308c31ddec0e8ceffbdc9f33f228bde Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 16:19:22 +0200 Subject: [PATCH 097/236] Fix test compilation issue (LazyLoading work) --- .../androidsdk/lazyloading/RoomStateTest.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index 931f0bce7..ef985ac73 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -50,11 +50,11 @@ private void RoomState_InitialSync(final boolean withLazyLoading) throws Excepti mTestHelper.syncSession(data.aliceSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); if (withLazyLoading) { - Assert.assertEquals(1, aliceRoom.getMembers().size()); - Assert.assertEquals(1, aliceRoom.getJoinedMembers().size()); + Assert.assertEquals(1, aliceRoom.getState().getLoadedMembers().size()); + Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } else { - Assert.assertEquals(4, aliceRoom.getMembers().size()); - Assert.assertEquals(3, aliceRoom.getJoinedMembers().size()); + Assert.assertEquals(4, aliceRoom.getState().getLoadedMembers().size()); + Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } } @@ -79,11 +79,11 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro mTestHelper.sendTextMessage(samRoom, "A message from Sam", 1); lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); if (withLazyLoading) { - Assert.assertEquals(2, aliceRoom.getMembers().size()); - Assert.assertEquals(2, aliceRoom.getJoinedMembers().size()); + Assert.assertEquals(2, aliceRoom.getState().getLoadedMembers().size()); + Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } else { - Assert.assertEquals(4, aliceRoom.getMembers().size()); - Assert.assertEquals(3, aliceRoom.getJoinedMembers().size()); + Assert.assertEquals(4, aliceRoom.getState().getLoadedMembers().size()); + Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } } @@ -152,11 +152,11 @@ public void onSuccess(Void info) { Assert.assertTrue(handled); final RoomState roomState = eventTimeline.getState(); if (withLazyLoading) { - Assert.assertEquals(1, roomState.getMembers().size()); - Assert.assertEquals(1, aliceRoom.getJoinedMembers().size()); + Assert.assertEquals(1, roomState.getLoadedMembers().size()); + Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } else { - Assert.assertEquals(4, roomState.getMembers().size()); - Assert.assertEquals(3, aliceRoom.getJoinedMembers().size()); + Assert.assertEquals(4, roomState.getLoadedMembers().size()); + Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } } From 7c819cc82d3235a37bea803a82d1a6bfdbc7c27b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 16:21:12 +0200 Subject: [PATCH 098/236] Create test with LazyLoading on --- .../androidsdk/common/CommonTestHelper.java | 37 ++++++++++------ .../matrix/androidsdk/crypto/CryptoTest.java | 4 +- .../lazyloading/LazyLoadingTestHelper.java | 7 ++-- .../androidsdk/lazyloading/RoomStateTest.java | 42 ++++++++++++++++--- 4 files changed, 66 insertions(+), 24 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index 23a5d4b61..19af34483 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -71,15 +71,15 @@ public MXSession createSamAccount(boolean withInitialSync, boolean enableCrypto) } public MXSession logIntoBobAccount(final String bobUserId, final boolean withInitialSync, boolean enableCrypto) { - return logIntoAccount(bobUserId, TestConstants.BOB_PWD, withInitialSync, enableCrypto); + return logIntoAccount(bobUserId, TestConstants.BOB_PWD, withInitialSync, enableCrypto, false); } - public MXSession logIntoAliceAccount(final String aliceUserId, final boolean withInitialSync, boolean enableCrypto) { - return logIntoAccount(aliceUserId, TestConstants.ALICE_PWD, withInitialSync, enableCrypto); + public MXSession logIntoAliceAccount(final String aliceUserId, final boolean withInitialSync, boolean enableCrypto, boolean withLazyLoading) { + return logIntoAccount(aliceUserId, TestConstants.ALICE_PWD, withInitialSync, enableCrypto, withLazyLoading); } public MXSession logIntoSamAccount(final String samUserId, final boolean withInitialSync, boolean enableCrypto) { - return logIntoAccount(samUserId, TestConstants.SAM_PWD, withInitialSync, enableCrypto); + return logIntoAccount(samUserId, TestConstants.SAM_PWD, withInitialSync, enableCrypto, false); } /** @@ -144,14 +144,13 @@ public void onCryptoSyncComplete() { public List sendTextMessage(@Nonnull final Room room, @Nonnull final String message, final int nbOfMessages) throws Exception { final List sentEvents = new ArrayList<>(nbOfMessages); final CountDownLatch latch = new CountDownLatch(nbOfMessages); - final MXEventListener onEventsentListener = new MXEventListener() { + final MXEventListener onEventSentListener = new MXEventListener() { @Override public void onEventSent(Event event, String prevEventId) { - super.onEventSent(event, prevEventId); latch.countDown(); } }; - room.addEventListener(onEventsentListener); + room.addEventListener(onEventSentListener); for (int i = 0; i < nbOfMessages; i++) { room.sendTextMessage(message, null, Message.FORMAT_MATRIX_HTML, new RoomMediaMessage.EventCreationListener() { @Override @@ -172,7 +171,11 @@ public void onEncryptionFailed(RoomMediaMessage roomMediaMessage) { }); } latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - room.removeEventListener(onEventsentListener); + room.removeEventListener(onEventSentListener); + + // Check that all events has been created + Assert.assertEquals(nbOfMessages, sentEvents.size()); + return sentEvents; } @@ -216,9 +219,10 @@ private MXSession createAccount(@NonNull final String userId, private MXSession logIntoAccount(@NonNull final String userId, @NonNull final String password, final boolean withInitialSync, - final boolean enableCrypto) { + final boolean enableCrypto, + boolean withLazyLoading) { final Context context = InstrumentationRegistry.getContext(); - final MXSession session = logAccountAndSync(context, userId, password, withInitialSync, enableCrypto); + final MXSession session = logAccountAndSync(context, userId, password, withInitialSync, enableCrypto, withLazyLoading); Assert.assertNotNull(session); return session; } @@ -328,7 +332,12 @@ public void onSuccess(Credentials credentials) { * @param withInitialSync true to perform an initial sync * @param enableCrypto true to set enableCryptoWhenStarting */ - private MXSession logAccountAndSync(Context context, String userName, String password, boolean withInitialSync, boolean enableCrypto) { + private MXSession logAccountAndSync(Context context, + String userName, + String password, + boolean withInitialSync, + boolean enableCrypto, + boolean withLazyLoading) { final HomeServerConnectionConfig hs = createHomeServerConfig(null); LoginRestClient loginRestClient = new LoginRestClient(hs); final Map params = new HashMap<>(); @@ -356,7 +365,11 @@ public void onSuccess(Credentials credentials) { hs.setCredentials(credentials); final IMXStore store = new MXFileStore(hs, false, context); - final MXSession mxSession = new MXSession.Builder(hs, new MXDataHandler(store, credentials), context) + + MXDataHandler mxDataHandler = new MXDataHandler(store, credentials); + mxDataHandler.setLazyLoadingEnabled(withLazyLoading); + + final MXSession mxSession = new MXSession.Builder(hs, mxDataHandler, context) .build(); if (enableCrypto) { diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index e9701eabe..7b7d0b639 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -1979,7 +1979,7 @@ public void onSuccess(Void info) { Assert.assertNotNull(bobSession2); bobSession2.getCrypto().setWarnOnUnknownDevices(false); - MXSession aliceSession2 = mTestHelper.logIntoAliceAccount(aliceSession.getMyUserId(), true, true); + MXSession aliceSession2 = mTestHelper.logIntoAliceAccount(aliceSession.getMyUserId(), true, true, false); Assert.assertNotNull(aliceSession2); aliceSession2.getCrypto().setWarnOnUnknownDevices(false); @@ -3135,7 +3135,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("lock1")); // - Alice adds a new device - final MXSession aliceSession2 = mTestHelper.logIntoAliceAccount(aliceSession.getMyUserId(), true, true); + final MXSession aliceSession2 = mTestHelper.logIntoAliceAccount(aliceSession.getMyUserId(), true, true, false); Assert.assertNotNull(aliceSession2); // - Alice and Bob start sharing a room again diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java index 376e22b18..f4b932ee1 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java @@ -54,9 +54,10 @@ public LazyLoadingTestHelper(CommonTestHelper mCommonTestHelper) { * - Alice sends 50 messages * - Alice makes an initial /sync with lazy-loading enabled or not * + * @param withLazyLoading true to enable lazy loading for alice account * @return initialized data */ - public LazyLoadingScenarioData createScenario() throws Exception { + public LazyLoadingScenarioData createScenario(boolean withLazyLoading) throws Exception { MXSession bobSession = mTestHelper.createBobAccount(true, false); MXSession aliceSession = mTestHelper.createAliceAccount(true, false); MXSession samSession = mTestHelper.createSamAccount(true, false); @@ -117,11 +118,9 @@ public void onSuccess(String info) { bobSession.clear(context); samSession.clear(context); - aliceSession = mTestHelper.logIntoAliceAccount(aliceId, false, false); + aliceSession = mTestHelper.logIntoAliceAccount(aliceId, false, false, withLazyLoading); bobSession = mTestHelper.logIntoBobAccount(bobId, false, false); samSession = mTestHelper.logIntoSamAccount(samId, false, false); return new LazyLoadingScenarioData(aliceSession, bobSession, samSession, roomId, bobMessageId); - } - } diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index ef985ac73..3cc5e8802 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -45,8 +45,13 @@ public void RoomState_InitialSync_ShouldLoadAllMembers() throws Exception { RoomState_InitialSync(false); } + @Test + public void RoomState_InitialSync_ShouldLoadAllMembers_LL() throws Exception { + RoomState_InitialSync(true); + } + private void RoomState_InitialSync(final boolean withLazyLoading) throws Exception { - final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); mTestHelper.syncSession(data.aliceSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); if (withLazyLoading) { @@ -63,8 +68,13 @@ public void RoomState_IncomingMessage_ShouldLoadAllMembers() throws Exception { RoomState_IncomingMessage(false); } + @Test + public void RoomState_IncomingMessage_ShouldLoadAllMembers_LL() throws Exception { + RoomState_IncomingMessage(true); + } + private void RoomState_IncomingMessage(final boolean withLazyLoading) throws Exception { - final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); mTestHelper.syncSession(data.aliceSession, false); mTestHelper.syncSession(data.samSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); @@ -92,8 +102,13 @@ public void RoomState_BackPaginate_ShouldLoadAllMembers() throws Exception { RoomState_BackPaginate(false); } + @Test + public void RoomState_BackPaginate_ShouldLoadAllMembers_LL() throws Exception { + RoomState_BackPaginate(true); + } + private void RoomState_BackPaginate(final boolean withLazyLoading) throws Exception { - final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); mTestHelper.syncSession(data.aliceSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); final CountDownLatch lock = new CountDownLatch(1); @@ -135,8 +150,13 @@ public void RoomState_Permalink_ShouldLoadAllMembers() throws Exception { RoomState_Permalink(false); } + @Test + public void RoomState_Permalink_ShouldLoadAllMembers_LL() throws Exception { + RoomState_Permalink(true); + } + private void RoomState_Permalink(final boolean withLazyLoading) throws Exception { - final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); mTestHelper.syncSession(data.aliceSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); final Event lastEvent = aliceRoom.getDataHandler().getStore().getLatestEvent(data.roomId); @@ -165,8 +185,13 @@ public void RoomState_PermalinkWithBackPagination_ShouldLoadAllMembers() throws RoomState_PermalinkWithBackPagination(false); } + @Test + public void RoomState_PermalinkWithBackPagination_ShouldLoadAllMembers_LL() throws Exception { + RoomState_PermalinkWithBackPagination(true); + } + private void RoomState_PermalinkWithBackPagination(final boolean withLazyLoading) throws Exception { - final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); mTestHelper.syncSession(data.aliceSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); final CountDownLatch lock = new CountDownLatch(1); @@ -214,13 +239,18 @@ public void RoomState_PermalinkWithForwardPagination_ShouldLoadAllMembers() thro RoomState_PermalinkWithForwardPagination(false); } + @Test + public void RoomState_PermalinkWithForwardPagination_ShouldLoadAllMembers_LL() throws Exception { + RoomState_PermalinkWithForwardPagination(true); + } + // Test lazy loaded members sent by the HS when paginating forward // - Come back to Bob message // - We should only know Bob membership // - Paginate forward to get Alice next message // - We should know Alice membership now private void RoomState_PermalinkWithForwardPagination(final boolean withLazyLoading) throws Exception { - final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(); + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); mTestHelper.syncSession(data.aliceSession, false); final CountDownLatch lock = new CountDownLatch(1); final EventTimeline eventTimeline = new EventTimeline(data.aliceSession.getDataHandler(), data.roomId, data.bobMessageId); From 5d1e6544434c1486a21cf20539977a69a851577d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 17:52:36 +0200 Subject: [PATCH 099/236] Improve again cURL interceptor --- .../androidsdk/interceptors/CurlLoggingInterceptor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java b/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java index c25ab87f1..d8882e2da 100644 --- a/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java +++ b/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java @@ -95,7 +95,11 @@ public Response intercept(Chain chain) throws IOException { curlCmd += " -H " + "\"" + name + ": " + value + "\""; } - curlCmd += ((compressed) ? " --compressed " : " ") + request.url().toString().replaceAll("!", "\\!"); + curlCmd += ((compressed) ? " --compressed " : " ") + request.url().toString() + // Escape '!' because it is interpreted by the shell prompt + .replaceAll("!", "\\!") + // Replace localhost for emulator by localhost for shell + .replaceAll("://10.0.2.2:8080/", "://127.0.0.1:8080/"); // Add Json formatting curlCmd += " | python -m json.tool"; From 4d3927d4663520eeab5761e3a655ede9446d4aef Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 18:00:14 +0200 Subject: [PATCH 100/236] Fix test compilation issue --- .../RoomMemberCountConditionTest.java | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/rest/model/bingrules/RoomMemberCountConditionTest.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/rest/model/bingrules/RoomMemberCountConditionTest.java index 40d1946d3..e0bf9a085 100644 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/rest/model/bingrules/RoomMemberCountConditionTest.java +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/rest/model/bingrules/RoomMemberCountConditionTest.java @@ -21,15 +21,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.matrix.androidsdk.data.Room; -import org.matrix.androidsdk.rest.model.RoomMember; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; -import java.util.ArrayList; -import java.util.List; - @RunWith(RobolectricTestRunner.class) public class RoomMemberCountConditionTest { @@ -45,26 +41,7 @@ public void setUp() { } private void setUpThreeRoomMembers() { - List members = new ArrayList<>(); - - RoomMember rm1 = new RoomMember(); - rm1.membership = RoomMember.MEMBERSHIP_JOIN; - members.add(rm1); - - RoomMember rm2 = new RoomMember(); - rm2.membership = RoomMember.MEMBERSHIP_JOIN; - members.add(rm2); - - RoomMember rm3 = new RoomMember(); - rm3.membership = RoomMember.MEMBERSHIP_JOIN; - members.add(rm3); - - // This one shouldn't count because they're not joined - RoomMember rm4 = new RoomMember(); - rm4.membership = RoomMember.MEMBERSHIP_LEAVE; - members.add(rm4); - - Mockito.when(mockRoom.getMembers()).thenReturn(members); + Mockito.when(mockRoom.getNumberOfJoinedMembers()).thenReturn(3); } @Test From 7f4b374da877b241ae455a7969009aad26ad988c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Sep 2018 18:00:55 +0200 Subject: [PATCH 101/236] Improve code comment regarding code --- .../androidsdk/lazyloading/LazyLoadingTestHelper.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java index f4b932ee1..00348d9fc 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java @@ -46,11 +46,11 @@ public LazyLoadingTestHelper(CommonTestHelper mCommonTestHelper) { /** * Create a base scenario for all lazy loading tests * Common initial conditions: - * - Alice, Bob in a room - * - Charlie joins the room + * - Bob create a public room named "LazyLoading Test Room" + * - Sam and Alice join the room * - Dave is invited * - Alice sends 50 messages - * - Bob sends one message + * - Bob sends 1 message * - Alice sends 50 messages * - Alice makes an initial /sync with lazy-loading enabled or not * From 34ea984da7b54a5fff2ab08bff5358831493d0c3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 10:06:06 +0200 Subject: [PATCH 102/236] Improve test --- .../androidsdk/lazyloading/RoomStateTest.java | 90 +++++++++++-------- 1 file changed, 53 insertions(+), 37 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index 3cc5e8802..c0b64c17f 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -18,10 +18,8 @@ import android.support.test.runner.AndroidJUnit4; import org.junit.Assert; -import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.MethodSorters; import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.data.EventTimeline; @@ -34,7 +32,6 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) public class RoomStateTest { private CommonTestHelper mTestHelper = new CommonTestHelper(); @@ -54,13 +51,15 @@ private void RoomState_InitialSync(final boolean withLazyLoading) throws Excepti final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); mTestHelper.syncSession(data.aliceSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); + if (withLazyLoading) { Assert.assertEquals(1, aliceRoom.getState().getLoadedMembers().size()); - Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } else { Assert.assertEquals(4, aliceRoom.getState().getLoadedMembers().size()); - Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } + + Assert.assertEquals(1, aliceRoom.getNumberOfInvitedMembers()); + Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } @Test @@ -88,13 +87,16 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro final Room samRoom = data.samSession.getDataHandler().getRoom(data.roomId); mTestHelper.sendTextMessage(samRoom, "A message from Sam", 1); lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + if (withLazyLoading) { + // Sam is now loaded Assert.assertEquals(2, aliceRoom.getState().getLoadedMembers().size()); - Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } else { Assert.assertEquals(4, aliceRoom.getState().getLoadedMembers().size()); - Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } + + Assert.assertEquals(1, aliceRoom.getNumberOfInvitedMembers()); + Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } @Test @@ -120,22 +122,26 @@ private void RoomState_BackPaginate(final boolean withLazyLoading) throws Except public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { messageCount++; if (messageCount == 50) { - if (withLazyLoading) { - Assert.assertNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); - Assert.assertNull(liveTimeline.getState().getMember(data.samSession.getMyUserId())); - Assert.assertNull(roomState.getMember(data.bobSession.getMyUserId())); - } Assert.assertNotNull(liveTimeline.getState().getMember(data.aliceSession.getMyUserId())); + + // With LazyLoading, Bob and Sam are not known by Alice yet + Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.bobSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.bobSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); } else if (messageCount == 51) { - if (withLazyLoading) { - Assert.assertNull(roomState.getMember(data.samSession.getMyUserId())); - Assert.assertNull(liveTimeline.getState().getMember(data.samSession.getMyUserId())); - } + // Bob is known now Assert.assertNotNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); + + // With LazyLoading, Sam is not known by Alice yet + Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); } else if (messageCount >= 110) { + // All users are known now Assert.assertNotNull(liveTimeline.getState().getMember(data.aliceSession.getMyUserId())); Assert.assertNotNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); Assert.assertNotNull(liveTimeline.getState().getMember(data.samSession.getMyUserId())); + lock.countDown(); } } @@ -171,13 +177,15 @@ public void onSuccess(Void info) { boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); Assert.assertTrue(handled); final RoomState roomState = eventTimeline.getState(); + if (withLazyLoading) { Assert.assertEquals(1, roomState.getLoadedMembers().size()); - Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } else { Assert.assertEquals(4, roomState.getLoadedMembers().size()); - Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } + + Assert.assertEquals(1, aliceRoom.getNumberOfInvitedMembers()); + Assert.assertEquals(3, aliceRoom.getNumberOfJoinedMembers()); } @Test @@ -204,22 +212,26 @@ private void RoomState_PermalinkWithBackPagination(final boolean withLazyLoading public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { messageCount++; if (messageCount == 50) { - if (withLazyLoading) { - Assert.assertNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); - Assert.assertNull(eventTimeline.getState().getMember(data.samSession.getMyUserId())); - Assert.assertNull(roomState.getMember(data.bobSession.getMyUserId())); - } Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); + + // With LazyLoading, Bob and Sam are not known by Alice yet + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.bobSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.bobSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); } else if (messageCount == 51) { - if (withLazyLoading) { - Assert.assertNull(roomState.getMember(data.samSession.getMyUserId())); - Assert.assertNull(eventTimeline.getState().getMember(data.samSession.getMyUserId())); - } + // Bob is known now Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); + + // With LazyLoading, Sam is not known by Alice yet + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); } else if (messageCount >= 110) { + // All users are known now Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); Assert.assertNotNull(eventTimeline.getState().getMember(data.samSession.getMyUserId())); + lock.countDown(); } } @@ -261,21 +273,26 @@ private void RoomState_PermalinkWithForwardPagination(final boolean withLazyLoad public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { messageCount++; if (messageCount == 1) { + // We received the Event from bob Assert.assertEquals(event.sender, data.bobSession.getMyUserId()); - if (withLazyLoading) { - Assert.assertNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); - Assert.assertNull(eventTimeline.getState().getMember(data.samSession.getMyUserId())); - } else { - Assert.assertNotNull(roomState.getMember(data.aliceSession.getMyUserId())); - } + + // Bob is known Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); + + // With LazyLoading, Alice and Sam are not known by Alice yet + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.aliceSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); } else if (messageCount == 2) { + // We received the Event from Alice Assert.assertEquals(event.sender, data.aliceSession.getMyUserId()); - if (withLazyLoading) { - Assert.assertNull(eventTimeline.getState().getMember(data.samSession.getMyUserId())); - } + + // Alice and Bob are known Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); + + // With LazyLoading, Sam is not known by Alice yet + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + lock.countDown(); } } @@ -315,5 +332,4 @@ public void onSuccess(Integer info) { } }); } - } From f4c5e86baef2c8c639ddc9d85cbe22807404c1d6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 10:06:58 +0200 Subject: [PATCH 103/236] Fix number of members method when LazyLoading is OFF --- .../java/org/matrix/androidsdk/data/Room.java | 66 +++++++++++++++---- 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 2e9efe465..4efaae7f1 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -3086,32 +3086,76 @@ public boolean isDirect() { @Nullable public RoomSummary getRoomSummary() { + if (getDataHandler() == null) { + return null; + } + + if (getDataHandler().getStore() == null) { + return null; + } + return getDataHandler().getStore().getSummary(getRoomId()); } public int getNumberOfMembers() { - return getNumberOfJoinedMembers() + getNumberOfInvitedMembers(); + if (getDataHandler().isLazyLoadingEnabled()) { + return getNumberOfJoinedMembers() + getNumberOfInvitedMembers(); + } else { + return getState().getLoadedMembers().size(); + } } - // FIXME It returns 0 when LL is off (it will fix avatar issue) public int getNumberOfJoinedMembers() { - RoomSummary roomSummary = getRoomSummary(); + if (getDataHandler().isLazyLoadingEnabled()) { + RoomSummary roomSummary = getRoomSummary(); - if (roomSummary != null) { - return roomSummary.getNumberOfJoinedMembers(); + if (roomSummary != null) { + return roomSummary.getNumberOfJoinedMembers(); + } else { + // Should not happen, fallback to loaded members + return getNumberOfLoadedJoinedMembers(); + } } else { - return 0; + return getNumberOfLoadedJoinedMembers(); + } + } + + private int getNumberOfLoadedJoinedMembers() { + int count = 0; + + for (RoomMember roomMember : getState().getLoadedMembers()) { + if (RoomMember.MEMBERSHIP_JOIN.equals(roomMember.membership)) { + count++; + } } + + return count; } - // FIXME It returns 0 when LL is off (it will fix avatar issue) public int getNumberOfInvitedMembers() { - RoomSummary roomSummary = getRoomSummary(); + if (getDataHandler().isLazyLoadingEnabled()) { + RoomSummary roomSummary = getRoomSummary(); - if (roomSummary != null) { - return roomSummary.getNumberOfInvitedMembers(); + if (roomSummary != null) { + return roomSummary.getNumberOfInvitedMembers(); + } else { + // Should not happen, fallback to loaded members + return getNumberOfLoadedInvitedMembers(); + } } else { - return 0; + return getNumberOfLoadedInvitedMembers(); } } + + private int getNumberOfLoadedInvitedMembers() { + int count = 0; + + for (RoomMember roomMember : getState().getLoadedMembers()) { + if (RoomMember.MEMBERSHIP_INVITE.equals(roomMember.membership)) { + count++; + } + } + + return count; + } } From 23424cf2fa275f17953ebaf9f059a665f36b1af3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 10:18:44 +0200 Subject: [PATCH 104/236] Rename parameter --- .../rest/client/EventsRestClient.java | 380 +++++++++--------- 1 file changed, 190 insertions(+), 190 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/EventsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/EventsRestClient.java index 51e8071bf..0f23254e7 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/EventsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/EventsRestClient.java @@ -80,12 +80,12 @@ public void getThirdPartyServerProtocols(final ApiCallback>(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getThirdPartyServerProtocols(callback); - } - })); + new RestAdapterCallback.RequestRetryCallBack() { + @Override + public void onRetry() { + getThirdPartyServerProtocols(callback); + } + })); } /** @@ -164,12 +164,12 @@ public void loadPublicRooms(final String server, mApi.publicRooms(server, publicRoomsParams) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, - new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - loadPublicRooms(server, thirdPartyInstanceId, includeAllNetworks, pattern, since, limit, callback); - } - })); + new RestAdapterCallback.RequestRetryCallBack() { + @Override + public void onRetry() { + loadPublicRooms(server, thirdPartyInstanceId, includeAllNetworks, pattern, since, limit, callback); + } + })); } @@ -181,22 +181,22 @@ public void onRetry() { * of the state on the server, and then continue to call this API to get * incremental deltas to the state, and to receive new messages. * - * @param token the token to stream from (nil in case of initial sync). - * @param serverTimeout the maximum time in ms to wait for an event. - * @param clientTimeout the maximum time in ms the SDK must wait for the server response. - * @param setPresence the optional parameter which controls whether the client is automatically - * marked as online by polling this API. If this parameter is omitted then the client is - * automatically marked as online when it uses this API. Otherwise if - * the parameter is set to "offline" then the client is not marked as - * being online when it uses this API. - * @param filterId the ID of a filter created using the filter API (optional). - * @param callback The request callback + * @param token the token to stream from (nil in case of initial sync). + * @param serverTimeout the maximum time in ms to wait for an event. + * @param clientTimeout the maximum time in ms the SDK must wait for the server response. + * @param setPresence the optional parameter which controls whether the client is automatically + * marked as online by polling this API. If this parameter is omitted then the client is + * automatically marked as online when it uses this API. Otherwise if + * the parameter is set to "offline" then the client is not marked as + * being online when it uses this API. + * @param filterOrFilterId a JSON filter or the ID of a filter created using the filter API (optional). + * @param callback The request callback */ public void syncFromToken(final String token, final int serverTimeout, final int clientTimeout, final String setPresence, - final String filterId, + final String filterOrFilterId, final ApiCallback callback) { Map params = new HashMap<>(); int timeout = (EVENT_STREAM_TIMEOUT_MS / 1000); @@ -213,8 +213,8 @@ public void syncFromToken(final String token, params.put("set_presence", setPresence); } - if (!TextUtils.isEmpty(filterId)) { - params.put("filter", filterId); + if (!TextUtils.isEmpty(filterOrFilterId)) { + params.put("filter", filterOrFilterId); } params.put("timeout", timeout); @@ -228,11 +228,11 @@ public void syncFromToken(final String token, mApi.sync(params) .enqueue(new RestAdapterCallback(description, null, false, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - syncFromToken(token, serverTimeout, clientTimeout, setPresence, filterId, callback); - } - })); + @Override + public void onRetry() { + syncFromToken(token, serverTimeout, clientTimeout, setPresence, filterOrFilterId, callback); + } + })); } /** @@ -279,65 +279,65 @@ public void searchMessagesByText(final String text, // if the search fails, stop it mApi.searchEvents(searchParams, nextBatch) .enqueue(new RestAdapterCallback(description, null, new ApiCallback() { - /** - * Tells if the current response for the latest request. - * - * @return true if it is the response of the latest request. - */ - private boolean isActiveRequest() { - return TextUtils.equals(mSearchEventsPatternIdentifier, uid + text); - } - - @Override - public void onSuccess(SearchResponse response) { - if (isActiveRequest()) { - if (null != callback) { - callback.onSuccess(response); + /** + * Tells if the current response for the latest request. + * + * @return true if it is the response of the latest request. + */ + private boolean isActiveRequest() { + return TextUtils.equals(mSearchEventsPatternIdentifier, uid + text); } - mSearchEventsPatternIdentifier = null; - } - } + @Override + public void onSuccess(SearchResponse response) { + if (isActiveRequest()) { + if (null != callback) { + callback.onSuccess(response); + } - @Override - public void onNetworkError(Exception e) { - if (isActiveRequest()) { - if (null != callback) { - callback.onNetworkError(e); + mSearchEventsPatternIdentifier = null; + } } - mSearchEventsPatternIdentifier = null; - } - } + @Override + public void onNetworkError(Exception e) { + if (isActiveRequest()) { + if (null != callback) { + callback.onNetworkError(e); + } - @Override - public void onMatrixError(MatrixError e) { - if (isActiveRequest()) { - if (null != callback) { - callback.onMatrixError(e); + mSearchEventsPatternIdentifier = null; + } } - mSearchEventsPatternIdentifier = null; - } - } + @Override + public void onMatrixError(MatrixError e) { + if (isActiveRequest()) { + if (null != callback) { + callback.onMatrixError(e); + } - @Override - public void onUnexpectedError(Exception e) { - if (isActiveRequest()) { - if (null != callback) { - callback.onUnexpectedError(e); + mSearchEventsPatternIdentifier = null; + } } - mSearchEventsPatternIdentifier = null; - } - } + @Override + public void onUnexpectedError(Exception e) { + if (isActiveRequest()) { + if (null != callback) { + callback.onUnexpectedError(e); + } - }, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - searchMessagesByText(text, rooms, beforeLimit, afterLimit, nextBatch, callback); - } - })); + mSearchEventsPatternIdentifier = null; + } + } + + }, new RestAdapterCallback.RequestRetryCallBack() { + @Override + public void onRetry() { + searchMessagesByText(text, rooms, beforeLimit, afterLimit, nextBatch, callback); + } + })); } /** @@ -397,53 +397,53 @@ public void searchMediasByText(final String name, // if the search fails, stop it mApi.searchEvents(searchParams, nextBatch) .enqueue(new RestAdapterCallback(description, null, new ApiCallback() { - /** - * Tells if the current response for the latest request. - * - * @return true if it is the response of the latest request. - */ - private boolean isActiveRequest() { - return TextUtils.equals(mSearchEventsMediaNameIdentifier, uid + name); - } + /** + * Tells if the current response for the latest request. + * + * @return true if it is the response of the latest request. + */ + private boolean isActiveRequest() { + return TextUtils.equals(mSearchEventsMediaNameIdentifier, uid + name); + } - @Override - public void onSuccess(SearchResponse newSearchResponse) { - if (isActiveRequest()) { - callback.onSuccess(newSearchResponse); - mSearchEventsMediaNameIdentifier = null; - } - } + @Override + public void onSuccess(SearchResponse newSearchResponse) { + if (isActiveRequest()) { + callback.onSuccess(newSearchResponse); + mSearchEventsMediaNameIdentifier = null; + } + } - @Override - public void onNetworkError(Exception e) { - if (isActiveRequest()) { - callback.onNetworkError(e); - mSearchEventsMediaNameIdentifier = null; - } - } + @Override + public void onNetworkError(Exception e) { + if (isActiveRequest()) { + callback.onNetworkError(e); + mSearchEventsMediaNameIdentifier = null; + } + } - @Override - public void onMatrixError(MatrixError e) { - if (isActiveRequest()) { - callback.onMatrixError(e); - mSearchEventsMediaNameIdentifier = null; - } - } + @Override + public void onMatrixError(MatrixError e) { + if (isActiveRequest()) { + callback.onMatrixError(e); + mSearchEventsMediaNameIdentifier = null; + } + } - @Override - public void onUnexpectedError(Exception e) { - if (isActiveRequest()) { - callback.onUnexpectedError(e); - mSearchEventsMediaNameIdentifier = null; - } - } + @Override + public void onUnexpectedError(Exception e) { + if (isActiveRequest()) { + callback.onUnexpectedError(e); + mSearchEventsMediaNameIdentifier = null; + } + } - }, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - searchMediasByText(name, rooms, beforeLimit, afterLimit, nextBatch, callback); - } - })); + }, new RestAdapterCallback.RequestRetryCallBack() { + @Override + public void onRetry() { + searchMediasByText(name, rooms, beforeLimit, afterLimit, nextBatch, callback); + } + })); } @@ -469,70 +469,70 @@ public void searchUsers(final String text, final Integer limit, final Set(description, null, new ApiCallback() { - /** - * Tells if the current response for the latest request. - * - * @return true if it is the response of the latest request. - */ - private boolean isActiveRequest() { - return TextUtils.equals(mSearchUsersPatternIdentifier, uid); - } - - @Override - public void onSuccess(SearchUsersRequestResponse aResponse) { - if (isActiveRequest()) { - SearchUsersResponse response = new SearchUsersResponse(); - response.limited = aResponse.limited; - response.results = new ArrayList<>(); - Set filter = (null != userIdsFilter) ? userIdsFilter : new HashSet(); - - if (null != aResponse.results) { - for (SearchUsersRequestResponse.User user : aResponse.results) { - if ((null != user.user_id) && !filter.contains(user.user_id)) { - User addedUser = new User(); - addedUser.user_id = user.user_id; - addedUser.avatar_url = user.avatar_url; - addedUser.displayname = user.display_name; - response.results.add(addedUser); + /** + * Tells if the current response for the latest request. + * + * @return true if it is the response of the latest request. + */ + private boolean isActiveRequest() { + return TextUtils.equals(mSearchUsersPatternIdentifier, uid); } - } - } - callback.onSuccess(response); - mSearchUsersPatternIdentifier = null; - } - } + @Override + public void onSuccess(SearchUsersRequestResponse aResponse) { + if (isActiveRequest()) { + SearchUsersResponse response = new SearchUsersResponse(); + response.limited = aResponse.limited; + response.results = new ArrayList<>(); + Set filter = (null != userIdsFilter) ? userIdsFilter : new HashSet(); + + if (null != aResponse.results) { + for (SearchUsersRequestResponse.User user : aResponse.results) { + if ((null != user.user_id) && !filter.contains(user.user_id)) { + User addedUser = new User(); + addedUser.user_id = user.user_id; + addedUser.avatar_url = user.avatar_url; + addedUser.displayname = user.display_name; + response.results.add(addedUser); + } + } + } + + callback.onSuccess(response); + mSearchUsersPatternIdentifier = null; + } + } - @Override - public void onNetworkError(Exception e) { - if (isActiveRequest()) { - callback.onNetworkError(e); - mSearchUsersPatternIdentifier = null; - } - } + @Override + public void onNetworkError(Exception e) { + if (isActiveRequest()) { + callback.onNetworkError(e); + mSearchUsersPatternIdentifier = null; + } + } - @Override - public void onMatrixError(MatrixError e) { - if (isActiveRequest()) { - callback.onMatrixError(e); - mSearchUsersPatternIdentifier = null; - } - } + @Override + public void onMatrixError(MatrixError e) { + if (isActiveRequest()) { + callback.onMatrixError(e); + mSearchUsersPatternIdentifier = null; + } + } - @Override - public void onUnexpectedError(Exception e) { - if (isActiveRequest()) { - callback.onUnexpectedError(e); - mSearchUsersPatternIdentifier = null; - } - } + @Override + public void onUnexpectedError(Exception e) { + if (isActiveRequest()) { + callback.onUnexpectedError(e); + mSearchUsersPatternIdentifier = null; + } + } - }, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - searchUsers(text, limit, userIdsFilter, callback); - } - })); + }, new RestAdapterCallback.RequestRetryCallBack() { + @Override + public void onRetry() { + searchUsers(text, limit, userIdsFilter, callback); + } + })); } /** @@ -568,18 +568,18 @@ public void getURLPreview(final String url, final long ts, final ApiCallback>(description, null, false, - new SimpleApiCallback >(callback) { - @Override - public void onSuccess(Map map) { - if (null != callback) { - callback.onSuccess(new URLPreview(map, url)); - } - } - }, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getURLPreview(url, ts, callback); - } - })); + new SimpleApiCallback>(callback) { + @Override + public void onSuccess(Map map) { + if (null != callback) { + callback.onSuccess(new URLPreview(map, url)); + } + } + }, new RestAdapterCallback.RequestRetryCallBack() { + @Override + public void onRetry() { + getURLPreview(url, ts, callback); + } + })); } } From 0c2d9cd4bba24e1e100210226fb9d9c6b28c5962 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 11:24:02 +0200 Subject: [PATCH 105/236] Improve lock management --- .../androidsdk/common/CommonTestHelper.java | 63 +++-- .../androidsdk/crypto/CryptoRestTest.java | 10 +- .../matrix/androidsdk/crypto/CryptoTest.java | 244 +++++++++--------- .../lazyloading/LazyLoadingTestHelper.java | 21 +- .../androidsdk/lazyloading/RoomStateTest.java | 14 +- 5 files changed, 177 insertions(+), 175 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index 19af34483..ce2791689 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -58,27 +58,28 @@ */ public class CommonTestHelper { - public MXSession createBobAccount(boolean withInitialSync, boolean enableCrypto) { + public MXSession createBobAccount(boolean withInitialSync, boolean enableCrypto) throws InterruptedException { return createAccount(TestConstants.BOB_USER_ID, TestConstants.BOB_PWD, withInitialSync, enableCrypto); } - public MXSession createAliceAccount(boolean withInitialSync, boolean enableCrypto) { + public MXSession createAliceAccount(boolean withInitialSync, boolean enableCrypto) throws InterruptedException { return createAccount(TestConstants.ALICE_USER_ID, TestConstants.ALICE_PWD, withInitialSync, enableCrypto); } - public MXSession createSamAccount(boolean withInitialSync, boolean enableCrypto) { + public MXSession createSamAccount(boolean withInitialSync, boolean enableCrypto) throws InterruptedException { return createAccount(TestConstants.SAM_USER_ID, TestConstants.SAM_PWD, withInitialSync, enableCrypto); } - public MXSession logIntoBobAccount(final String bobUserId, final boolean withInitialSync, boolean enableCrypto) { + public MXSession logIntoBobAccount(final String bobUserId, final boolean withInitialSync, boolean enableCrypto) throws InterruptedException { return logIntoAccount(bobUserId, TestConstants.BOB_PWD, withInitialSync, enableCrypto, false); } - public MXSession logIntoAliceAccount(final String aliceUserId, final boolean withInitialSync, boolean enableCrypto, boolean withLazyLoading) { + public MXSession logIntoAliceAccount(final String aliceUserId, final boolean withInitialSync, boolean enableCrypto, boolean withLazyLoading) + throws InterruptedException { return logIntoAccount(aliceUserId, TestConstants.ALICE_PWD, withInitialSync, enableCrypto, withLazyLoading); } - public MXSession logIntoSamAccount(final String samUserId, final boolean withInitialSync, boolean enableCrypto) { + public MXSession logIntoSamAccount(final String samUserId, final boolean withInitialSync, boolean enableCrypto) throws InterruptedException { return logIntoAccount(samUserId, TestConstants.SAM_PWD, withInitialSync, enableCrypto, false); } @@ -103,7 +104,7 @@ public HomeServerConnectionConfig createHomeServerConfig(@Nullable Credentials c * @param session the session to sync * @param withCrypto true if crypto is enabled and should be checked */ - public void syncSession(@Nonnull final MXSession session, final boolean withCrypto) { + public void syncSession(@Nonnull final MXSession session, final boolean withCrypto) throws InterruptedException { final Map params = new HashMap<>(); final int sizeOfLock = withCrypto ? 2 : 1; final CountDownLatch lock2 = new CountDownLatch(sizeOfLock); @@ -122,11 +123,8 @@ public void onCryptoSyncComplete() { }); session.getDataHandler().getStore().open(); session.startEventStream(null); - try { - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } + + await(lock2); Assert.assertTrue(params.containsKey("isInit")); if (withCrypto) { Assert.assertTrue(params.containsKey("onCryptoSyncComplete")); @@ -170,7 +168,7 @@ public void onEncryptionFailed(RoomMediaMessage roomMediaMessage) { } }); } - latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + await(latch); room.removeEventListener(onEventSentListener); // Check that all events has been created @@ -194,7 +192,7 @@ public void onEncryptionFailed(RoomMediaMessage roomMediaMessage) { private MXSession createAccount(@NonNull final String userId, @NonNull final String password, final boolean withInitialSync, - final boolean enableCrypto) { + final boolean enableCrypto) throws InterruptedException { final Context context = InstrumentationRegistry.getContext(); final MXSession session = createAccountAndSync( context, @@ -220,7 +218,7 @@ private MXSession logIntoAccount(@NonNull final String userId, @NonNull final String password, final boolean withInitialSync, final boolean enableCrypto, - boolean withLazyLoading) { + boolean withLazyLoading) throws InterruptedException { final Context context = InstrumentationRegistry.getContext(); final MXSession session = logAccountAndSync(context, userId, password, withInitialSync, enableCrypto, withLazyLoading); Assert.assertNotNull(session); @@ -236,7 +234,11 @@ private MXSession logIntoAccount(@NonNull final String userId, * @param withInitialSync true to perform an initial sync * @param enableCrypto true to set enableCryptoWhenStarting */ - private MXSession createAccountAndSync(Context context, String userName, String password, boolean withInitialSync, boolean enableCrypto) { + private MXSession createAccountAndSync(Context context, + String userName, + String password, + boolean withInitialSync, + boolean enableCrypto) throws InterruptedException { final HomeServerConnectionConfig hs = createHomeServerConfig(null); final LoginRestClient loginRestClient = new LoginRestClient(hs); @@ -270,11 +272,7 @@ public void onMatrixError(MatrixError e) { } }); - try { - lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - - } + await(lock); final String session = (String) params.get("session"); @@ -297,11 +295,7 @@ public void onSuccess(Credentials credentials) { } }); - try { - lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } + await(lock); Credentials credentials = (Credentials) params.get("credentials"); @@ -337,7 +331,7 @@ private MXSession logAccountAndSync(Context context, String password, boolean withInitialSync, boolean enableCrypto, - boolean withLazyLoading) { + boolean withLazyLoading) throws InterruptedException { final HomeServerConnectionConfig hs = createHomeServerConfig(null); LoginRestClient loginRestClient = new LoginRestClient(hs); final Map params = new HashMap<>(); @@ -352,11 +346,7 @@ public void onSuccess(Credentials credentials) { } }); - try { - lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } + await(lock); final Credentials credentials = (Credentials) params.get("credentials"); @@ -381,4 +371,13 @@ public void onSuccess(Credentials credentials) { return mxSession; } + /** + * Await for a latch and ensure the result is true + * + * @param latch + * @throws InterruptedException + */ + public void await(CountDownLatch latch) throws InterruptedException { + Assert.assertTrue(latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS)); + } } diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java index 1d0e0c30e..ac76a120e 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java @@ -75,7 +75,7 @@ public void onSuccess(KeysUploadResponse keysUploadResponse) { super.onSuccess(keysUploadResponse); } }); - lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock0); KeysUploadResponse keysUploadResponse = (KeysUploadResponse) results.get("keysUploadResponse"); @@ -94,7 +94,7 @@ public void onSuccess(KeysQueryResponse keysQueryResponse) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); KeysQueryResponse keysQueryResponse = (KeysQueryResponse) results.get("keysQueryResponse"); Assert.assertNotNull(keysQueryResponse); @@ -136,7 +136,7 @@ public void onSuccess(KeysUploadResponse keysUploadResponse) { super.onSuccess(keysUploadResponse); } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); KeysUploadResponse keysUploadResponse = (KeysUploadResponse) results.get("keysUploadResponse"); Assert.assertNotNull(keysUploadResponse); @@ -194,7 +194,7 @@ public void onSuccess(KeysUploadResponse keysUploadResponse) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); KeysUploadResponse bobKeysUploadResponse = (KeysUploadResponse) results.get("keysUploadResponse"); Assert.assertNotNull(bobKeysUploadResponse); @@ -211,7 +211,7 @@ public void onSuccess(MXUsersDevicesMap usersDevicesMap) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); MXUsersDevicesMap oneTimeKeys = (MXUsersDevicesMap) results.get("usersDevicesMap"); Assert.assertNotNull(oneTimeKeys); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 7b7d0b639..e69183dc1 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -101,7 +101,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("enableCrypto")); Assert.assertNotNull(bobSession.getCrypto()); @@ -129,7 +129,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("enableCrypto")); Assert.assertNotNull(bobSession.getCrypto()); @@ -179,7 +179,7 @@ public void onStoreOOM(String accountId, String description) { bobSession2.getDataHandler().getStore().addMXStoreListener(listener); bobSession2.getDataHandler().getStore().open(); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("onStoreReady")); Assert.assertTrue(bobSession2.isCryptoEnabled()); @@ -201,7 +201,7 @@ public void onCryptoSyncComplete() { }; bobSession2.getDataHandler().addListener(eventsListener); bobSession2.startEventStream(null); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); @@ -237,7 +237,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("enableCrypto")); MXSession bobSession = mTestHelper.createBobAccount(true, false); @@ -250,7 +250,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("enableCrypto2")); CountDownLatch lock3 = new CountDownLatch(1); @@ -265,7 +265,7 @@ public void onSuccess(MXUsersDevicesMap info) { } }); - lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3); Assert.assertTrue(results.containsKey("downloadKeys")); MXUsersDevicesMap usersDevicesInfoMap = (MXUsersDevicesMap) results.get("downloadKeys"); @@ -291,7 +291,7 @@ public void onSuccess(Void info) { } } ); - lock3a.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3a); Assert.assertTrue(results.containsKey("setDevicesKnown")); Assert.assertTrue(aliceDeviceFromBobPOV.isUnverified()); @@ -308,7 +308,7 @@ public void onSuccess(Void info) { } } ); - lock3b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3b); Assert.assertTrue(results.containsKey("setDeviceVerification1")); Assert.assertTrue(aliceDeviceFromBobPOV.isBlocked()); @@ -348,7 +348,7 @@ public void onStoreOOM(String accountId, String description) { bobSession2.getDataHandler().getStore().addMXStoreListener(listener); bobSession2.getDataHandler().getStore().open(); - lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock4); Assert.assertTrue(results.containsKey("onStoreReady")); final CountDownLatch lock4b = new CountDownLatch(2); @@ -369,7 +369,7 @@ public void onCryptoSyncComplete() { bobSession2.getDataHandler().addListener(eventListener); bobSession2.startEventStream(null); - lock4b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock4b); Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); @@ -392,7 +392,7 @@ public void onSuccess(MXUsersDevicesMap info) { super.onSuccess(info); } }); - lock5.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock5); Assert.assertTrue(results.containsKey("downloadKeys2")); MXDeviceInfo aliceDeviceFromBobPOV3 = bobSession2.getCrypto().deviceWithIdentityKey(aliceSession.getCrypto().getOlmDevice().getDeviceCurve25519Key(), @@ -428,7 +428,7 @@ public void onSuccess(Void info) { } }); - lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("enableCryptoAlice")); MXSession bobSession = mTestHelper.createBobAccount(true, false); @@ -442,7 +442,7 @@ public void onSuccess(Void info) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("enableCryptoBob")); CountDownLatch lock3 = new CountDownLatch(1); @@ -455,7 +455,7 @@ public void onSuccess(MXUsersDevicesMap map) { } }); - lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3); Assert.assertTrue(results.containsKey("downloadKeys")); CountDownLatch lock4 = new CountDownLatch(1); @@ -468,7 +468,7 @@ public void onSuccess(MXUsersDevicesMap info) { } }); - lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock4); Assert.assertTrue(results.containsKey("ensureOlmSessionsForUsers")); MXUsersDevicesMap result = (MXUsersDevicesMap) results.get("ensureOlmSessionsForUsers"); @@ -522,7 +522,7 @@ public void onStoreReady() { lock5.countDown(); } }); - lock5.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock5); Assert.assertTrue(results.containsKey("onStoreReady")); final CountDownLatch lock5b = new CountDownLatch(2); @@ -543,7 +543,7 @@ public void onCryptoSyncComplete() { bobSession2.getDataHandler().addListener(eventListener); bobSession2.startEventStream(null); - lock5b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock5b); Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); @@ -556,7 +556,7 @@ public void onSuccess(MXUsersDevicesMap info) { super.onSuccess(info); } }); - lock6.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock6); Assert.assertTrue(results.containsKey("ensureOlmSessionsForUsers2")); MXUsersDevicesMap result2 = (MXUsersDevicesMap) results.get("ensureOlmSessionsForUsers2"); @@ -588,7 +588,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("enableCrypto")); final String[] roomId = {null}; @@ -602,7 +602,7 @@ public void onSuccess(String info) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertNotNull(roomId[0]); Room room = bobSession.getDataHandler().getRoom(roomId[0]); @@ -617,7 +617,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("enableEncryptionWithAlgorithm")); Assert.assertTrue(room.isEncrypted()); @@ -648,7 +648,7 @@ public void test06_testAliceInAEncryptedRoom() throws Exception { roomFromAlicePOV.sendEvent(buildTextEvent(message, aliceSession, aliceRoomId), new TestApiCallback(lock1)); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); aliceSession.clear(context); } @@ -683,7 +683,7 @@ public void onMatrixError(MatrixError e) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("sendEventError")); MXCryptoError error = (MXCryptoError) results.get("sendEventError"); Assert.assertEquals(MXCryptoError.UNKNOWN_DEVICES_CODE, error.errcode); @@ -701,7 +701,7 @@ public void onSuccess(Void info) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("setDevicesKnown")); final CountDownLatch lock3 = new CountDownLatch(3); @@ -730,7 +730,7 @@ public void onToDeviceEvent(Event event) { roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new TestApiCallback(lock3)); - lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertTrue(results.containsKey("onLiveEvent")); @@ -812,28 +812,28 @@ public void onToDeviceEvent(Event event) { }); roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession, aliceRoomId), callback); - list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(list.get(list.size() - 1)); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, nbReceivedMessagesFromAlice[0]); list.add(new CountDownLatch(1)); roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession, aliceRoomId), callback); - list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(list.get(list.size() - 1)); Assert.assertEquals(1, nbReceivedMessagesFromBob[0]); list.add(new CountDownLatch(1)); roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession, aliceRoomId), callback); - list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(list.get(list.size() - 1)); Assert.assertEquals(2, nbReceivedMessagesFromBob[0]); list.add(new CountDownLatch(1)); roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(nbReceivedMessagesFromBob[0]), bobSession, aliceRoomId), callback); - list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(list.get(list.size() - 1)); Assert.assertEquals(3, nbReceivedMessagesFromBob[0]); list.add(new CountDownLatch(1)); roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession, aliceRoomId), callback); - list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(list.get(list.size() - 1)); Assert.assertEquals(2, nbReceivedMessagesFromAlice[0]); } @@ -889,7 +889,7 @@ public void onStoreOOM(String accountId, String description) { aliceSession2.getDataHandler().getStore().addMXStoreListener(listener); aliceSession2.getDataHandler().getStore().open(); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("onStoreReady")); final CountDownLatch lock1b = new CountDownLatch(2); @@ -909,7 +909,7 @@ public void onCryptoSyncComplete() { aliceSession2.getDataHandler().addListener(eventListener); aliceSession2.startEventStream(null); - lock1b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1b); Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); @@ -945,7 +945,7 @@ public void onSuccess(Void info) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("sendEvent")); aliceSession2.clear(context); @@ -976,7 +976,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("sendEvent")); Credentials aliceCredentials = aliceSession.getCredentials(); @@ -1025,7 +1025,7 @@ public void onStoreOOM(String accountId, String description) { aliceSession2.getDataHandler().getStore().addMXStoreListener(listener); aliceSession2.getDataHandler().getStore().open(); - lock1b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1b); Assert.assertTrue(results.containsKey("onStoreReady")); final CountDownLatch lock2 = new CountDownLatch(2); @@ -1046,7 +1046,7 @@ public void onCryptoSyncComplete() { aliceSession2.getDataHandler().addListener(eventListener); aliceSession2.startEventStream(null); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); @@ -1107,7 +1107,7 @@ public void onCryptoSyncComplete() { bobSession2.getDataHandler().getStore().open(); bobSession2.startEventStream(null); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); @@ -1138,7 +1138,7 @@ public void onSuccess(Integer info) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("backPaginate")); Assert.assertEquals(receivedEvents.size() + " instead of 5", 5, receivedEvents.size()); @@ -1193,7 +1193,7 @@ public void onSuccess(Integer info) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("backPaginate")); Assert.assertEquals(5, receivedEvents.size()); @@ -1253,7 +1253,7 @@ public void onSuccess(Void info) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("bobEcho")); Event event = (Event) results.get("bobEcho"); @@ -1286,7 +1286,7 @@ public void onSuccess(Void info) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("aliceEcho")); event = (Event) results.get("aliceEcho"); @@ -1349,7 +1349,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock0); Assert.assertTrue(results + "", results.containsKey("send0") && results.containsKey("alice0") && results.containsKey("sam0")); roomFromAlicePOV.removeEventListener(aliceEventsListener0); @@ -1388,7 +1388,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results + "", results.containsKey("send1") && results.containsKey("bob1") && results.containsKey("sam1")); List list = bobSession.getCrypto().getUserDevices(aliceSession.getMyUserId()); @@ -1405,7 +1405,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock1b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1b); Assert.assertTrue(results.containsKey("setDeviceVerification10")); final CountDownLatch lock2 = new CountDownLatch(3); @@ -1440,7 +1440,7 @@ public void onSuccess(Void info) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("send2") && results.containsKey("alice2") && results.containsKey("sam2")); roomFromAlicePOV.removeEventListener(aliceEventsListener2); @@ -1465,7 +1465,7 @@ public void onSuccess(Void info) { } }); - lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3); Assert.assertTrue(results.containsKey("leave") && results.containsKey("bobleave")); final CountDownLatch lock4 = new CountDownLatch(2); @@ -1489,7 +1489,7 @@ public void onSuccess(Void info) { } }); - lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock4); Assert.assertTrue(results.containsKey("send3") && results.containsKey("alice3")); bobSession.clear(context); @@ -1552,7 +1552,7 @@ public void onSuccess(Void info) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertTrue(results.containsKey("bobEcho")); Assert.assertTrue(results.containsKey("decrypted")); @@ -1622,7 +1622,7 @@ public void onSuccess(Void info) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, receivedEvents.size()); @@ -1703,7 +1703,7 @@ public void onSuccess(Void info) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, receivedEvents.size()); @@ -1744,7 +1744,7 @@ public void onEventDecrypted(Event event) { bobSession.getDataHandler().onToDeviceEvent(toDeviceEvent); // the message should be decrypted later - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("onEventDecrypted")); Assert.assertEquals(1, receivedEvents.size()); @@ -1808,7 +1808,7 @@ public void onSuccess(Void info) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, receivedEvents.size()); @@ -1825,7 +1825,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("logout")); final CountDownLatch lock3 = new CountDownLatch(1); @@ -1848,7 +1848,7 @@ public void onToDeviceEvent(Event event) { Assert.assertNotEquals(bobDeviceId2, bobDeviceId1); // before sending a message, wait that the device event is received. - lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3); Assert.assertTrue(results.containsKey("onToDeviceEvent2")); SystemClock.sleep(1000); @@ -1881,7 +1881,7 @@ public void onSuccess(Void info) { } }); - lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock4); Assert.assertEquals("received event of type " + results.get("event4"), 1, receivedEvents4.size()); event = receivedEvents4.get(0); @@ -1945,7 +1945,7 @@ public void onSuccess(Void info) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, receivedEvents.size()); @@ -1961,7 +1961,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("boblogout")); CountDownLatch lock3 = new CountDownLatch(1); @@ -1972,7 +1972,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3); Assert.assertTrue(results.containsKey("alicelogout")); MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), true, true); @@ -2014,7 +2014,7 @@ public void onSuccess(Void info) { } }); - lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock4); Assert.assertEquals(1, receivedEvents2.size()); event = receivedEvents2.get(0); @@ -2063,7 +2063,7 @@ public void onSuccess(Void info) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); @@ -2107,7 +2107,7 @@ public void onSuccess(Void info) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertEquals(1, receivedEvents2.size()); event = receivedEvents2.get(0); @@ -2126,7 +2126,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock2b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2b); Assert.assertTrue(results.containsKey("setDeviceVerification40")); /// final CountDownLatch lock3 = new CountDownLatch(1); @@ -2152,7 +2152,7 @@ public void onSuccess(Void info) { } }); - lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3); Assert.assertEquals(1, receivedEvents3.size()); event = receivedEvents3.get(0); @@ -2190,7 +2190,7 @@ public void onSuccess(MXUsersDevicesMap info) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("downloadKeys")); MXUsersDevicesMap usersDevicesInfoMap = (MXUsersDevicesMap) results.get("downloadKeys"); @@ -2225,7 +2225,7 @@ public void onSuccess(MXUsersDevicesMap info) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("downloadKeys")); MXUsersDevicesMap usersDevicesInfoMap = (MXUsersDevicesMap) results.get("downloadKeys"); @@ -2247,7 +2247,7 @@ public void onSuccess(MXUsersDevicesMap info) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("downloadKeys2")); } @@ -2287,7 +2287,7 @@ public void onSuccess(Void info) { } }); - lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("sendEvent")); final CountDownLatch lock2 = new CountDownLatch(2); @@ -2315,7 +2315,7 @@ public void onToDeviceEvent(Event event) { bobSession.resumeEventStream(); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertTrue(results.containsKey("onLiveEvent")); @@ -2348,7 +2348,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("sendEvent")); Credentials aliceCredentials = aliceSession.getCredentials(); @@ -2363,7 +2363,7 @@ public void onSuccess(byte[] info) { } }); - lock1a.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1a); Assert.assertTrue(results.containsKey("exportRoomKeys")); // close the session and clear the data @@ -2409,7 +2409,7 @@ public void onStoreOOM(String accountId, String description) { aliceSession2.getDataHandler().getStore().addMXStoreListener(listener); aliceSession2.getDataHandler().getStore().open(); - lock1b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1b); Assert.assertTrue(results.containsKey("onStoreReady")); final CountDownLatch lock2 = new CountDownLatch(2); @@ -2430,7 +2430,7 @@ public void onCryptoSyncComplete() { aliceSession2.getDataHandler().addListener(eventListener); aliceSession2.startEventStream(null); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("onInitialSyncComplete")); Assert.assertTrue(results.containsKey("onCryptoSyncComplete")); @@ -2475,7 +2475,7 @@ public void onUnexpectedError(Exception e) { super.onUnexpectedError(e); } }); - lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3); Assert.assertFalse(results.containsKey("importRoomKeys")); Assert.assertTrue(results.containsKey("importRoomKeys_failed")); @@ -2495,7 +2495,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock4); Assert.assertTrue(results.containsKey("importRoomKeys")); // check that the message CAN be decrypted @@ -2528,7 +2528,7 @@ public void test25_testLeftAndJoinedBob() throws Exception { aliceSession.enableCrypto(true, new TestApiCallback(lock_1)); bobSession.enableCrypto(true, new TestApiCallback(lock_1)); - lock_1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock_1); Assert.assertNotNull(aliceSession.getCrypto()); Assert.assertNotNull(bobSession.getCrypto()); @@ -2545,7 +2545,7 @@ public void onSuccess(String roomId) { super.onSuccess(roomId); } }); - lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("roomId")); String aliceRoomId = (String) results.get("roomId"); @@ -2559,7 +2559,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("enableEncryptionWithAlgorithm")); CountDownLatch lock2 = new CountDownLatch(1); @@ -2570,7 +2570,7 @@ public void onSuccess(String info) { super.onSuccess(info); } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("joinRoom")); Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); @@ -2593,7 +2593,7 @@ public void onSuccess(Void info) { } }); - lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3); Assert.assertEquals(1, receivedEvents.size()); Event event = receivedEvents.get(0); @@ -2607,7 +2607,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock4); Assert.assertTrue(results.containsKey("leave")); // Make Bob come back to the room with a new device @@ -2628,7 +2628,7 @@ public void onSuccess(String info) { super.onSuccess(info); } }); - lock5.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock5); Assert.assertTrue(results.containsKey("joinRoom2")); Room roomFromBobPOV2 = bobSession2.getDataHandler().getRoom(aliceRoomId); @@ -2652,7 +2652,7 @@ public void onSuccess(Void info) { } }); - lock6.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock6); Assert.assertEquals(1, receivedEvents2.size()); event = receivedEvents2.get(0); @@ -2713,7 +2713,7 @@ public void onMatrixError(MatrixError e) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("sendEventError")); MXCryptoError error = (MXCryptoError) results.get("sendEventError"); Assert.assertEquals(MXCryptoError.UNKNOWN_DEVICES_CODE, error.errcode); @@ -2739,7 +2739,7 @@ public void onSuccess(Void info) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("setDevicesKnown")); final CountDownLatch lock3 = new CountDownLatch(5); @@ -2794,7 +2794,7 @@ public void onSuccess(Void info) { } }); - lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3); Assert.assertTrue(results.containsKey("onToDeviceEventBob")); Assert.assertTrue(results.containsKey("onToDeviceEventSam")); Assert.assertTrue(results.containsKey("onLiveEventBob1")); @@ -2848,7 +2848,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock4); Assert.assertTrue(results.containsKey("setGlobalBlacklistUnverifiedDevicesTrue")); // ensure that there is no received message @@ -2862,7 +2862,7 @@ public void onSuccess(Void info) { roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession, aliceRoomId), new TestApiCallback(lock5)); - lock5.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock5); Assert.assertFalse(results.containsKey("eventListenerBob2")); Assert.assertFalse(results.containsKey("eventListenerSam2")); Assert.assertTrue(results.containsKey("eventListenerEncyptedBob2")); @@ -2876,7 +2876,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock6.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock6); Assert.assertTrue(results.containsKey("setGlobalBlacklistUnverifiedDevicesfalse")); // ensure that the messages are received @@ -2890,7 +2890,7 @@ public void onSuccess(Void info) { roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession, aliceRoomId), new TestApiCallback(lock7)); - lock7.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock7); Assert.assertTrue(results.containsKey("eventListenerBob2")); Assert.assertTrue(results.containsKey("eventListenerSam2")); Assert.assertFalse(results.containsKey("eventListenerEncyptedBob2")); @@ -2908,7 +2908,7 @@ public void onSuccess(Void info) { } } ); - lock8.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock8); Assert.assertTrue(results.containsKey("setDeviceVerificationBob")); CountDownLatch lock9 = new CountDownLatch(3); @@ -2919,7 +2919,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock9.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock9); Assert.assertTrue(results.containsKey("setRoomBlacklistUnverifiedDevices")); // ensure that the messages are received @@ -2933,7 +2933,7 @@ public void onSuccess(Void info) { roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession, aliceRoomId), new TestApiCallback(lock10)); - lock10.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock10); Assert.assertTrue(results.containsKey("eventListenerBob2")); Assert.assertFalse(results.containsKey("eventListenerSam2")); Assert.assertFalse(results.containsKey("eventListenerEncyptedBob2")); @@ -2947,7 +2947,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock11.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock11); Assert.assertTrue(results.containsKey("setRoomUnblacklistUnverifiedDevices")); // ensure that the messages are received @@ -2961,7 +2961,7 @@ public void onSuccess(Void info) { roomFromAlicePOV.sendEvent(buildTextEvent(activeMessage.get(0), aliceSession, aliceRoomId), new TestApiCallback(lock12)); - lock12.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock12); Assert.assertTrue(results.containsKey("eventListenerBob2")); Assert.assertTrue(results.containsKey("eventListenerSam2")); Assert.assertFalse(results.containsKey("eventListenerEncyptedBob2")); @@ -3003,7 +3003,7 @@ public void onSuccess(Void info) { results.put("enableCrypto2", "enableCrypto2"); } }); - lock00b.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock00b); Assert.assertTrue(results.containsKey("enableCrypto2")); Assert.assertTrue(results.containsKey("enableCrypto1")); @@ -3020,7 +3020,7 @@ public void onSuccess(String roomId) { super.onSuccess(roomId); } }); - lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("roomId")); String aliceRoomId = (String) results.get("roomId"); @@ -3032,7 +3032,7 @@ public void onSuccess(String info) { super.onSuccess(info); } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("joinRoom")); Room roomFromAlicePOV = aliceSession.getDataHandler().getRoom(aliceRoomId); @@ -3045,7 +3045,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("sendEvent1")); // Make Bob come back to the room with a new device @@ -3066,7 +3066,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3); Assert.assertTrue(results.containsKey("enableEncryptionWithAlgorithm")); Room roomFromBobPOV2 = bobSession2.getDataHandler().getRoom(aliceRoomId); @@ -3092,7 +3092,7 @@ public void onSuccess(Void info) { } }); - lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock4); Assert.assertEquals(1, receivedEvents2.size()); Event event = receivedEvents2.get(0); @@ -3131,7 +3131,7 @@ public void onSuccess(Void info) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(results.containsKey("lock1")); // - Alice adds a new device @@ -3151,7 +3151,7 @@ public void onSuccess(String info) { super.onSuccess(info); } }); - lock3.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock3); Assert.assertNotNull(aliceRoomId2[0]); Room roomFromAlicePOV = aliceSession2.getDataHandler().getRoom(aliceRoomId2[0]); @@ -3163,7 +3163,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock4.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock4); Assert.assertTrue(results.containsKey("lock4")); CountDownLatch lock5 = new CountDownLatch(1); @@ -3174,7 +3174,7 @@ public void onSuccess(String info) { super.onSuccess(info); } }); - lock5.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock5); Assert.assertTrue(results.containsKey("lock5")); // - Bob has an out of date list of Alice's devices @@ -3197,7 +3197,7 @@ public void onLiveEvent(Event event, RoomState roomState) { roomFromBobPOV.sendEvent(buildTextEvent(messageFromBob, bobSession, aliceRoomId2[0]), new TestApiCallback(lock6)); - lock6.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock6); Assert.assertTrue(results.containsKey("lock6")); bobSession.clear(context); @@ -3299,7 +3299,7 @@ public void onToDeviceEvent(Event event) { // Alice sends a first event roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(nbReceivedMessagesFromAlice[0]), aliceSession, aliceRoomId), callback); - list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(list.get(list.size() - 1)); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, nbReceivedMessagesFromAlice[0]); @@ -3308,7 +3308,7 @@ public void onToDeviceEvent(Event event) { list.add(new CountDownLatch(1)); roomFromBobPOV.sendTextMessage(messagesFromBob.get(nbReceivedMessagesFromBob[0]), null, Message.MSGTYPE_TEXT, bobReceivedEvents.get(0), null); - list.get(list.size() - 1).await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(list.get(list.size() - 1)); Assert.assertEquals(1, nbReceivedMessagesFromBob[0]); Event event = aliceReceivedEvents.get(0); @@ -3351,7 +3351,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("enableCrypto")); final String[] roomId = {null}; @@ -3365,7 +3365,7 @@ public void onSuccess(String createdRoomId) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertNotNull(roomId[0]); Room room = aliceSession.getDataHandler().getRoom(roomId[0]); @@ -3378,7 +3378,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(results.containsKey("enableEncryptionWithAlgorithm")); return new SessionAndRoomId(aliceSession, roomId[0]); @@ -3408,7 +3408,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock0); final CountDownLatch lock1 = new CountDownLatch(2); @@ -3434,7 +3434,7 @@ public void onSuccess(Void info) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(statuses.containsKey("invite") && statuses.containsKey("onNewRoom")); @@ -3483,7 +3483,7 @@ public void onLiveEvent(Event event, RoomState roomState) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(statuses + "", statuses.containsKey("joinRoom")); Assert.assertTrue(statuses + "", statuses.containsKey("AliceJoin")); @@ -3515,7 +3515,7 @@ public void onSuccess(Void info) { super.onSuccess(info); } }); - lock0.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock0); final CountDownLatch lock1 = new CountDownLatch(2); @@ -3541,7 +3541,7 @@ public void onSuccess(Void info) { } }); - lock1.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock1); Assert.assertTrue(statuses.containsKey("invite") && statuses.containsKey("onNewRoom")); @@ -3557,7 +3557,7 @@ public void onSuccess(String info) { } }); - lock2.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock2); Assert.assertTrue(statuses.containsKey("joinRoom")); // wait the initial sync @@ -3636,7 +3636,7 @@ public void onToDeviceEvent(Event event) { }); roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(0), aliceSession, aliceRoomId), callback); - lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock); Assert.assertTrue(results.containsKey("onToDeviceEvent")); Assert.assertEquals(1, messagesCount[0]); @@ -3646,7 +3646,7 @@ public void onToDeviceEvent(Event event) { roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(0), bobSession, aliceRoomId), callback); // android does not echo the messages sent from itself messagesCount[0]++; - lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock); Assert.assertEquals(2, messagesCount[0]); lock = new CountDownLatch(1); @@ -3655,7 +3655,7 @@ public void onToDeviceEvent(Event event) { roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(1), bobSession, aliceRoomId), callback); // android does not echo the messages sent from itself messagesCount[0]++; - lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock); Assert.assertEquals(3, messagesCount[0]); lock = new CountDownLatch(1); @@ -3664,14 +3664,14 @@ public void onToDeviceEvent(Event event) { roomFromBobPOV.sendEvent(buildTextEvent(messagesFromBob.get(2), bobSession, aliceRoomId), callback); // android does not echo the messages sent from itself messagesCount[0]++; - lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock); Assert.assertEquals(4, messagesCount[0]); lock = new CountDownLatch(2); list.clear(); list.add(lock); roomFromAlicePOV.sendEvent(buildTextEvent(messagesFromAlice.get(1), aliceSession, aliceRoomId), callback); - lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock); Assert.assertEquals(5, messagesCount[0]); return pair; diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java index 00348d9fc..f29d67f37 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java @@ -18,6 +18,8 @@ import android.content.Context; import android.support.test.InstrumentationRegistry; +import junit.framework.Assert; + import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.common.TestApiCallback; @@ -58,8 +60,8 @@ public LazyLoadingTestHelper(CommonTestHelper mCommonTestHelper) { * @return initialized data */ public LazyLoadingScenarioData createScenario(boolean withLazyLoading) throws Exception { - MXSession bobSession = mTestHelper.createBobAccount(true, false); MXSession aliceSession = mTestHelper.createAliceAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(true, false); MXSession samSession = mTestHelper.createSamAccount(true, false); final String aliceId = aliceSession.getMyUserId(); @@ -75,7 +77,7 @@ public void onSuccess(String info) { super.onSuccess(info); } }); - latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(latch); final String roomId = results.get("roomId"); final Room bobRoom = bobSession.getDataHandler().getRoom(roomId); @@ -83,33 +85,38 @@ public void onSuccess(String info) { //update name and join rules latch = new CountDownLatch(1); bobRoom.updateName("LazyLoading Test Room", new TestApiCallback(latch)); - latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(latch); latch = new CountDownLatch(1); bobRoom.updateJoinRules(RoomState.JOIN_RULE_PUBLIC, new TestApiCallback(latch)); - latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(latch); // sam join latch = new CountDownLatch(1); samSession.joinRoom(roomId, new TestApiCallback(latch)); - latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(latch); //alice join latch = new CountDownLatch(1); aliceSession.joinRoom(roomId, new TestApiCallback(latch)); - latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(latch); final Room aliceRoom = aliceSession.getDataHandler().getStore().getRoom(roomId); //invite dave latch = new CountDownLatch(1); bobRoom.invite("@dave:localhost:8480", new TestApiCallback(latch)); - latch.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(latch); // Send messages final List aliceFirstMessages = mTestHelper.sendTextMessage(aliceRoom, "Alice message", 50); final List bobMessages = mTestHelper.sendTextMessage(bobRoom, "Bob message", 1); final List aliceLastMessages = mTestHelper.sendTextMessage(aliceRoom, "Alice message", 50); + + Assert.assertEquals(50, aliceFirstMessages.size()); + Assert.assertEquals(1, bobMessages.size()); + Assert.assertEquals(50, aliceLastMessages.size()); + final String bobMessageId = bobMessages.isEmpty() ? null : bobMessages.get(0).eventId; // Clear Alice session and open new one diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index c0b64c17f..f99d66b66 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -86,7 +86,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro }); final Room samRoom = data.samSession.getDataHandler().getRoom(data.roomId); mTestHelper.sendTextMessage(samRoom, "A message from Sam", 1); - lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); + mTestHelper.await(lock); if (withLazyLoading) { // Sam is now loaded @@ -147,8 +147,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } }); recursiveBackPaginate(liveTimeline, 0, 30, 120); - boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertTrue(handled); + mTestHelper.await(lock); } @Test @@ -174,8 +173,7 @@ public void onSuccess(Void info) { lock.countDown(); } }); - boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertTrue(handled); + mTestHelper.await(lock); final RoomState roomState = eventTimeline.getState(); if (withLazyLoading) { @@ -242,8 +240,7 @@ public void onSuccess(Void info) { recursiveBackPaginate(eventTimeline, 0, 30, 120); } }); - boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertTrue(handled); + mTestHelper.await(lock); } @Test @@ -308,8 +305,7 @@ public void onSuccess(Integer info) { }); } }); - boolean handled = lock.await(TestConstants.AWAIT_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS); - Assert.assertTrue(handled); + mTestHelper.await(lock); } /** From 00c1e0a00937dadea4f36d2520610952422a0029 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 11:24:29 +0200 Subject: [PATCH 106/236] Rename useless class (may has been restored by mistake during rebase --- .../org/matrix/androidsdk/TestsHelper.java | 191 ------------------ 1 file changed, 191 deletions(-) delete mode 100644 matrix-sdk/src/test/java/org/matrix/androidsdk/TestsHelper.java diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestsHelper.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/TestsHelper.java deleted file mode 100644 index 1dfcd6bfb..000000000 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/TestsHelper.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright 2016 OpenMarket Ltd - * Copyright 2018 New Vector Ltd - * - * 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 org.matrix.androidsdk; - -import android.content.Context; -import android.net.Uri; - -import org.matrix.androidsdk.data.store.IMXStore; -import org.matrix.androidsdk.data.store.MXFileStore; -import org.matrix.androidsdk.listeners.MXEventListener; -import org.matrix.androidsdk.rest.callback.ApiCallback; -import org.matrix.androidsdk.rest.client.LoginRestClient; -import org.matrix.androidsdk.rest.model.MatrixError; -import org.matrix.androidsdk.rest.model.login.Credentials; -import org.matrix.androidsdk.rest.model.login.RegistrationFlowResponse; -import org.matrix.androidsdk.rest.model.login.RegistrationParams; -import org.matrix.androidsdk.util.JsonUtils; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -public class TestsHelper { - public static final String TESTS_HOME_SERVER_URL = "http://localhost:8080"; - - private static CountDownLatch mLock; - - /** - * 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 - * @param callback the callback - * @throws Exception an exception if the account cannot be created - */ - public static void createAccountAndSync(Context context, - String userName, - String password, - boolean startSession, - ApiCallback callback) throws Exception { - RestClient.mUseMXExecutor = true; - - Uri uri = Uri.parse(TESTS_HOME_SERVER_URL); - HomeServerConnectionConfig hs = new HomeServerConnectionConfig.Builder() - .withHomeServerUri(uri) - .build(); - LoginRestClient loginRestClient = new LoginRestClient(hs); - - final Map params = new HashMap<>(); - RegistrationParams registrationParams = new RegistrationParams(); - - mLock = new CountDownLatch(1); - - // get the registration session id - loginRestClient.register(registrationParams, new ApiCallback() { - @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(1000, TimeUnit.MILLISECONDS); - - String session = (String)params.get("session"); - - if (null == session) { - callback.onUnexpectedError(null); - } - - registrationParams.username = userName; - registrationParams.password = password; - Map 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() { - @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(1000, TimeUnit.MILLISECONDS); - - Credentials credentials = (Credentials)params.get("credentials"); - - if (null == credentials) { - callback.onMatrixError(null); - return; - } - - hs.setCredentials(credentials); - - IMXStore store = new MXFileStore(hs, false, context); - - MXSession mxSession = new MXSession.Builder(hs, new MXDataHandler(store, credentials), context) - .build(); - - - if (!startSession) { - callback.onSuccess(mxSession); - return; - } - - 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(10000, TimeUnit.MILLISECONDS); - - if (params.containsKey("isInit")) { - callback.onSuccess(mxSession); - } else { - callback.onMatrixError(null); - } - } -} From 9d75584b7759df4533ec1100e350009bd2a1c1c2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 11:43:30 +0200 Subject: [PATCH 107/236] Format code --- .../org/matrix/androidsdk/rest/api/RoomsApi.java | 12 +++++++----- .../androidsdk/rest/client/RoomsRestClient.java | 6 +++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index 9bd23ea75..057ea2a77 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -284,13 +284,15 @@ Call sendStateEvent(@Path("roomId") String roomId, * Get a list of messages starting from a reference.. * * @param roomId the room id - * @param dir The direction to return messages from. - * @param from the token identifying where to start - * @param limit the maximum number of messages to retrieve + * @param from the token identifying where to start. Required. + * @param dir The direction to return messages from. Required. + * @param limit the maximum number of messages to retrieve. Optional. */ @GET("rooms/{roomId}/messages") - Call> getRoomMessagesFrom(@Path("roomId") String roomId, @Query("dir") String dir, - @Query("from") String from, @Query("limit") int limit); + Call> getRoomMessagesFrom(@Path("roomId") String roomId, + @Query("from") String from, + @Query("dir") String dir, + @Query("limit") int limit); /** * Get the initial information concerning a specific room. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index 5a22c47b0..c108dcd6f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -133,8 +133,8 @@ public void onRetry() { * The amount of message is set to {@link #DEFAULT_MESSAGES_PAGINATION_LIMIT}. * * @param roomId the room id - * @param fromToken the token identifying the message to start from - * @param direction the direction + * @param fromToken the token identifying the message to start from Required. + * @param direction the direction. Required. * @param limit the maximum number of messages to retrieve. * @param callback the callback called with the response. Messages will be returned in reverse order. */ @@ -145,7 +145,7 @@ public void getRoomMessagesFrom(final String roomId, final ApiCallback> callback) { final String description = "messagesFrom : roomId " + roomId + " fromToken " + fromToken + "with direction " + direction + " with limit " + limit; - mApi.getRoomMessagesFrom(roomId, (direction == EventTimeline.Direction.BACKWARDS) ? "b" : "f", fromToken, limit) + mApi.getRoomMessagesFrom(roomId, fromToken, (direction == EventTimeline.Direction.BACKWARDS) ? "b" : "f", limit) .enqueue(new RestAdapterCallback>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override From 86b23e3c4dbfcc4080d6bf311fddbe085a25fcbf Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 12:17:49 +0200 Subject: [PATCH 108/236] Add filter for /rooms/{roomId}/messages API and use it for LazyLoading --- .../matrix/androidsdk/data/DataRetriever.java | 67 +++++++++++++------ .../matrix/androidsdk/data/EventTimeline.java | 8 +-- .../java/org/matrix/androidsdk/data/Room.java | 17 +++-- .../matrix/androidsdk/rest/api/RoomsApi.java | 7 +- .../rest/client/RoomsRestClient.java | 17 +++-- .../rest/model/RoomEventFilter.java | 47 ------------- 6 files changed, 78 insertions(+), 85 deletions(-) delete mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomEventFilter.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java index 47589d908..282253c16 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java @@ -17,6 +17,7 @@ package org.matrix.androidsdk.data; import android.os.Looper; +import android.support.annotation.Nullable; import android.text.TextUtils; import org.matrix.androidsdk.data.store.IMXStore; @@ -26,6 +27,7 @@ import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.MatrixError; import org.matrix.androidsdk.rest.model.TokensChunkResponse; +import org.matrix.androidsdk.rest.model.filter.RoomEventFilter; import org.matrix.androidsdk.util.Log; import java.util.Collection; @@ -107,16 +109,18 @@ public void getEvent(final IMXStore store, final String roomId, final String eve /** * Trigger a back pagination for a dedicated room from Token. * - * @param store the store to use - * @param roomId the room Id - * @param token the start token. - * @param limit the maximum number of messages to retrieve - * @param callback the callback + * @param store the store to use + * @param roomId the room Id + * @param token the start token. + * @param limit the maximum number of messages to retrieve + * @param withLazyLoading true when lazy loading is enabled + * @param callback the callback */ public void backPaginate(final IMXStore store, final String roomId, final String token, final int limit, + final boolean withLazyLoading, final ApiCallback> callback) { // reach the marker end if (TextUtils.equals(token, Event.PAGINATE_BACK_TOKEN_END)) { @@ -178,7 +182,8 @@ public void run() { t.start(); } else { Log.d(LOG_TAG, "## backPaginate() : trigger a remote request"); - mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, limit, + + mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, limit, createRoomEventFilter(withLazyLoading), new SimpleApiCallback>(callback) { @Override public void onSuccess(TokensChunkResponse events) { @@ -265,18 +270,21 @@ public void onUnexpectedError(Exception e) { /** * Trigger a forward pagination for a dedicated room from Token. * - * @param store the store to use - * @param roomId the room Id - * @param token the start token. - * @param callback the callback + * @param store the store to use + * @param roomId the room Id + * @param token the start token. + * @param withLazyLoading true when lazy loading is enabled + * @param callback the callback */ private void forwardPaginate(final IMXStore store, final String roomId, final String token, + final boolean withLazyLoading, final ApiCallback> callback) { putPendingToken(mPendingForwardRequestTokenByRoomId, roomId, token); mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.FORWARDS, RoomsRestClient.DEFAULT_MESSAGES_PAGINATION_LIMIT, + createRoomEventFilter(withLazyLoading), new SimpleApiCallback>(callback) { @Override public void onSuccess(TokensChunkResponse events) { @@ -292,21 +300,23 @@ public void onSuccess(TokensChunkResponse events) { /** * Request messages than the given token. These will come from storage if available, from the server otherwise. * - * @param store the store to use - * @param roomId the room id - * @param token the token to go back from. Null to start from live. - * @param direction the pagination direction - * @param callback the onComplete callback + * @param store the store to use + * @param roomId the room id + * @param token the token to go back from. Null to start from live. + * @param direction the pagination direction + * @param withLazyLoading true when lazy loading is enabled + * @param callback the onComplete callback */ public void paginate(final IMXStore store, final String roomId, final String token, final EventTimeline.Direction direction, + final boolean withLazyLoading, final ApiCallback> callback) { if (direction == EventTimeline.Direction.BACKWARDS) { - backPaginate(store, roomId, token, RoomsRestClient.DEFAULT_MESSAGES_PAGINATION_LIMIT, callback); + backPaginate(store, roomId, token, RoomsRestClient.DEFAULT_MESSAGES_PAGINATION_LIMIT, withLazyLoading, callback); } else { - forwardPaginate(store, roomId, token, callback); + forwardPaginate(store, roomId, token, withLazyLoading, callback); } } @@ -317,19 +327,20 @@ public void paginate(final IMXStore store, * @param roomId the room id * @param token the token to go back from. * @param paginationCount the number of events to retrieve. + * @param withLazyLoading true when lazy loading is enabled * @param callback the onComplete callback */ public void requestServerRoomHistory(final String roomId, final String token, final int paginationCount, + final boolean withLazyLoading, final ApiCallback> callback) { putPendingToken(mPendingRemoteRequestTokenByRoomId, roomId, token); - mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, paginationCount, + mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, paginationCount, createRoomEventFilter(withLazyLoading), new SimpleApiCallback>(callback) { @Override public void onSuccess(TokensChunkResponse info) { - if (TextUtils.equals(getPendingToken(mPendingRemoteRequestTokenByRoomId, roomId), token)) { if (info.chunk.size() != 0) { info.chunk.get(0).mToken = info.start; @@ -407,4 +418,22 @@ private void putPendingToken(final Map dict, final String roomId } } } + + /** + * Create a RoomEventFilter + * + * @param withLazyLoading true when lazy loading is enabled + * @return a RoomEventFilter or null if lazy loading if OFF + */ + @Nullable + private RoomEventFilter createRoomEventFilter(boolean withLazyLoading) { + RoomEventFilter roomEventFilter = null; + + if (withLazyLoading) { + roomEventFilter = new RoomEventFilter(); + roomEventFilter.lazyLoadMembers = true; + } + + return roomEventFilter; + } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index 807569680..3c71feb18 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -623,10 +623,10 @@ else if ((null != roomSync.state) && (null != roomSync.state.events) && (roomSyn } } - if(roomSync.roomSyncSummary != null) { + if (roomSync.roomSyncSummary != null) { RoomSummary summary = mStore.getSummary(mRoomId); - if(summary == null) { + if (summary == null) { // Should never happen here Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!! RoomSummary is null !!!!!!!!!!!!!!!!!!!!!"); } else { @@ -1239,7 +1239,7 @@ public void run() { return true; } - mDataHandler.getDataRetriever().backPaginate(mStore, mRoomId, getBackState().getToken(), eventCount, + mDataHandler.getDataRetriever().backPaginate(mStore, mRoomId, getBackState().getToken(), eventCount, mDataHandler.isLazyLoadingEnabled(), new SimpleApiCallback>(callback) { @Override public void onSuccess(TokensChunkResponse response) { @@ -1330,7 +1330,7 @@ public boolean forwardPaginate(final ApiCallback callback) { mIsForwardPaginating = true; - mDataHandler.getDataRetriever().paginate(mStore, mRoomId, mForwardsPaginationToken, Direction.FORWARDS, + mDataHandler.getDataRetriever().paginate(mStore, mRoomId, mForwardsPaginationToken, Direction.FORWARDS, mDataHandler.isLazyLoadingEnabled(), new SimpleApiCallback>(callback) { @Override public void onSuccess(TokensChunkResponse response) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 4efaae7f1..8db862862 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -388,14 +388,17 @@ public void storeOutgoingEvent(Event event) { * @param paginationCount the number of events to retrieve. * @param callback the onComplete callback */ - public void requestServerRoomHistory(final String token, final int paginationCount, final ApiCallback> callback) { + public void requestServerRoomHistory(final String token, + final int paginationCount, + final ApiCallback> callback) { mDataHandler.getDataRetriever() - .requestServerRoomHistory(getRoomId(), token, paginationCount, new SimpleApiCallback>(callback) { - @Override - public void onSuccess(TokensChunkResponse info) { - callback.onSuccess(info); - } - }); + .requestServerRoomHistory(getRoomId(), token, paginationCount, mDataHandler.isLazyLoadingEnabled(), + new SimpleApiCallback>(callback) { + @Override + public void onSuccess(TokensChunkResponse info) { + callback.onSuccess(info); + } + }); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index 057ea2a77..afb155dd9 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -17,6 +17,8 @@ */ package org.matrix.androidsdk.rest.api; +import android.support.annotation.Nullable; + import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -34,6 +36,7 @@ import org.matrix.androidsdk.rest.model.TokensChunkResponse; import org.matrix.androidsdk.rest.model.Typing; import org.matrix.androidsdk.rest.model.User; +import org.matrix.androidsdk.rest.model.filter.RoomEventFilter; import org.matrix.androidsdk.rest.model.message.Message; import org.matrix.androidsdk.rest.model.sync.RoomResponse; @@ -287,12 +290,14 @@ Call sendStateEvent(@Path("roomId") String roomId, * @param from the token identifying where to start. Required. * @param dir The direction to return messages from. Required. * @param limit the maximum number of messages to retrieve. Optional. + * @param filter A RoomEventFilter to filter returned events with. Optional. */ @GET("rooms/{roomId}/messages") Call> getRoomMessagesFrom(@Path("roomId") String roomId, @Query("from") String from, @Query("dir") String dir, - @Query("limit") int limit); + @Query("limit") int limit, + @Nullable @Query("filter") RoomEventFilter filter); /** * Get the initial information concerning a specific room. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index c108dcd6f..29cc6e33a 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -46,6 +46,7 @@ import org.matrix.androidsdk.rest.model.TokensChunkResponse; import org.matrix.androidsdk.rest.model.Typing; import org.matrix.androidsdk.rest.model.User; +import org.matrix.androidsdk.rest.model.filter.RoomEventFilter; import org.matrix.androidsdk.rest.model.message.Message; import org.matrix.androidsdk.rest.model.sync.RoomResponse; @@ -132,25 +133,27 @@ public void onRetry() { * Get a limited amount of messages, for the given room starting from the given token. * The amount of message is set to {@link #DEFAULT_MESSAGES_PAGINATION_LIMIT}. * - * @param roomId the room id - * @param fromToken the token identifying the message to start from Required. - * @param direction the direction. Required. - * @param limit the maximum number of messages to retrieve. - * @param callback the callback called with the response. Messages will be returned in reverse order. + * @param roomId the room id + * @param fromToken the token identifying the message to start from Required. + * @param direction the direction. Required. + * @param limit the maximum number of messages to retrieve. + * @param roomEventFilter A RoomEventFilter to filter returned events with. Optional. + * @param callback the callback called with the response. Messages will be returned in reverse order. */ public void getRoomMessagesFrom(final String roomId, final String fromToken, final EventTimeline.Direction direction, final int limit, + @Nullable final RoomEventFilter roomEventFilter, final ApiCallback> callback) { final String description = "messagesFrom : roomId " + roomId + " fromToken " + fromToken + "with direction " + direction + " with limit " + limit; - mApi.getRoomMessagesFrom(roomId, fromToken, (direction == EventTimeline.Direction.BACKWARDS) ? "b" : "f", limit) + mApi.getRoomMessagesFrom(roomId, fromToken, (direction == EventTimeline.Direction.BACKWARDS) ? "b" : "f", limit, roomEventFilter) .enqueue(new RestAdapterCallback>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { - getRoomMessagesFrom(roomId, fromToken, direction, limit, callback); + getRoomMessagesFrom(roomId, fromToken, direction, limit, roomEventFilter, callback); } })); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomEventFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomEventFilter.java deleted file mode 100644 index 132ad280f..000000000 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomEventFilter.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2018 New Vector Ltd - * - * 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 org.matrix.androidsdk.rest.model; - -import com.google.gson.annotations.SerializedName; - -import java.util.List; - -public class RoomEventFilter { - @SerializedName("limit") - Integer maxNumberOfEvents; - - @SerializedName("not_senders") - List mSenderIdsToExclude; - - @SerializedName("not_types") - List mTypesToExclude; - - @SerializedName("senders") - List mSenderIds; - - @SerializedName("types") - List mTypes; - - @SerializedName("not_rooms") - List mRoomIdsToExclude; - - @SerializedName("rooms") - List mRooms; - - @SerializedName("contains_url") - String mContainsUrl; -} From 4c50a28f73d5bad4d240827f75e427ea471f39d7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 12:32:52 +0200 Subject: [PATCH 109/236] Add filter for /rooms/{roomId}/context/{eventId} API and use it for LazyLoading --- .../matrix/androidsdk/data/DataRetriever.java | 27 +-- .../matrix/androidsdk/data/EventTimeline.java | 186 +++++++++--------- .../matrix/androidsdk/rest/api/RoomsApi.java | 6 +- .../rest/client/RoomsRestClient.java | 22 ++- .../matrix/androidsdk/util/FilterUtil.java | 19 ++ 5 files changed, 137 insertions(+), 123 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java index 282253c16..6123e5f48 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java @@ -17,7 +17,6 @@ package org.matrix.androidsdk.data; import android.os.Looper; -import android.support.annotation.Nullable; import android.text.TextUtils; import org.matrix.androidsdk.data.store.IMXStore; @@ -27,7 +26,7 @@ import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.MatrixError; import org.matrix.androidsdk.rest.model.TokensChunkResponse; -import org.matrix.androidsdk.rest.model.filter.RoomEventFilter; +import org.matrix.androidsdk.util.FilterUtil; import org.matrix.androidsdk.util.Log; import java.util.Collection; @@ -183,7 +182,7 @@ public void run() { } else { Log.d(LOG_TAG, "## backPaginate() : trigger a remote request"); - mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, limit, createRoomEventFilter(withLazyLoading), + mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, limit, FilterUtil.createRoomEventFilter(withLazyLoading), new SimpleApiCallback>(callback) { @Override public void onSuccess(TokensChunkResponse events) { @@ -284,7 +283,7 @@ private void forwardPaginate(final IMXStore store, putPendingToken(mPendingForwardRequestTokenByRoomId, roomId, token); mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.FORWARDS, RoomsRestClient.DEFAULT_MESSAGES_PAGINATION_LIMIT, - createRoomEventFilter(withLazyLoading), + FilterUtil.createRoomEventFilter(withLazyLoading), new SimpleApiCallback>(callback) { @Override public void onSuccess(TokensChunkResponse events) { @@ -337,7 +336,7 @@ public void requestServerRoomHistory(final String roomId, final ApiCallback> callback) { putPendingToken(mPendingRemoteRequestTokenByRoomId, roomId, token); - mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, paginationCount, createRoomEventFilter(withLazyLoading), + mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, paginationCount, FilterUtil.createRoomEventFilter(withLazyLoading), new SimpleApiCallback>(callback) { @Override public void onSuccess(TokensChunkResponse info) { @@ -418,22 +417,4 @@ private void putPendingToken(final Map dict, final String roomId } } } - - /** - * Create a RoomEventFilter - * - * @param withLazyLoading true when lazy loading is enabled - * @return a RoomEventFilter or null if lazy loading if OFF - */ - @Nullable - private RoomEventFilter createRoomEventFilter(boolean withLazyLoading) { - RoomEventFilter roomEventFilter = null; - - if (withLazyLoading) { - roomEventFilter = new RoomEventFilter(); - roomEventFilter.lazyLoadMembers = true; - } - - return roomEventFilter; - } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index 3c71feb18..84eb747a6 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -42,6 +42,7 @@ import org.matrix.androidsdk.rest.model.sync.RoomSync; import org.matrix.androidsdk.util.BingRulesManager; import org.matrix.androidsdk.util.EventDisplay; +import org.matrix.androidsdk.util.FilterUtil; import org.matrix.androidsdk.util.JsonUtils; import org.matrix.androidsdk.util.Log; @@ -1417,100 +1418,103 @@ public void resetPaginationAroundInitialEvent(final int limit, final ApiCallback mForwardsPaginationToken = null; mHasReachedHomeServerForwardsPaginationEnd = false; - mDataHandler.getDataRetriever().getRoomsRestClient().getContextOfEvent(mRoomId, mInitialEventId, limit, new SimpleApiCallback(callback) { - @Override - public void onSuccess(final EventContext eventContext) { - - AsyncTask task = new AsyncTask() { - @Override - protected Void doInBackground(Void... params) { - // the state is the one after the latest event of the chunk i.e. the last message of eventContext.eventsAfter - for (Event event : eventContext.state) { - processStateEvent(event, Direction.FORWARDS); - } - - // init the room states - initHistory(); - - // build the events list - List events = new ArrayList<>(); - - Collections.reverse(eventContext.eventsAfter); - events.addAll(eventContext.eventsAfter); - events.add(eventContext.event); - events.addAll(eventContext.eventsBefore); - - // add events after - addPaginationEvents(events, Direction.BACKWARDS); - - return null; - } - - @Override - protected void onPostExecute(Void args) { - // create dummy forward events list - // to center the selected event id - // else if might be out of screen - List nextSnapshotEvents = new ArrayList<>(mSnapshotEvents.subList(0, (mSnapshotEvents.size() + 1) / 2)); - - // put in the right order - Collections.reverse(nextSnapshotEvents); - - // send them one by one - for (SnapshotEvent snapshotEvent : nextSnapshotEvents) { - mSnapshotEvents.remove(snapshotEvent); - onEvent(snapshotEvent.mEvent, Direction.FORWARDS, snapshotEvent.mState); - } - - // init the tokens - mBackState.setToken(eventContext.start); - mForwardsPaginationToken = eventContext.end; - - // send the back events to complete pagination - manageBackEvents(MAX_EVENT_COUNT_PER_PAGINATION, new ApiCallback() { - @Override - public void onSuccess(Integer info) { - Log.d(LOG_TAG, "addPaginationEvents succeeds"); - } - + mDataHandler.getDataRetriever() + .getRoomsRestClient() + .getContextOfEvent(mRoomId, mInitialEventId, limit, FilterUtil.createRoomEventFilter(mDataHandler.isLazyLoadingEnabled()), + new SimpleApiCallback(callback) { @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage(), e); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage(), e); + public void onSuccess(final EventContext eventContext) { + + AsyncTask task = new AsyncTask() { + @Override + protected Void doInBackground(Void... params) { + // the state is the one after the latest event of the chunk i.e. the last message of eventContext.eventsAfter + for (Event event : eventContext.state) { + processStateEvent(event, Direction.FORWARDS); + } + + // init the room states + initHistory(); + + // build the events list + List events = new ArrayList<>(); + + Collections.reverse(eventContext.eventsAfter); + events.addAll(eventContext.eventsAfter); + events.add(eventContext.event); + events.addAll(eventContext.eventsBefore); + + // add events after + addPaginationEvents(events, Direction.BACKWARDS); + + return null; + } + + @Override + protected void onPostExecute(Void args) { + // create dummy forward events list + // to center the selected event id + // else if might be out of screen + List nextSnapshotEvents = new ArrayList<>(mSnapshotEvents.subList(0, (mSnapshotEvents.size() + 1) / 2)); + + // put in the right order + Collections.reverse(nextSnapshotEvents); + + // send them one by one + for (SnapshotEvent snapshotEvent : nextSnapshotEvents) { + mSnapshotEvents.remove(snapshotEvent); + onEvent(snapshotEvent.mEvent, Direction.FORWARDS, snapshotEvent.mState); + } + + // init the tokens + mBackState.setToken(eventContext.start); + mForwardsPaginationToken = eventContext.end; + + // send the back events to complete pagination + manageBackEvents(MAX_EVENT_COUNT_PER_PAGINATION, new ApiCallback() { + @Override + public void onSuccess(Integer info) { + Log.d(LOG_TAG, "addPaginationEvents succeeds"); + } + + @Override + public void onNetworkError(Exception e) { + Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage(), e); + } + + @Override + public void onMatrixError(MatrixError e) { + Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage()); + } + + @Override + public void onUnexpectedError(Exception e) { + Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage(), e); + } + }); + + // everything is done + callback.onSuccess(null); + } + }; + + try { + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } catch (final Exception e) { + Log.e(LOG_TAG, "## resetPaginationAroundInitialEvent() failed " + e.getMessage(), e); + task.cancel(true); + + (new android.os.Handler(Looper.getMainLooper())).post(new Runnable() { + @Override + public void run() { + if (callback != null) { + callback.onUnexpectedError(e); + } + } + }); + } } }); - - // everything is done - callback.onSuccess(null); - } - }; - - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (final Exception e) { - Log.e(LOG_TAG, "## resetPaginationAroundInitialEvent() failed " + e.getMessage(), e); - task.cancel(true); - - (new android.os.Handler(Looper.getMainLooper())).post(new Runnable() { - @Override - public void run() { - if (callback != null) { - callback.onUnexpectedError(e); - } - } - }); - } - } - }); } //============================================================================================================== diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index afb155dd9..d5e655b48 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -314,9 +314,13 @@ Call> getRoomMessagesFrom(@Path("roomId") String room * @param roomId the room id * @param eventId the event Id * @param limit the maximum number of messages to retrieve + * @param filter A RoomEventFilter to filter returned events with. Optional. */ @GET("rooms/{roomId}/context/{eventId}") - Call getContextOfEvent(@Path("roomId") String roomId, @Path("eventId") String eventId, @Query("limit") int limit); + Call getContextOfEvent(@Path("roomId") String roomId, + @Path("eventId") String eventId, + @Query("limit") int limit, + @Nullable @Query("filter") RoomEventFilter filter); /** * Retrieve an event from its room id / events id diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index 29cc6e33a..e8354b6a7 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -419,7 +419,8 @@ public void onSuccess(Event event) { @Override public void onMatrixError(MatrixError e) { if (TextUtils.equals(e.errcode, MatrixError.UNRECOGNIZED)) { - getContextOfEvent(roomId, eventId, 1, new SimpleApiCallback(callback) { + // TODO LazyLoading Manu do we should enable lazy loading here? + getContextOfEvent(roomId, eventId, 1, null, new SimpleApiCallback(callback) { @Override public void onSuccess(EventContext eventContext) { callback.onSuccess(eventContext.event); @@ -478,19 +479,24 @@ public void onRetry() { /** * Get the context surrounding an event. * - * @param roomId the room id - * @param eventId the event Id - * @param limit the maximum number of messages to retrieve - * @param callback the asynchronous callback called with the response + * @param roomId the room id + * @param eventId the event Id + * @param limit the maximum number of messages to retrieve + * @param roomEventFilter A RoomEventFilter to filter returned events with. Optional. + * @param callback the asynchronous callback called with the response */ - public void getContextOfEvent(final String roomId, final String eventId, final int limit, final ApiCallback callback) { + public void getContextOfEvent(final String roomId, + final String eventId, + final int limit, + @Nullable final RoomEventFilter roomEventFilter, + final ApiCallback callback) { final String description = "getContextOfEvent : roomId " + roomId + " eventId " + eventId + " limit " + limit; - mApi.getContextOfEvent(roomId, eventId, limit) + mApi.getContextOfEvent(roomId, eventId, limit, roomEventFilter) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { - getContextOfEvent(roomId, eventId, limit, callback); + getContextOfEvent(roomId, eventId, limit, roomEventFilter, callback); } })); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/FilterUtil.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/FilterUtil.java index bfde52c22..6d2be047f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/FilterUtil.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/FilterUtil.java @@ -17,6 +17,7 @@ package org.matrix.androidsdk.util; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import org.matrix.androidsdk.rest.model.filter.Filter; import org.matrix.androidsdk.rest.model.filter.FilterBody; @@ -130,4 +131,22 @@ public static void enableLazyLoading(FilterBody filterBody, boolean useLazyLoadi } } } + + /** + * Create a RoomEventFilter + * + * @param withLazyLoading true when lazy loading is enabled + * @return a RoomEventFilter or null if lazy loading if OFF + */ + @Nullable + public static RoomEventFilter createRoomEventFilter(boolean withLazyLoading) { + RoomEventFilter roomEventFilter = null; + + if (withLazyLoading) { + roomEventFilter = new RoomEventFilter(); + roomEventFilter.lazyLoadMembers = true; + } + + return roomEventFilter; + } } From 784365bdde67e5fcf59c03525dbad9658e685b97 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 12:34:35 +0200 Subject: [PATCH 110/236] Rename tests --- .../androidsdk/lazyloading/RoomStateTest.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index f99d66b66..a17469826 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -21,7 +21,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.matrix.androidsdk.common.CommonTestHelper; -import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.data.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; @@ -29,7 +28,6 @@ import org.matrix.androidsdk.rest.model.Event; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) public class RoomStateTest { @@ -43,7 +41,7 @@ public void RoomState_InitialSync_ShouldLoadAllMembers() throws Exception { } @Test - public void RoomState_InitialSync_ShouldLoadAllMembers_LL() throws Exception { + public void RoomState_InitialSync_LazyLoading() throws Exception { RoomState_InitialSync(true); } @@ -68,7 +66,7 @@ public void RoomState_IncomingMessage_ShouldLoadAllMembers() throws Exception { } @Test - public void RoomState_IncomingMessage_ShouldLoadAllMembers_LL() throws Exception { + public void RoomState_IncomingMessage_LazyLoading() throws Exception { RoomState_IncomingMessage(true); } @@ -105,7 +103,7 @@ public void RoomState_BackPaginate_ShouldLoadAllMembers() throws Exception { } @Test - public void RoomState_BackPaginate_ShouldLoadAllMembers_LL() throws Exception { + public void RoomState_BackPaginate_LazyLoading() throws Exception { RoomState_BackPaginate(true); } @@ -156,7 +154,7 @@ public void RoomState_Permalink_ShouldLoadAllMembers() throws Exception { } @Test - public void RoomState_Permalink_ShouldLoadAllMembers_LL() throws Exception { + public void RoomState_Permalink_LazyLoading() throws Exception { RoomState_Permalink(true); } @@ -192,7 +190,7 @@ public void RoomState_PermalinkWithBackPagination_ShouldLoadAllMembers() throws } @Test - public void RoomState_PermalinkWithBackPagination_ShouldLoadAllMembers_LL() throws Exception { + public void RoomState_PermalinkWithBackPagination_LazyLoading() throws Exception { RoomState_PermalinkWithBackPagination(true); } @@ -249,7 +247,7 @@ public void RoomState_PermalinkWithForwardPagination_ShouldLoadAllMembers() thro } @Test - public void RoomState_PermalinkWithForwardPagination_ShouldLoadAllMembers_LL() throws Exception { + public void RoomState_PermalinkWithForwardPagination_LazyLoading() throws Exception { RoomState_PermalinkWithForwardPagination(true); } From a9f980f246d09c08d5a6ca70d0a1a9c4df0db381 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 14:48:04 +0200 Subject: [PATCH 111/236] Fix issue with serialization --- .../org/matrix/androidsdk/rest/api/RoomsApi.java | 8 ++++---- .../androidsdk/rest/client/FilterRestClient.java | 2 -- .../androidsdk/rest/client/RoomsRestClient.java | 13 +++++++++++-- .../rest/model/filter/RoomEventFilter.java | 5 +++++ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index d5e655b48..53f5b4217 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -290,14 +290,14 @@ Call sendStateEvent(@Path("roomId") String roomId, * @param from the token identifying where to start. Required. * @param dir The direction to return messages from. Required. * @param limit the maximum number of messages to retrieve. Optional. - * @param filter A RoomEventFilter to filter returned events with. Optional. + * @param filter A JSON RoomEventFilter to filter returned events with. Optional. */ @GET("rooms/{roomId}/messages") Call> getRoomMessagesFrom(@Path("roomId") String roomId, @Query("from") String from, @Query("dir") String dir, @Query("limit") int limit, - @Nullable @Query("filter") RoomEventFilter filter); + @Nullable @Query("filter") String filter); /** * Get the initial information concerning a specific room. @@ -314,13 +314,13 @@ Call> getRoomMessagesFrom(@Path("roomId") String room * @param roomId the room id * @param eventId the event Id * @param limit the maximum number of messages to retrieve - * @param filter A RoomEventFilter to filter returned events with. Optional. + * @param filter A JSON RoomEventFilter to filter returned events with. Optional. */ @GET("rooms/{roomId}/context/{eventId}") Call getContextOfEvent(@Path("roomId") String roomId, @Path("eventId") String eventId, @Query("limit") int limit, - @Nullable @Query("filter") RoomEventFilter filter); + @Nullable @Query("filter") String filter); /** * Retrieve an event from its room id / events id diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java index 70ef46d88..bca2fcdd9 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/FilterRestClient.java @@ -16,8 +16,6 @@ */ package org.matrix.androidsdk.rest.client; -import com.google.gson.Gson; - import org.matrix.androidsdk.HomeServerConnectionConfig; import org.matrix.androidsdk.RestClient; import org.matrix.androidsdk.rest.api.FilterApi; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index e8354b6a7..da92cea9d 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -148,7 +148,7 @@ public void getRoomMessagesFrom(final String roomId, final ApiCallback> callback) { final String description = "messagesFrom : roomId " + roomId + " fromToken " + fromToken + "with direction " + direction + " with limit " + limit; - mApi.getRoomMessagesFrom(roomId, fromToken, (direction == EventTimeline.Direction.BACKWARDS) ? "b" : "f", limit, roomEventFilter) + mApi.getRoomMessagesFrom(roomId, fromToken, (direction == EventTimeline.Direction.BACKWARDS) ? "b" : "f", limit, toJson(roomEventFilter)) .enqueue(new RestAdapterCallback>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override @@ -492,7 +492,7 @@ public void getContextOfEvent(final String roomId, final ApiCallback callback) { final String description = "getContextOfEvent : roomId " + roomId + " eventId " + eventId + " limit " + limit; - mApi.getContextOfEvent(roomId, eventId, limit, roomEventFilter) + mApi.getContextOfEvent(roomId, eventId, limit, toJson(roomEventFilter)) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { @@ -1035,4 +1035,13 @@ public void onRetry() { } })); } + + @Nullable + private String toJson(@Nullable RoomEventFilter roomEventFilter) { + if (roomEventFilter == null) { + return null; + } + + return roomEventFilter.toJSONString(); + } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java index 60969d617..aa7b178c5 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java @@ -16,6 +16,7 @@ */ package org.matrix.androidsdk.rest.model.filter; +import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; import java.util.List; @@ -60,4 +61,8 @@ public boolean hasData() { || containsUrl != null || lazyLoadMembers != null; } + + public String toJSONString() { + return new Gson().toJson(this); + } } From 72386657fecea2ce322b41a105556db696917675 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 15:08:45 +0200 Subject: [PATCH 112/236] Improve test --- .../androidsdk/common/CommonTestHelper.java | 2 +- .../androidsdk/lazyloading/RoomStateTest.java | 152 ++++++++++-------- 2 files changed, 89 insertions(+), 65 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index ce2791689..61616053a 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -150,7 +150,7 @@ public void onEventSent(Event event, String prevEventId) { }; room.addEventListener(onEventSentListener); for (int i = 0; i < nbOfMessages; i++) { - room.sendTextMessage(message, null, Message.FORMAT_MATRIX_HTML, new RoomMediaMessage.EventCreationListener() { + room.sendTextMessage(message + " #" + (i + 1), null, Message.FORMAT_MATRIX_HTML, new RoomMediaMessage.EventCreationListener() { @Override public void onEventCreated(RoomMediaMessage roomMediaMessage) { final Event sentEvent = roomMediaMessage.getEvent(); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index a17469826..0e00da8ce 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -16,6 +16,7 @@ package org.matrix.androidsdk.lazyloading; import android.support.test.runner.AndroidJUnit4; +import android.text.TextUtils; import org.junit.Assert; import org.junit.Test; @@ -26,6 +27,8 @@ import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.util.JsonUtils; +import org.matrix.androidsdk.util.Log; import java.util.concurrent.CountDownLatch; @@ -118,29 +121,36 @@ private void RoomState_BackPaginate(final boolean withLazyLoading) throws Except @Override public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { - messageCount++; - if (messageCount == 50) { - Assert.assertNotNull(liveTimeline.getState().getMember(data.aliceSession.getMyUserId())); - - // With LazyLoading, Bob and Sam are not known by Alice yet - Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.bobSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.samSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, roomState.getMember(data.bobSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); - } else if (messageCount == 51) { - // Bob is known now - Assert.assertNotNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); - - // With LazyLoading, Sam is not known by Alice yet - Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.samSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); - } else if (messageCount >= 110) { - // All users are known now - Assert.assertNotNull(liveTimeline.getState().getMember(data.aliceSession.getMyUserId())); - Assert.assertNotNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); - Assert.assertNotNull(liveTimeline.getState().getMember(data.samSession.getMyUserId())); - - lock.countDown(); + if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { + messageCount++; + + Log.d("TAG", "Receiving message #" + messageCount + ": " + JsonUtils.toMessage(event.getContent()).body); + + if (messageCount <= 50) { + Assert.assertNotNull(liveTimeline.getState().getMember(data.aliceSession.getMyUserId())); + + // With LazyLoading, Bob and Sam are not known by Alice yet + Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.bobSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.bobSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); + } else if (messageCount <= 100) { + // Bob is known now + Assert.assertNotNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); + + // With LazyLoading, Sam is not known by Alice yet + Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); + } else if (messageCount == 101) { + // All users are known now + Assert.assertNotNull(liveTimeline.getState().getMember(data.aliceSession.getMyUserId())); + Assert.assertNotNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); + Assert.assertNotNull(liveTimeline.getState().getMember(data.samSession.getMyUserId())); + + lock.countDown(); + } + } else { + Log.d("TAG", "Receiving other event: " + event.getType()); } } }); @@ -206,29 +216,36 @@ private void RoomState_PermalinkWithBackPagination(final boolean withLazyLoading @Override public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { - messageCount++; - if (messageCount == 50) { - Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); - - // With LazyLoading, Bob and Sam are not known by Alice yet - Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.bobSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, roomState.getMember(data.bobSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); - } else if (messageCount == 51) { - // Bob is known now - Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); - - // With LazyLoading, Sam is not known by Alice yet - Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); - } else if (messageCount >= 110) { - // All users are known now - Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); - Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); - Assert.assertNotNull(eventTimeline.getState().getMember(data.samSession.getMyUserId())); - - lock.countDown(); + if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { + messageCount++; + + Log.d("TAG", "Receiving message #" + messageCount + ": " + JsonUtils.toMessage(event.getContent()).body); + + if (messageCount <= 50) { + Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); + + // With LazyLoading, Bob and Sam are not known by Alice yet + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.bobSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.bobSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); + } else if (messageCount <= 100) { + // Bob is known now + Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); + + // With LazyLoading, Sam is not known by Alice yet + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); + } else if (messageCount == 101) { + // All users are known now + Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); + Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); + Assert.assertNotNull(eventTimeline.getState().getMember(data.samSession.getMyUserId())); + + lock.countDown(); + } + } else { + Log.d("TAG", "Receiving other event: " + event.getType()); } } }); @@ -266,29 +283,36 @@ private void RoomState_PermalinkWithForwardPagination(final boolean withLazyLoad @Override public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { - messageCount++; - if (messageCount == 1) { - // We received the Event from bob - Assert.assertEquals(event.sender, data.bobSession.getMyUserId()); + if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { + messageCount++; + + Log.d("TAG", "Receiving message #" + messageCount + ": " + JsonUtils.toMessage(event.getContent()).body); - // Bob is known - Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); + if (messageCount == 1) { + // We received the Event from bob + Assert.assertEquals(event.sender, data.bobSession.getMyUserId()); - // With LazyLoading, Alice and Sam are not known by Alice yet - Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.aliceSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); - } else if (messageCount == 2) { - // We received the Event from Alice - Assert.assertEquals(event.sender, data.aliceSession.getMyUserId()); + // Bob is known + Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); - // Alice and Bob are known - Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); - Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); + // With LazyLoading, Alice and Sam are not known by Alice yet + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.aliceSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + } else if (messageCount == 2) { + // We received the Event from Alice + Assert.assertEquals(event.sender, data.aliceSession.getMyUserId()); - // With LazyLoading, Sam is not known by Alice yet - Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + // Alice and Bob are known + Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); + Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); - lock.countDown(); + // With LazyLoading, Sam is not known by Alice yet + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + + lock.countDown(); + } + } else { + Log.d("TAG", "Receiving other event: " + event.getType()); } } }); From 233d74811ecf91c1817ef9cb14b586c97d056685 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 15:36:39 +0200 Subject: [PATCH 113/236] Add annotation --- .../src/main/java/org/matrix/androidsdk/data/Room.java | 1 + .../src/main/java/org/matrix/androidsdk/data/RoomState.java | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 8db862862..540610004 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -502,6 +502,7 @@ public void onSuccess(List members) { }); } + @Nullable public RoomMember getMember(String userId) { return getState().getMember(userId); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 2f72e9afc..dbbb41d81 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -493,6 +493,7 @@ private void setMember(String userId, RoomMember member) { * @return the linked member it exists. */ // TODO Change this? Can return null if all members are not loaded yet + @Nullable public RoomMember getMember(String userId) { RoomMember member; @@ -502,7 +503,7 @@ public RoomMember getMember(String userId) { if (member == null) { // TODO LazyLoading - Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Null member !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Null member '" + userId + "' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } return member; @@ -515,6 +516,7 @@ public RoomMember getMember(String userId) { * @return the linked member it exists. */ // TODO Change this? Can return null if all members are not loaded yet + @Nullable public RoomMember getMemberByEventId(String eventId) { RoomMember member = null; @@ -529,7 +531,7 @@ public RoomMember getMemberByEventId(String eventId) { if (member == null) { // TODO LazyLoading - Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Null member !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Null member for event '" + eventId + "' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } return member; From 010f5b8c78f5a42d24935922290188f1f202e37a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 16:41:47 +0200 Subject: [PATCH 114/236] Use token from store instead of introducing a new class member --- .../src/main/java/org/matrix/androidsdk/MXDataHandler.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index f3f4570fe..7ebdbf920 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -180,9 +180,6 @@ public interface RequestNetworkErrorListener { // tell if the lazy loading is enabled private boolean mIsLazyLoadingEnabled; - // Current sync token - private String mSyncToken; - /** * Default constructor. * @@ -955,7 +952,7 @@ public void onSuccess(RoomAliasDescription info) { * @param callback the callback */ public void getMembersAsync(final String roomId, final ApiCallback> callback) { - mRoomsRestClient.getRoomMembers(roomId, mSyncToken, null, null, new SimpleApiCallback>(callback) { + mRoomsRestClient.getRoomMembers(roomId, getStore().getEventStreamToken(), null, null, new SimpleApiCallback>(callback) { @Override public void onSuccess(TokensChunkResponse info) { Room room = getRoom(roomId); @@ -1287,8 +1284,6 @@ private void handlePresenceEvent(Event presenceEvent) { * @param isCatchingUp true when there is a pending catch-up */ public void onSyncResponse(final SyncResponse syncResponse, final String fromToken, final boolean isCatchingUp) { - mSyncToken = syncResponse.nextBatch; - // perform the sync in background // to avoid UI thread lags. mSyncHandler.post(new Runnable() { From 6d2b46617655c0b0f78f537557741df064b0c905 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Sep 2018 17:31:13 +0200 Subject: [PATCH 115/236] Info of invited/joined room is not get from user own membership, but from position of the room in the sync response --- .../org/matrix/androidsdk/MXDataHandler.java | 1 - .../java/org/matrix/androidsdk/data/Room.java | 32 +++++++---- .../matrix/androidsdk/data/RoomSummary.java | 56 +++++++++++++------ 3 files changed, 60 insertions(+), 29 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 7ebdbf920..831cb18b0 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -1383,7 +1383,6 @@ private void manageResponse(final SyncResponse syncResponse, final String fromTo // 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"); if (mMetricsListener != null) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 540610004..b6f5e1651 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -348,8 +348,6 @@ public void run() { }); mOnInitialSyncCallback = null; - - } mIsSyncing = false; @@ -360,6 +358,12 @@ public void run() { } // else -> it will be done at the end of the sync mRefreshUnreadAfterSync = false; } + + RoomSummary roomSummary = getRoomSummary(); + + if (roomSummary != null) { + roomSummary.setIsJoined(); + } } /** @@ -369,6 +373,12 @@ public void run() { */ public void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync) { mLiveTimeline.handleInvitedRoomSync(invitedRoomSync); + + RoomSummary roomSummary = getRoomSummary(); + + if (roomSummary != null) { + roomSummary.setIsInvited(); + } } /** @@ -553,20 +563,22 @@ public String getVisibility() { * @return true if the user is invited to the room */ public boolean isInvited() { - return hasMembership(RoomMember.MEMBERSHIP_INVITE); + if (getRoomSummary() == null) { + return false; + } + + return getRoomSummary().isInvited(); } /** - * @param membership is the string representing one of the membership state - * @return true if the user membership is equals to the membership param + * @return true if the user is invited to the room */ - public boolean hasMembership(@NonNull final String membership) { - final RoomState state = getState(); - final RoomMember selfMember = state.getMember(mMyUserId); - if (selfMember == null) { + public boolean isJoined() { + if (getRoomSummary() == null) { return false; } - return TextUtils.equals(selfMember.membership, membership); + + return getRoomSummary().isJoined(); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index 908bb7857..e25cd1c70 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -75,10 +75,13 @@ public class RoomSummary implements java.io.Serializable { private String mInviterUserId = null; // retrieved from the roomState - private boolean mIsInvited = false; private String mInviterName = null; - private String mMatrixId = null; + private String mUserId = null; + + // Info from sync, depending on the room position in the sync + private boolean mIsInInvitedRooms = false; + private boolean mIsInJoinedRooms = false; /** * Tell if the room is a user conference user one @@ -109,7 +112,7 @@ public RoomSummary(@Nullable RoomSummary fromSummary, Event event, RoomState roomState, String userId) { - setMatrixId(userId); + mUserId = userId; if (null != roomState) { setRoomId(roomState.roomId); @@ -246,10 +249,10 @@ public static boolean isSupportedEvent(Event event) { } /** - * @return the matrix id + * @return the user id */ - public String getMatrixId() { - return mMatrixId; + public String getUserId() { + return mUserId; } /** @@ -284,23 +287,37 @@ public RoomState getLatestRoomState() { * @return true if the current user is invited */ public boolean isInvited() { - return mIsInvited || (mInviterUserId != null); + return mIsInInvitedRooms; } /** - * @return the inviter user id. + * To call when the room is in the invited section of the sync response */ - public String getInviterUserId() { - return mInviterUserId; + public void setIsInvited() { + mIsInInvitedRooms = true; + mIsInJoinedRooms = false; } /** - * Update the linked matrix id. - * - * @param matrixId the new matrix id. + * To call when the room is in the joined section of the sync response + */ + public void setIsJoined() { + mIsInInvitedRooms = false; + mIsInJoinedRooms = true; + } + + /** + * @return true if the current user is invited */ - public void setMatrixId(String matrixId) { - mMatrixId = matrixId; + public boolean isJoined() { + return mIsInJoinedRooms; + } + + /** + * @return the inviter user id. + */ + public String getInviterUserId() { + return mInviterUserId; } /** @@ -362,13 +379,16 @@ public RoomSummary setLatestReceivedEvent(Event event) { public RoomSummary setLatestRoomState(RoomState roomState) { mLatestRoomState = roomState; + // Keep this code for compatibility? + boolean isInvited = false; + // check for the invitation status if (null != mLatestRoomState) { - RoomMember member = mLatestRoomState.getMember(mMatrixId); - mIsInvited = (null != member) && RoomMember.MEMBERSHIP_INVITE.equals(member.membership); + RoomMember member = mLatestRoomState.getMember(mUserId); + isInvited = (null != member) && RoomMember.MEMBERSHIP_INVITE.equals(member.membership); } // when invited, the only received message should be the invitation one - if (mIsInvited) { + if (isInvited) { mInviterName = null; if (null != mLatestReceivedEvent) { From 8953967065f8f836612f401a10e986b34fef4686 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 5 Sep 2018 11:14:09 +0200 Subject: [PATCH 116/236] Add isMember() method, because self RoomMember may not be known after initial sync --- .../java/org/matrix/androidsdk/data/Room.java | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index b6f5e1651..169e72782 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -571,7 +571,7 @@ public boolean isInvited() { } /** - * @return true if the user is invited to the room + * @return true if the user has joined the room */ public boolean isJoined() { if (getRoomSummary() == null) { @@ -581,6 +581,13 @@ public boolean isJoined() { return getRoomSummary().isJoined(); } + /** + * @return true is the user is a member of the room (invited or joined) + */ + public boolean isMember() { + return isJoined() || isInvited(); + } + /** * @return true if the user is invited in a direct chat room */ @@ -763,16 +770,6 @@ public void onUnexpectedError(Exception e) { }); } - /** - * @return true if the user joined the room - */ - private boolean selfJoined() { - RoomMember roomMember = getMember(mMyUserId); - - // send the event only if the user has joined the room. - return ((null != roomMember) && RoomMember.MEMBERSHIP_JOIN.equals(roomMember.membership)); - } - /** * @return true if the user is not yet an active member of the room */ @@ -1638,7 +1635,7 @@ public List getTypingUsers() { */ public void sendTypingNotification(boolean isTyping, int timeout, ApiCallback callback) { // send the event only if the user has joined the room. - if (selfJoined()) { + if (isJoined()) { mDataHandler.getDataRetriever().getRoomsRestClient().sendTypingNotification(getRoomId(), mMyUserId, isTyping, timeout, callback); } } @@ -2325,7 +2322,7 @@ public void removeEventListener(IMXEventListener eventListener) { */ public void sendEvent(final Event event, final ApiCallback callback) { // wait that the room is synced before sending messages - if (!mIsReady || !selfJoined()) { + if (!mIsReady || !isJoined()) { mDataHandler.updateEventState(event, Event.SentState.WAITING_RETRY); try { callback.onNetworkError(null); From c8270e6f57f65bc41f92e102f05f7e34afe18c78 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 5 Sep 2018 17:28:26 +0200 Subject: [PATCH 117/236] Better handling of just join room, waiting for initial sync --- .../main/java/org/matrix/androidsdk/MXSession.java | 4 ++-- .../main/java/org/matrix/androidsdk/data/Room.java | 12 ++---------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index 6b0fa8e43..402f9f220 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -1319,7 +1319,7 @@ public void onSuccess(CreateRoomResponse info) { final Room createdRoom = mDataHandler.getRoom(roomId); // the creation events are not be called during the creation - if (createdRoom.isWaitingInitialSync()) { + if (!createdRoom.isJoined()) { createdRoom.setOnInitialSyncCallback(new SimpleApiCallback(callback) { @Override public void onSuccess(Void info) { @@ -1363,7 +1363,7 @@ public void onSuccess(final RoomResponse roomResponse) { Room joinedRoom = mDataHandler.getRoom(roomId); // wait until the initial sync is done - if (joinedRoom.isWaitingInitialSync()) { + if (!joinedRoom.isJoined()) { joinedRoom.setOnInitialSyncCallback(new SimpleApiCallback(callback) { @Override public void onSuccess(Void info) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 169e72782..9fc141e12 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -329,7 +329,7 @@ public void handleJoinedRoomSync(RoomSync roomSync, boolean isGlobalInitialSync) // the user joined the room // With V2 sync, the server sends the events to init the room. - if ((null != mOnInitialSyncCallback) && !isWaitingInitialSync()) { + if ((null != mOnInitialSyncCallback) && isJoined()) { Log.d(LOG_TAG, "handleJoinedRoomSync " + getRoomId() + " : the initial sync is done"); final ApiCallback fOnInitialSyncCallback = mOnInitialSyncCallback; @@ -718,7 +718,7 @@ private void join(final String roomAlias, final Map extraParams, public void onSuccess(final RoomResponse aResponse) { try { // the join request did not get the room initial history - if (isWaitingInitialSync()) { + if (!isJoined()) { Log.d(LOG_TAG, "the room " + getRoomId() + " is joined but wait after initial sync"); // wait the server sends the events chunk before calling the callback @@ -770,14 +770,6 @@ public void onUnexpectedError(Exception e) { }); } - /** - * @return true if the user is not yet an active member of the room - */ - public boolean isWaitingInitialSync() { - RoomMember roomMember = getMember(mMyUserId); - return ((null == roomMember) || RoomMember.MEMBERSHIP_INVITE.equals(roomMember.membership)); - } - //================================================================================ // Room info (liveState) update //================================================================================ From fd97508142ae032df8eb67d5b4bc36f3c57b6381 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 5 Sep 2018 17:55:14 +0200 Subject: [PATCH 118/236] DisplayName condition with LazyLoading: fallback to default displayName --- .../androidsdk/util/BingRulesManager.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/BingRulesManager.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/BingRulesManager.java index 4f7fd415d..1f5216368 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/BingRulesManager.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/BingRulesManager.java @@ -1,13 +1,13 @@ -/* +/* * Copyright 2014 OpenMarket Ltd * Copyright 2018 New Vector Ltd * * 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. @@ -433,7 +433,7 @@ private BingRule fulfilledBingRule(Event event, boolean highlightRuleOnly) { /** * Check if an event matches a conditions set * - * @param event the evnt to test + * @param event the event to test * @param conditions the conditions set * @return true if the event matches all the conditions set. */ @@ -446,18 +446,27 @@ private boolean eventMatchesConditions(Event event, List conditions) return false; } } else if (condition instanceof ContainsDisplayNameCondition) { + String myDisplayName = null; + if (event.roomId != null) { Room room = mDataHandler.getRoom(event.roomId, false); // sanity checks - if ((null != room) && (null != room.getMember(mMyUserId))) { + if (room != null && room.getMember(mMyUserId) != null) { // Best way to get your display name for now - String myDisplayName = room.getMember(mMyUserId).displayname; - if (!((ContainsDisplayNameCondition) condition).isSatisfied(event, myDisplayName)) { - return false; - } + myDisplayName = room.getMember(mMyUserId).displayname; } } + + if (TextUtils.isEmpty(myDisplayName)) { + // RoomMember is maybe not known due to lazy loading + // Get displayName from the session + myDisplayName = mSession.getMyUser().displayname; + } + + if (!((ContainsDisplayNameCondition) condition).isSatisfied(event, myDisplayName)) { + return false; + } } else if (condition instanceof RoomMemberCountCondition) { if (event.roomId != null) { Room room = mDataHandler.getRoom(event.roomId, false); From fb7298f64c674199798bd5f028c717cf2a09f6b3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 6 Sep 2018 11:29:44 +0200 Subject: [PATCH 119/236] Simplify the RoomsApi interface. Avoid creating big RoomState object for a body with just 1 parameter --- .../matrix/androidsdk/rest/api/RoomsApi.java | 70 +------------------ .../rest/client/RoomsRestClient.java | 50 +++++++------ 2 files changed, 27 insertions(+), 93 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index 53f5b4217..e1a217098 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -36,7 +36,6 @@ import org.matrix.androidsdk.rest.model.TokensChunkResponse; import org.matrix.androidsdk.rest.model.Typing; import org.matrix.androidsdk.rest.model.User; -import org.matrix.androidsdk.rest.model.filter.RoomEventFilter; import org.matrix.androidsdk.rest.model.message.Message; import org.matrix.androidsdk.rest.model.sync.RoomResponse; @@ -77,60 +76,6 @@ public interface RoomsApi { @PUT("rooms/{roomId}/send/m.room.message/{txId}") Call sendMessage(@Path("txId") String txId, @Path("roomId") String roomId, @Body Message message); - /** - * Set the room topic. - * - * @param roomId the room id - * @param state state object containing the new topic in the topic field - */ - @PUT("rooms/{roomId}/state/m.room.topic") - Call setRoomTopic(@Path("roomId") String roomId, @Body RoomState state); - - /** - * Set the room name. - * - * @param roomId the room id - * @param state state object containing the new room name in the name field - */ - @PUT("rooms/{roomId}/state/m.room.name") - Call setRoomName(@Path("roomId") String roomId, @Body RoomState state); - - /** - * Set the canonical alias name. - * - * @param roomId the room id - * @param state state object containing the new canonical alias in the name field - */ - @PUT("rooms/{roomId}/state/m.room.canonical_alias") - Call setCanonicalAlias(@Path("roomId") String roomId, @Body RoomState state); - - /** - * Set the history visibility. - * - * @param roomId the room id - * @param state state object containing the new history visibility in the name field - */ - @PUT("rooms/{roomId}/state/m.room.history_visibility") - Call setHistoryVisibility(@Path("roomId") String roomId, @Body RoomState state); - - /** - * Set the join rule for the given room. - * - * @param roomId the room id where to apply the request - * @param state state object containing the new join rule in its {@link RoomState#join_rule} field - */ - @PUT("rooms/{roomId}/state/m.room.join_rules") - Call setJoinRules(@Path("roomId") String roomId, @Body RoomState state); - - /** - * Set the guest access rule for the given room. - * - * @param roomId the room id where to apply the request - * @param state state object containing the new guest access rule in its {@link RoomState#guest_access} field - */ - @PUT("rooms/{roomId}/state/m.room.guest_access") - Call setGuestAccess(@Path("roomId") String roomId, @Body RoomState state); - /** * Update the power levels * @@ -359,15 +304,6 @@ Call getContextOfEvent(@Path("roomId") String roomId, @POST("rooms/{roomId}/report/{eventId}") Call reportEvent(@Path("roomId") String roomId, @Path("eventId") String eventId, @Body ReportContentParams param); - /** - * Set the room avatar url. - * - * @param roomId the room id - * @param params the put params. - */ - @PUT("rooms/{roomId}/state/m.room.avatar") - Call setRoomAvatarUrl(@Path("roomId") String roomId, @Body Map params); - /** * Send a read receipt. * @@ -451,11 +387,11 @@ Call updateAccountData(@Path("userId") String userId, * Set the visibility of the given room in the list directory. If the visibility is set to public, the room * name is listed among the directory list. * - * @param roomId the room id where to apply the request - * @param state state object containing the new guest access rule in its {@link RoomState#visibility} field + * @param roomId the room id where to apply the request + * @param content the put params containing the new "visibility" field */ @PUT("directory/list/room/{roomId}") - Call setRoomDirectoryVisibility(@Path("roomId") String roomId, @Body RoomState state); + Call setRoomDirectoryVisibility(@Path("roomId") String roomId, Map content); /** * Get the visibility of the given room in the list directory. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index da92cea9d..ccd26eaa5 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -302,6 +302,7 @@ public void onRetry() { public void kickFromRoom(final String roomId, final String userId, final ApiCallback callback) { final String description = "kickFromRoom : roomId " + roomId + " userId " + userId; + // TODO It does not look like this in the Matrix spec // Kicking is done by posting that the user is now in a "leave" state RoomMember member = new RoomMember(); member.membership = RoomMember.MEMBERSHIP_LEAVE; @@ -511,10 +512,10 @@ public void onRetry() { public void updateRoomName(final String roomId, final String name, final ApiCallback callback) { final String description = "updateName : roomId " + roomId + " name " + name; - RoomState roomState = new RoomState(); - roomState.name = name; + Map params = new HashMap<>(); + params.put("name", name); - mApi.setRoomName(roomId, roomState) + mApi.sendStateEvent(roomId, Event.EVENT_TYPE_STATE_ROOM_NAME, params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { @@ -533,11 +534,10 @@ public void onRetry() { public void updateCanonicalAlias(final String roomId, final String canonicalAlias, final ApiCallback callback) { final String description = "updateCanonicalAlias : roomId " + roomId + " canonicalAlias " + canonicalAlias; - // FIXME Do not use a RoomState object to do this request, create a new object (same for all other next method) - RoomState roomState = new RoomState(); - roomState.alias = canonicalAlias; + Map params = new HashMap<>(); + params.put("alias", canonicalAlias); - mApi.setCanonicalAlias(roomId, roomState) + mApi.sendStateEvent(roomId, Event.EVENT_TYPE_STATE_CANONICAL_ALIAS, params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { @@ -556,10 +556,10 @@ public void onRetry() { public void updateHistoryVisibility(final String roomId, final String aVisibility, final ApiCallback callback) { final String description = "updateHistoryVisibility : roomId " + roomId + " visibility " + aVisibility; - RoomState roomState = new RoomState(); - roomState.history_visibility = aVisibility; + Map params = new HashMap<>(); + params.put("history_visibility", aVisibility); - mApi.setHistoryVisibility(roomId, roomState) + mApi.sendStateEvent(roomId, Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY, params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { @@ -578,10 +578,10 @@ public void onRetry() { public void updateDirectoryVisibility(final String aRoomId, final String aDirectoryVisibility, final ApiCallback callback) { final String description = "updateRoomDirectoryVisibility : roomId=" + aRoomId + " visibility=" + aDirectoryVisibility; - RoomState roomState = new RoomState(); - roomState.visibility = aDirectoryVisibility; + Map params = new HashMap<>(); + params.put("visibility", aDirectoryVisibility); - mApi.setRoomDirectoryVisibility(aRoomId, roomState) + mApi.setRoomDirectoryVisibility(aRoomId, params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { @@ -638,10 +638,10 @@ public void onRetry() { public void updateTopic(final String roomId, final String topic, final ApiCallback callback) { final String description = "updateTopic : roomId " + roomId + " topic " + topic; - RoomState roomState = new RoomState(); - roomState.topic = topic; + Map params = new HashMap<>(); + params.put("topic", topic); - mApi.setRoomTopic(roomId, roomState) + mApi.sendStateEvent(roomId, Event.EVENT_TYPE_STATE_ROOM_TOPIC, params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { @@ -822,10 +822,10 @@ public void sendTypingNotification(String roomId, String userId, boolean isTypin public void updateAvatarUrl(final String roomId, final String avatarUrl, final ApiCallback callback) { final String description = "updateAvatarUrl : roomId " + roomId + " avatarUrl " + avatarUrl; - Map params = new HashMap<>(); + Map params = new HashMap<>(); params.put("url", avatarUrl); - mApi.setRoomAvatarUrl(roomId, params) + mApi.sendStateEvent(roomId, Event.EVENT_TYPE_STATE_ROOM_AVATAR, params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { @@ -999,11 +999,10 @@ public void onRetry() { public void updateJoinRules(final String aRoomId, final String aJoinRule, final ApiCallback callback) { final String description = "updateJoinRules : roomId=" + aRoomId + " rule=" + aJoinRule; - // build RoomState as input parameter - RoomState roomStateParam = new RoomState(); - roomStateParam.join_rule = aJoinRule; + Map params = new HashMap<>(); + params.put("join_rule", aJoinRule); - mApi.setJoinRules(aRoomId, roomStateParam) + mApi.sendStateEvent(aRoomId, Event.EVENT_TYPE_STATE_ROOM_JOIN_RULES, params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { @@ -1023,11 +1022,10 @@ public void onRetry() { public void updateGuestAccess(final String aRoomId, final String aGuestAccessRule, final ApiCallback callback) { final String description = "updateGuestAccess : roomId=" + aRoomId + " rule=" + aGuestAccessRule; - // build RoomState as input parameter - RoomState roomStateParam = new RoomState(); - roomStateParam.guest_access = aGuestAccessRule; + Map params = new HashMap<>(); + params.put("guest_access", aGuestAccessRule); - mApi.setGuestAccess(aRoomId, roomStateParam) + mApi.sendStateEvent(aRoomId, Event.EVENT_TYPE_STATE_ROOM_GUEST_ACCESS, params) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { From 0495f1dbbc201c952f9dcc840b264fb4ccffb1de Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 6 Sep 2018 11:47:31 +0200 Subject: [PATCH 120/236] Simplify code --- .../java/org/matrix/androidsdk/data/Room.java | 24 ++----------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 9fc141e12..a5a0f4ee0 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -778,13 +778,14 @@ public void onUnexpectedError(Exception e) { * This class dispatches the error to the dedicated callbacks. * If the operation succeeds, the room state is saved because calling the callback. */ - private class RoomInfoUpdateCallback implements ApiCallback { + private class RoomInfoUpdateCallback extends SimpleApiCallback { private final ApiCallback mCallback; /** * Constructor */ public RoomInfoUpdateCallback(ApiCallback callback) { + super(callback); mCallback = callback; } @@ -796,27 +797,6 @@ public void onSuccess(T info) { mCallback.onSuccess(info); } } - - @Override - public void onNetworkError(Exception e) { - if (null != mCallback) { - mCallback.onNetworkError(e); - } - } - - @Override - public void onMatrixError(final MatrixError e) { - if (null != mCallback) { - mCallback.onMatrixError(e); - } - } - - @Override - public void onUnexpectedError(final Exception e) { - if (null != mCallback) { - mCallback.onUnexpectedError(e); - } - } } /** From e716960df9e79badbde7bfcffaa607688b3638d0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 6 Sep 2018 11:51:07 +0200 Subject: [PATCH 121/236] Cleanup alias data --- .../java/org/matrix/androidsdk/data/Room.java | 2 +- .../org/matrix/androidsdk/data/RoomState.java | 25 +++---------------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index a5a0f4ee0..29eed5d7a 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -856,7 +856,7 @@ public void updateCanonicalAlias(final String aCanonicalAlias, final ApiCallback mDataHandler.getDataRetriever().getRoomsRestClient().updateCanonicalAlias(getRoomId(), fCanonicalAlias, new RoomInfoUpdateCallback(callback) { @Override public void onSuccess(Void info) { - getState().roomAliasName = fCanonicalAlias; + getState().alias = aCanonicalAlias; super.onSuccess(info); } }); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index dbbb41d81..323c4ba63 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -102,14 +102,9 @@ public class RoomState implements Externalizable { // private Map> mStateEvents = new HashMap<>(); - // Informs which alias is the canonical one. - // TODO LazyLoading Manu: Alias what is this? + // The canonical alias of the room public String alias; - // The canonical alias of the room, if any. - // TODO LazyLoading Manu: Alias what is this? - public String canonical_alias; - // The name of the room as provided by the home server. public String name; @@ -141,10 +136,6 @@ public class RoomState implements Externalizable { // SPEC-134 public String history_visibility; - // the public room alias / name - // TODO LazyLoading Manu: Alias what is this? - public String roomAliasName; - /** * the room visibility in the directory list (i.e. public, private...) **/ @@ -688,7 +679,6 @@ public RoomState deepCopy() { copy.guest_access = guest_access; copy.history_visibility = history_visibility; copy.visibility = visibility; - copy.roomAliasName = roomAliasName; copy.token = token; copy.groups = groups; copy.mDataHandler = mDataHandler; @@ -723,6 +713,7 @@ public RoomState deepCopy() { /** * @return the room alias + * // TODO Remove this */ public String getAlias() { // SPEC-125 @@ -730,8 +721,6 @@ public String getAlias() { return alias; } else if (!TextUtils.isEmpty(getFirstAlias())) { return getFirstAlias(); - } else if (!TextUtils.isEmpty(canonical_alias)) { - return canonical_alias; } return null; @@ -739,6 +728,7 @@ public String getAlias() { /** * Returns the first room alias. + * // TODO Remove this * * @return the first room alias */ @@ -1192,10 +1182,6 @@ public void readExternal(ObjectInput input) throws IOException, ClassNotFoundExc history_visibility = input.readUTF(); } - if (input.readBoolean()) { - roomAliasName = input.readUTF(); - } - if (input.readBoolean()) { visibility = input.readUTF(); } @@ -1321,11 +1307,6 @@ public void writeExternal(ObjectOutput output) throws IOException { output.writeUTF(history_visibility); } - output.writeBoolean(null != roomAliasName); - if (null != roomAliasName) { - output.writeUTF(roomAliasName); - } - output.writeBoolean(null != visibility); if (null != visibility) { output.writeUTF(visibility); From 53e330aa4da2955aca87e2e4d3d8fa25073c58ad Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 6 Sep 2018 12:02:06 +0200 Subject: [PATCH 122/236] Never get an Alias from the alias list, only return the canonical alias --- .../org/matrix/androidsdk/data/RoomState.java | 29 ++----------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 323c4ba63..953545a12 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -710,36 +710,11 @@ public RoomState deepCopy() { return copy; } - /** - * @return the room alias - * // TODO Remove this + * @return the room canonical alias */ public String getAlias() { - // SPEC-125 - if (!TextUtils.isEmpty(alias)) { - return alias; - } else if (!TextUtils.isEmpty(getFirstAlias())) { - return getFirstAlias(); - } - - return null; - } - - /** - * Returns the first room alias. - * // TODO Remove this - * - * @return the first room alias - */ - private String getFirstAlias() { - List mergedAliases = getAliases(); - - if (mergedAliases.size() != 0) { - return mergedAliases.get(0); - } - - return null; + return alias; } /** From d1fa030ef5cd5c0bc82647ff6ec066c5da57681c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 6 Sep 2018 16:16:38 +0200 Subject: [PATCH 123/236] Improve code --- .../org/matrix/androidsdk/data/EventTimeline.java | 1 + .../main/java/org/matrix/androidsdk/data/Room.java | 11 +++++------ .../java/org/matrix/androidsdk/data/RoomState.java | 6 ++++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index 84eb747a6..69a0f7d99 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -624,6 +624,7 @@ else if ((null != roomSync.state) && (null != roomSync.state.events) && (roomSyn } } + // TODO LazyLoading, maybe this should be done earlier, because nb of members can be usefull in the instruction above. if (roomSync.roomSyncSummary != null) { RoomSummary summary = mStore.getSummary(mRoomId); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 29eed5d7a..a69cbbfd5 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -443,12 +443,11 @@ public boolean isLeaving() { } public void getMembersAsync(@NonNull final ApiCallback> callback) { - getState().getMembersAsync(new SimpleApiCallback>(callback) { - @Override - public void onSuccess(List members) { - callback.onSuccess(members); - } - }); + getState().getMembersAsync(callback); + } + + public void getDisplayableMembersAsync(@NonNull final ApiCallback> callback) { + getState().getDisplayableMembersAsync(callback); } public EventTimeline getLiveTimeLine() { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 953545a12..7b864a866 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -265,6 +265,8 @@ public List getLoadedMembers() { /** * Get the list of all the room members. Fetch from server if the full list is not loaded yet. + * + * @param callback The callback to get a copy of the room members list. */ public void getMembersAsync(ApiCallback> callback) { if (areAllMembersLoaded()) { @@ -290,6 +292,8 @@ public void getMembersAsync(ApiCallback> callback) { getDataHandler().getMembersAsync(roomId, new SimpleApiCallback>(callback) { @Override public void onSuccess(List info) { + Log.d(LOG_TAG, "getMembers has returned " + info.size() + " users."); + List res; for (RoomMember member : info) { @@ -321,7 +325,6 @@ public void onSuccess(List info) { * * @return true is LazyLoading is Off, or if all members has been loaded */ - // TODO LazyLoading maybe compare size of mMembers with number of users instead of using mAllMembersAreLoaded private boolean areAllMembersLoaded() { return mDataHandler != null && (!((MXDataHandler) mDataHandler).isLazyLoadingEnabled() || mAllMembersAreLoaded); @@ -415,7 +418,6 @@ public List getDisplayableLoadedMembers() { return res; } - /** * Provides a list of displayable members. * Some dummy members are created to internal stuff. From 8f5149161bf356ec1a79e12e0e84b5f8e8cf76ca Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 6 Sep 2018 16:31:52 +0200 Subject: [PATCH 124/236] MatrixMessageListFragment is now abstract and take an Adapter type as class parameter --- CHANGES.rst | 1 + .../fragments/MatrixMessageListFragment.java | 80 +++++++++---------- .../fragments/MatrixMessagesFragment.java | 54 +++---------- 3 files changed, 52 insertions(+), 83 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index df4992807..f5a0dc0c1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -18,6 +18,7 @@ API Change: - A Builder has been added to create HomeServerConnectionConfig instances. - SentState.UNDELIVERABLE has been renamed to SentState.UNDELIVERED - Extract patterns and corresponding methods from MXSession to a dedicated MXPatterns class. + - MatrixMessageListFragment is now abstract and take an Adapter type as class parameter Translations: - diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java index 9acad5572..3b5c92edf 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java @@ -82,7 +82,8 @@ * UI Fragment containing matrix messages for a given room. * Contains {@link MatrixMessagesFragment} as a nested fragment to do the work. */ -public class MatrixMessageListFragment extends Fragment implements MatrixMessagesFragment.MatrixMessagesListener { +public abstract class MatrixMessageListFragment extends Fragment + implements MatrixMessagesFragment.MatrixMessagesListener { // search interface public interface OnSearchResultListener { @@ -165,11 +166,11 @@ public interface IOnScrollListener { } // fragment parameters - public static final String ARG_LAYOUT_ID = "MatrixMessageListFragment.ARG_LAYOUT_ID"; - public static final String ARG_MATRIX_ID = "MatrixMessageListFragment.ARG_MATRIX_ID"; - public static final String ARG_ROOM_ID = "MatrixMessageListFragment.ARG_ROOM_ID"; - public static final String ARG_EVENT_ID = "MatrixMessageListFragment.ARG_EVENT_ID"; - public static final String ARG_PREVIEW_MODE_ID = "MatrixMessageListFragment.ARG_PREVIEW_MODE_ID"; + private static final String ARG_MATRIX_ID = "MatrixMessageListFragment.ARG_MATRIX_ID"; + private static final String ARG_ROOM_ID = "MatrixMessageListFragment.ARG_ROOM_ID"; + private static final String ARG_LAYOUT_ID = "MatrixMessageListFragment.ARG_LAYOUT_ID"; + protected static final String ARG_EVENT_ID = "MatrixMessageListFragment.ARG_EVENT_ID"; + protected static final String ARG_PREVIEW_MODE_ID = "MatrixMessageListFragment.ARG_PREVIEW_MODE_ID"; // default preview mode public static final String PREVIEW_MODE_READ_ONLY = "PREVIEW_MODE_READ_ONLY"; @@ -179,17 +180,16 @@ public interface IOnScrollListener { private static final int UNDEFINED_VIEW_Y_POS = -12345678; - public static MatrixMessageListFragment newInstance(String matrixId, String roomId, int layoutResId) { - MatrixMessageListFragment f = new MatrixMessageListFragment(); + public static Bundle getArguments(String matrixId, String roomId, int layoutResId) { Bundle args = new Bundle(); + args.putString(ARG_MATRIX_ID, matrixId); args.putString(ARG_ROOM_ID, roomId); args.putInt(ARG_LAYOUT_ID, layoutResId); - args.putString(ARG_MATRIX_ID, matrixId); - return f; + return args; } private MatrixMessagesFragment mMatrixMessagesFragment; - protected AbstractMessagesAdapter mAdapter; + protected MessagesAdapter mAdapter; public AutoScrollDownListView mMessageListView; protected Handler mUiHandler; protected MXSession mSession; @@ -206,6 +206,9 @@ public static MatrixMessageListFragment newInstance(String matrixId, String room // timeline management protected final boolean mIsLive = true; + // From Fragment parameters + protected String mRoomId; + // by default the protected EventTimeline mEventTimeLine; protected String mEventId; @@ -249,21 +252,22 @@ public static MatrixMessageListFragment newInstance(String matrixId, String room // because there is no way to detect if enough data were retrieved private boolean mFillHistoryOnResume; - public MXMediasCache getMXMediasCache() { - return null; - } + /** + * Get MxMediaCache + * + * @return + */ + public abstract MXMediasCache getMXMediasCache(); - public MXSession getSession(String matrixId) { - return null; - } + /** + * Get MxSession + * + * @param matrixId + * @return + */ + public abstract MXSession getSession(String matrixId); public MXSession getSession() { - // if the session has not been set - if (null == mSession) { - // find it out - mSession = getSession(mMatrixId); - } - return mSession; } @@ -476,7 +480,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa throw new RuntimeException("Must have valid default MediasCache."); } - String roomId = args.getString(ARG_ROOM_ID); + mRoomId = args.getString(ARG_ROOM_ID); View v = inflater.inflate(args.getInt(ARG_LAYOUT_ID), container, false); mMessageListView = v.findViewById(R.id.listView_messages); @@ -501,7 +505,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa final String previewMode = args.getString(ARG_PREVIEW_MODE_ID); // the fragment displays the history around a message if (!TextUtils.isEmpty(mEventId)) { - mEventTimeLine = new EventTimeline(mSession.getDataHandler(), roomId, mEventId); + mEventTimeLine = new EventTimeline(mSession.getDataHandler(), mRoomId, mEventId); mRoom = mEventTimeLine.getRoom(); if (PREVIEW_MODE_UNREAD_MESSAGE.equals(previewMode)) { mAdapter.setIsUnreadViewMode(true); @@ -510,13 +514,13 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa // display a room preview else if (PREVIEW_MODE_READ_ONLY.equals(previewMode)) { mAdapter.setIsPreviewMode(true); - mEventTimeLine = new EventTimeline(mSession.getDataHandler(), roomId); + mEventTimeLine = new EventTimeline(mSession.getDataHandler(), mRoomId); mRoom = mEventTimeLine.getRoom(); } // standard case else { - if (!TextUtils.isEmpty(roomId)) { - mRoom = mSession.getDataHandler().getRoom(roomId); + if (!TextUtils.isEmpty(mRoomId)) { + mRoom = mSession.getDataHandler().getRoom(mRoomId); mEventTimeLine = mRoom.getLiveTimeLine(); } } @@ -585,13 +589,13 @@ public void onActivityCreated(Bundle savedInstanceState) { fm.beginTransaction().add(mMatrixMessagesFragment, getMatrixMessagesFragmentTag()).commit(); } else { Log.d(LOG_TAG, "onActivityCreated - reuse"); + } - // Set the listener because this is not done when the system restores the fragment (newInstance is not called) - mMatrixMessagesFragment.setMatrixMessagesListener(this); + // Set the listener + mMatrixMessagesFragment.setMatrixMessagesListener(this); - // Also set the session - mMatrixMessagesFragment.setMXSession(getSession()); - } + // Set the session + mMatrixMessagesFragment.setMXSession(getSession()); mMatrixMessagesFragment.mKeepRoomHistory = (-1 != mFirstVisibleRow); } @@ -653,13 +657,13 @@ public void onResume() { /** * Create the messageFragment. - * Should be inherited. + * Should be overridden. * * @param roomId the roomID * @return the MatrixMessagesFragment */ public MatrixMessagesFragment createMessagesFragmentInstance(String roomId) { - return MatrixMessagesFragment.newInstance(getSession(), roomId, this); + return MatrixMessagesFragment.newInstance(roomId); } /** @@ -671,13 +675,10 @@ protected String getMatrixMessagesFragmentTag() { /** * Create the messages adapter. - * This method must be overriden to provide a valid creation * * @return the messages adapter. */ - public AbstractMessagesAdapter createMessagesAdapter() { - return null; - } + public abstract MessagesAdapter createMessagesAdapter(); /** * The user scrolls the list. @@ -2218,7 +2219,6 @@ public void onUnexpectedError(Exception e) { if (mIsMediaSearch) { mSession.searchMediasByName(mPattern, roomIds, mNextBatch, callback); - } else { mSession.searchMessagesByText(mPattern, roomIds, mNextBatch, callback); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java index 44eac193b..5741e5736 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java @@ -1,6 +1,7 @@ /* * Copyright 2015 OpenMarket Ltd * Copyright 2017 Vector Creations Ltd + * Copyright 2018 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +22,6 @@ import android.os.Bundle; import android.os.Looper; import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; @@ -59,31 +59,20 @@ public class MatrixMessagesFragment extends Fragment { * The room ID to get messages for. * Fragment argument: String. */ - public static final String ARG_ROOM_ID = "org.matrix.androidsdk.fragments.MatrixMessageFragment.ARG_ROOM_ID"; + private static final String ARG_ROOM_ID = "org.matrix.androidsdk.fragments.MatrixMessageFragment.ARG_ROOM_ID"; - public static MatrixMessagesFragment newInstance(MXSession session, String roomId, MatrixMessagesListener listener) { + public static MatrixMessagesFragment newInstance(String roomId) { MatrixMessagesFragment fragment = new MatrixMessagesFragment(); - Bundle args = new Bundle(); - - - if (null == listener) { - throw new RuntimeException("Must define a listener."); - } - - if (null == session) { - throw new RuntimeException("Must define a session."); - } - - if (null != roomId) { - args.putString(ARG_ROOM_ID, roomId); - } - - fragment.setArguments(args); - fragment.setMatrixMessagesListener(listener); - fragment.setMXSession(session); + fragment.setArguments(getArgument(roomId)); return fragment; } + public static Bundle getArgument(String roomId) { + Bundle args = new Bundle(); + args.putString(ARG_ROOM_ID, roomId); + return args; + } + public interface MatrixMessagesListener { void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState); @@ -200,28 +189,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa // it saves only few ms but it reduces the white screen flash. mContext = getActivity().getApplicationContext(); - String roomId = getArguments().getString(ARG_ROOM_ID); - - // this code should never be called - // but we've got some crashes when the session was null - // so try to find it from the fragments call stack. - if (null == mSession) { - List fragments = null; - FragmentManager fm = getActivity().getSupportFragmentManager(); - - if (null != fm) { - fragments = fm.getFragments(); - } - - if (null != fragments) { - for (Fragment fragment : fragments) { - if (fragment instanceof MatrixMessageListFragment) { - mMatrixMessagesListener = (MatrixMessageListFragment) fragment; - mSession = ((MatrixMessageListFragment) fragment).getSession(); - } - } - } - } + String roomId = getArguments().getString(ARG_ROOM_ID);member? if (mSession == null) { throw new RuntimeException("Must have valid default MXSession."); From 3ea4649890c0b9a38fd3ba25f00a65cc5bc552c7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 6 Sep 2018 16:33:37 +0200 Subject: [PATCH 125/236] Fix issue on first access of Fragment (still bugged) --- .../matrix/androidsdk/fragments/MatrixMessagesFragment.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java index 5741e5736..f5c88fabb 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java @@ -39,7 +39,6 @@ import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.MatrixError; -import org.matrix.androidsdk.rest.model.RoomMember; import org.matrix.androidsdk.rest.model.sync.RoomResponse; import org.matrix.androidsdk.rest.model.sync.RoomSync; import org.matrix.androidsdk.rest.model.sync.RoomSyncState; @@ -232,6 +231,10 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa // check if some required fields are initialized // else, the joining could have been half broken (network error) if (null != mRoom.getState().getRoomCreateContent()) { + joinedRoom = mRoom.isJoined(); + + // TODO LazyLoading: handle KICK and BAN membership? + /* RoomMember self = mRoom.getMember(mSession.getCredentials().userId); if (self != null && (RoomMember.MEMBERSHIP_JOIN.equals(self.membership) || @@ -239,6 +242,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa RoomMember.MEMBERSHIP_BAN.equals(self.membership))) { joinedRoom = true; } + */ } mRoom.addEventListener(mEventListener); From cf006af6e15f6c934ad4d52e9b664c5d05fed790 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 6 Sep 2018 16:49:44 +0200 Subject: [PATCH 126/236] typo --- .../org/matrix/androidsdk/fragments/MatrixMessagesFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java index f5c88fabb..89f46d623 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java @@ -188,7 +188,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa // it saves only few ms but it reduces the white screen flash. mContext = getActivity().getApplicationContext(); - String roomId = getArguments().getString(ARG_ROOM_ID);member? + String roomId = getArguments().getString(ARG_ROOM_ID); if (mSession == null) { throw new RuntimeException("Must have valid default MXSession."); From 12dd46cc8ee538ecfeb82cd105b3fcbcbae99d49 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 6 Sep 2018 16:50:28 +0200 Subject: [PATCH 127/236] Exclude "leave" membership when requesting members --- .../org/matrix/androidsdk/MXDataHandler.java | 27 ++++++++++--------- .../matrix/androidsdk/rest/api/RoomsApi.java | 13 +++++---- .../rest/client/RoomsRestClient.java | 12 ++++++--- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 831cb18b0..f9701d22a 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -946,26 +946,27 @@ public void onSuccess(RoomAliasDescription info) { } /** - * Get the members of a Room with a request to the server + * Get the members of a Room with a request to the server. it will exclude the members who has left the room * * @param roomId the id of the room * @param callback the callback */ public void getMembersAsync(final String roomId, final ApiCallback> callback) { - mRoomsRestClient.getRoomMembers(roomId, getStore().getEventStreamToken(), null, null, new SimpleApiCallback>(callback) { - @Override - public void onSuccess(TokensChunkResponse info) { - Room room = getRoom(roomId); + mRoomsRestClient.getRoomMembers(roomId, getStore().getEventStreamToken(), null, RoomMember.MEMBERSHIP_LEAVE, + new SimpleApiCallback>(callback) { + @Override + public void onSuccess(TokensChunkResponse info) { + Room room = getRoom(roomId); - if (info.chunk != null) { - for (Event event : info.chunk) { - room.getState().applyState(getStore(), event, EventTimeline.Direction.FORWARDS); - } - } + if (info.chunk != null) { + for (Event event : info.chunk) { + room.getState().applyState(getStore(), event, EventTimeline.Direction.FORWARDS); + } + } - callback.onSuccess(room.getState().getLoadedMembers()); - } - }); + callback.onSuccess(room.getState().getLoadedMembers()); + } + }); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index e1a217098..ce2965076 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -405,14 +405,13 @@ Call updateAccountData(@Path("userId") String userId, * Get all members of a room * * @param roomId the room id where to get the members - * @param syncToken - * @param membership - * @param notMembership + * @param syncToken the sync token (optional) + * @param membership to include only one type of membership (optional) + * @param notMembership to exclude one type of membership (optional) */ - // TODO LazyLoading check that the "at" param has an effect... @GET("rooms/{roomId}/members") Call> getMembers(@Path("roomId") String roomId, - @Query("at") String syncToken, - @Query("membership") String membership, - @Query("not_membership") String notMembership); + @Nullable @Query("at") String syncToken, + @Nullable @Query("membership") String membership, + @Nullable @Query("not_membership") String notMembership); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index ccd26eaa5..b88f7d003 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -611,11 +611,17 @@ public void onRetry() { /** * Get the room members + * + * @param roomId the room id where to get the members + * @param syncToken the sync token (optional) + * @param membership to include only one type of membership (optional) + * @param notMembership to exclude one type of membership (optional) + * @param callback the callback */ public void getRoomMembers(final String roomId, - final String syncToken, - final String membership, - final String notMembership, + @Nullable final String syncToken, + @Nullable final String membership, + @Nullable final String notMembership, final ApiCallback> callback) { final String description = "getRoomMembers roomId=" + roomId; From 08dcf7a0bb4cff9429ebed62b925e2be7c98e1d0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Sep 2018 11:29:46 +0200 Subject: [PATCH 128/236] Force a fetch of the loaded members in case of gap in the received events --- .../org/matrix/androidsdk/data/EventTimeline.java | 4 ++++ .../java/org/matrix/androidsdk/data/RoomState.java | 7 +++++++ .../androidsdk/rest/model/sync/RoomSyncTimeline.java | 11 +++++++---- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index 69a0f7d99..d6360f707 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -457,6 +457,7 @@ public void handleJoinedRoomSync(RoomSync roomSync, boolean isGlobalInitialSync) if (null != roomSync.timeline) { if (roomSync.timeline.limited) { if (!isRoomInitialSync) { + // There is a gap between known events and received events in this incremental sync. currentSummary = mStore.getSummary(mRoomId); // define a summary if some messages are left @@ -476,6 +477,9 @@ public void handleJoinedRoomSync(RoomSync roomSync, boolean isGlobalInitialSync) } } } + + // Force a fetch of the loaded members the next time they will be requested + mState.forceMembersRequest(); } // if the prev batch is set to null diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 7b864a866..346aa3342 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -330,6 +330,13 @@ private boolean areAllMembersLoaded() { && (!((MXDataHandler) mDataHandler).isLazyLoadingEnabled() || mAllMembersAreLoaded); } + /** + * Force a fetch of the loaded members the next time they will be requested + */ + public void forceMembersRequest() { + mAllMembersAreLoaded = true; + } + /** * Provides the loaded states event list. * The room member events are NOT included. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncTimeline.java index e7ea2418a..2533b272e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncTimeline.java @@ -1,13 +1,13 @@ -/* +/* * Copyright 2016 OpenMarket Ltd * Copyright 2018 New Vector Ltd * * 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. @@ -20,7 +20,9 @@ import java.util.List; -// RoomSyncTimeline represents the timeline of messages and state changes for a room during server sync v2. +/** + * RoomSyncTimeline represents the timeline of messages and state changes for a room during server sync v2. + */ public class RoomSyncTimeline { /** @@ -30,6 +32,7 @@ public class RoomSyncTimeline { /** * Boolean which tells whether there are more events on the server + * In the case of an incremental sync, if the value is true, it's means that there is a gap between known events and received events */ public boolean limited; From 590f86f01c09953d549a73e841273e7bb296cf5c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 7 Sep 2018 14:24:46 +0200 Subject: [PATCH 129/236] Ensure user is always known --- .../src/main/java/org/matrix/androidsdk/data/RoomState.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 346aa3342..d2ffe07b4 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -504,6 +504,11 @@ public RoomMember getMember(String userId) { if (member == null) { // TODO LazyLoading Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Null member '" + userId + "' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + + if (TextUtils.equals(getDataHandler().getUserId(), userId)) { + // This should never happen + Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Null current user '" + userId + "' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } } return member; From 33687be9ae77afc9c67b2023578629b61dd1c9f8 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 11 Sep 2018 11:58:38 +0200 Subject: [PATCH 130/236] LL: Room summary set has joined sooner --- .../main/java/org/matrix/androidsdk/data/Room.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index a69cbbfd5..81b7990f0 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -311,7 +311,10 @@ public void handleJoinedRoomSync(RoomSync roomSync, boolean isGlobalInitialSync) synchronized (this) { mLiveTimeline.handleJoinedRoomSync(roomSync, isGlobalInitialSync); - + RoomSummary roomSummary = getRoomSummary(); + if (roomSummary != null) { + roomSummary.setIsJoined(); + } // ephemeral events if ((null != roomSync.ephemeral) && (null != roomSync.ephemeral.events)) { handleEphemeralEvents(roomSync.ephemeral.events); @@ -358,12 +361,6 @@ public void run() { } // else -> it will be done at the end of the sync mRefreshUnreadAfterSync = false; } - - RoomSummary roomSummary = getRoomSummary(); - - if (roomSummary != null) { - roomSummary.setIsJoined(); - } } /** From 4f9a0ed8fc0f9be3535e719729d31967a2f21bd8 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 11 Sep 2018 12:00:36 +0200 Subject: [PATCH 131/236] LL Test : modify backpaginate with permalink test (same behavior than forward with permalink) --- .../lazyloading/LazyLoadingTestHelper.java | 3 +- .../androidsdk/lazyloading/RoomStateTest.java | 51 ++++++++++--------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java index f29d67f37..ae1816b07 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java @@ -82,6 +82,7 @@ public void onSuccess(String info) { final String roomId = results.get("roomId"); final Room bobRoom = bobSession.getDataHandler().getRoom(roomId); + //update name and join rules latch = new CountDownLatch(1); bobRoom.updateName("LazyLoading Test Room", new TestApiCallback(latch)); @@ -119,7 +120,7 @@ public void onSuccess(String info) { final String bobMessageId = bobMessages.isEmpty() ? null : bobMessages.get(0).eventId; - // Clear Alice session and open new one + // Clear sessions and open new ones final Context context = InstrumentationRegistry.getContext(); aliceSession.clear(context); bobSession.clear(context); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index 0e00da8ce..55d02c9ba 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -107,7 +107,7 @@ public void RoomState_BackPaginate_ShouldLoadAllMembers() throws Exception { @Test public void RoomState_BackPaginate_LazyLoading() throws Exception { - RoomState_BackPaginate(true); + RoomState_BackPaginate(true); } private void RoomState_BackPaginate(final boolean withLazyLoading) throws Exception { @@ -165,7 +165,7 @@ public void RoomState_Permalink_ShouldLoadAllMembers() throws Exception { @Test public void RoomState_Permalink_LazyLoading() throws Exception { - RoomState_Permalink(true); + RoomState_Permalink(true); } private void RoomState_Permalink(final boolean withLazyLoading) throws Exception { @@ -204,13 +204,16 @@ public void RoomState_PermalinkWithBackPagination_LazyLoading() throws Exception RoomState_PermalinkWithBackPagination(true); } + // Test lazy loaded members sent by the HS when paginating backward + // - Come back to Bob message + // - We should only know Bob membership + // - Paginate backward to get Alice next message + // - We should know Alice membership now private void RoomState_PermalinkWithBackPagination(final boolean withLazyLoading) throws Exception { final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); mTestHelper.syncSession(data.aliceSession, false); - final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); final CountDownLatch lock = new CountDownLatch(1); - final Event lastEvent = aliceRoom.getDataHandler().getStore().getLatestEvent(data.roomId); - final EventTimeline eventTimeline = new EventTimeline(data.aliceSession.getDataHandler(), lastEvent.roomId, lastEvent.eventId); + final EventTimeline eventTimeline = new EventTimeline(data.aliceSession.getDataHandler(), data.roomId, data.bobMessageId); eventTimeline.addEventTimelineListener(new EventTimeline.EventTimelineListener() { int messageCount = 0; @@ -218,30 +221,23 @@ private void RoomState_PermalinkWithBackPagination(final boolean withLazyLoading public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { messageCount++; - Log.d("TAG", "Receiving message #" + messageCount + ": " + JsonUtils.toMessage(event.getContent()).body); - - if (messageCount <= 50) { - Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); - - // With LazyLoading, Bob and Sam are not known by Alice yet - Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.bobSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, roomState.getMember(data.bobSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); - } else if (messageCount <= 100) { - // Bob is known now + if (messageCount == 1) { + // We received the Event from bob + Assert.assertEquals(event.sender, data.bobSession.getMyUserId()); + // Bob is known Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); - - // With LazyLoading, Sam is not known by Alice yet + // With LazyLoading, Alice and Sam are not known by Alice yet + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.aliceSession.getMyUserId()) == null); Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); - } else if (messageCount == 101) { - // All users are known now + } else if (messageCount == 2) { + // We received the Event from Alice + Assert.assertEquals(event.sender, data.aliceSession.getMyUserId()); + // Alice and Bob are known Assert.assertNotNull(eventTimeline.getState().getMember(data.aliceSession.getMyUserId())); Assert.assertNotNull(eventTimeline.getState().getMember(data.bobSession.getMyUserId())); - Assert.assertNotNull(eventTimeline.getState().getMember(data.samSession.getMyUserId())); - + // With LazyLoading, Sam is not known by Alice yet + Assert.assertEquals(withLazyLoading, eventTimeline.getState().getMember(data.samSession.getMyUserId()) == null); lock.countDown(); } } else { @@ -252,7 +248,12 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro eventTimeline.resetPaginationAroundInitialEvent(0, new SimpleApiCallback() { @Override public void onSuccess(Void info) { - recursiveBackPaginate(eventTimeline, 0, 30, 120); + eventTimeline.backPaginate(new SimpleApiCallback() { + @Override + public void onSuccess(Integer info) { + // ignore + } + }); } }); mTestHelper.await(lock); From 3ab72fded55811eb3b09ba92b85648d4cea7331f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 10 Sep 2018 17:35:12 +0200 Subject: [PATCH 132/236] GET /event/{eventId} has been moved to the EventsApi and in not used anymore to search an event in a room --- .../matrix/androidsdk/rest/api/EventsApi.java | 10 +++++ .../matrix/androidsdk/rest/api/RoomsApi.java | 8 ---- .../rest/client/EventsRestClient.java | 18 ++++++++ .../rest/client/RoomsRestClient.java | 42 +++---------------- 4 files changed, 33 insertions(+), 45 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/EventsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/EventsApi.java index 136154032..813c5b43d 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/EventsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/EventsApi.java @@ -17,6 +17,7 @@ package org.matrix.androidsdk.rest.api; import org.matrix.androidsdk.RestClient; +import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.pid.ThirdPartyProtocol; import org.matrix.androidsdk.rest.model.publicroom.PublicRoomsParams; import org.matrix.androidsdk.rest.model.publicroom.PublicRoomsResponse; @@ -32,6 +33,7 @@ import retrofit2.http.Body; import retrofit2.http.GET; import retrofit2.http.POST; +import retrofit2.http.Path; import retrofit2.http.Query; import retrofit2.http.QueryMap; @@ -48,6 +50,14 @@ public interface EventsApi { @GET(RestClient.URI_API_PREFIX_PATH_R0 + "sync") Call sync(@QueryMap Map params); + /** + * Retrieve an event from its event id + * + * @param eventId the event Id + */ + @GET(RestClient.URI_API_PREFIX_PATH_R0 + "events/{eventId}") + Call getEvent(@Path("eventId") String eventId); + /** * Get the third party server protocols. */ diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index ce2965076..f796d219c 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -276,14 +276,6 @@ Call getContextOfEvent(@Path("roomId") String roomId, @GET("rooms/{roomId}/event/{eventId}") Call getEvent(@Path("roomId") String roomId, @Path("eventId") String eventId); - /** - * Retrieve an event from its event id - * - * @param eventId the event Id - */ - @GET("events/{eventId}") - Call getEvent(@Path("eventId") String eventId); - /** * Redact an event from the room>. * diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/EventsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/EventsRestClient.java index 0f23254e7..b36a5b18f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/EventsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/EventsRestClient.java @@ -235,6 +235,24 @@ public void onRetry() { })); } + /** + * Retrieve an event from its event id. + * + * @param eventId the event id + * @param callback the asynchronous callback. + */ + public void getEventFromEventId(final String eventId, final ApiCallback callback) { + final String description = "getEventFromEventId : eventId " + eventId; + + mApi.getEvent(eventId) + .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { + @Override + public void onRetry() { + getEventFromEventId(eventId, callback); + } + })); + } + /** * Search a text in room messages. * diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index b88f7d003..b5209f601 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -411,25 +411,12 @@ public void onSuccess(Event event) { @Override public void onMatrixError(MatrixError e) { if (TextUtils.equals(e.errcode, MatrixError.UNRECOGNIZED)) { - getEventFromEventId(eventId, new SimpleApiCallback(callback) { + // Try to retrieve the event using the context API + // It's ok to pass null as a filter here + getContextOfEvent(roomId, eventId, 1, null, new SimpleApiCallback(callback) { @Override - public void onSuccess(Event event) { - callback.onSuccess(event); - } - - @Override - public void onMatrixError(MatrixError e) { - if (TextUtils.equals(e.errcode, MatrixError.UNRECOGNIZED)) { - // TODO LazyLoading Manu do we should enable lazy loading here? - getContextOfEvent(roomId, eventId, 1, null, new SimpleApiCallback(callback) { - @Override - public void onSuccess(EventContext eventContext) { - callback.onSuccess(eventContext.event); - } - }); - } else { - callback.onMatrixError(e); - } + public void onSuccess(EventContext eventContext) { + callback.onSuccess(eventContext.event); } }); } else { @@ -458,25 +445,6 @@ public void onRetry() { })); } - /** - * Retrieve an event from its event id. - * - * @param eventId the event id - * @param callback the asynchronous callback. - */ - private void getEventFromEventId(final String eventId, final ApiCallback callback) { - final String description = "getEventFromEventId : eventId " + eventId; - - mApi.getEvent(eventId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getEventFromEventId(eventId, callback); - } - })); - } - - /** * Get the context surrounding an event. * From 2900e2c820b9746ba73ffa10b09957de0fe74a52 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 10:38:40 +0200 Subject: [PATCH 133/236] MXDataHandler does not implement IMXEventListener (it was useless) MxEventDispatcher is created to dispatch event to the listeners --- .../org/matrix/androidsdk/MXDataHandler.java | 756 ++-------------- .../matrix/androidsdk/MxEventDispatcher.java | 836 ++++++++++++++++++ 2 files changed, 888 insertions(+), 704 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index f9701d22a..e57df0bdd 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -92,7 +92,7 @@ *

  • Provides the means for an app to get callbacks for data changes
  • * */ -public class MXDataHandler implements IMXEventListener { +public class MXDataHandler { private static final String LOG_TAG = MXDataHandler.class.getSimpleName(); private static final String LEFT_ROOMS_FILTER = "{\"room\":{\"timeline\":{\"limit\":1},\"include_leave\":true}}"; @@ -113,8 +113,7 @@ public interface RequestNetworkErrorListener { void onSSLCertificateError(UnrecognizedCertificateException exception); } - private IMXEventListener mCryptoEventsListener = null; - private final Set mEventListeners = new HashSet<>(); + private MxEventDispatcher mMxEventDispatcher; private final IMXStore mStore; private final Credentials mCredentials; @@ -139,7 +138,6 @@ public interface RequestNetworkErrorListener { private HandlerThread mSyncHandlerThread; private final MXOsHandler mSyncHandler; - private final MXOsHandler mUiHandler; // list of ignored users // null -> not initialized @@ -190,7 +188,7 @@ public MXDataHandler(IMXStore store, Credentials credentials) { mStore = store; mCredentials = credentials; - mUiHandler = new MXOsHandler(Looper.getMainLooper()); + mMxEventDispatcher = new MxEventDispatcher(); mSyncHandlerThread = new HandlerThread("MXDataHandler" + mCredentials.userId, Thread.MIN_PRIORITY); mSyncHandlerThread.start(); @@ -598,7 +596,7 @@ public BingRulesManager getBingRulesManager() { * @param listener the listener */ public void setCryptoEventsListener(IMXEventListener listener) { - mCryptoEventsListener = listener; + mMxEventDispatcher.setCryptoEventsListener(listener); } /** @@ -608,8 +606,8 @@ public void setCryptoEventsListener(IMXEventListener listener) { */ public void addListener(IMXEventListener listener) { if (isAlive() && (null != listener)) { - synchronized (this) { - mEventListeners.add(listener); + synchronized (mMxEventDispatcher) { + mMxEventDispatcher.addListener(listener); } if (null != mInitialSyncToToken) { @@ -625,8 +623,8 @@ public void addListener(IMXEventListener listener) { */ public void removeListener(IMXEventListener listener) { if (isAlive() && (null != listener)) { - synchronized (this) { - mEventListeners.remove(listener); + synchronized (mMxEventDispatcher) { + mMxEventDispatcher.removeListener(listener); } } } @@ -635,10 +633,10 @@ public void removeListener(IMXEventListener listener) { * Clear the instance data. */ public void clear() { - synchronized (this) { + synchronized (mMxEventDispatcher) { mIsAlive = false; // remove any listener - mEventListeners.clear(); + mMxEventDispatcher.clearListeners(); } // clear the store @@ -1526,7 +1524,7 @@ public void onUnexpectedError(Exception e) { // 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. + // The room will then be able to notify its listeners. room.handleJoinedRoomSync(syncResponse.rooms.leave.get(roomId), isInitialSync); RoomMember member = room.getMember(getUserId()); @@ -1853,85 +1851,19 @@ public void resetReplayAttackCheckInTimeline(String timelineId) { // Listeners management //================================================================================ - /** - * @return the current MXEvents listeners. - */ - private List getListenersSnapshot() { - List eventListeners; - - synchronized (this) { - eventListeners = new ArrayList<>(mEventListeners); - } - - return eventListeners; - } - /** * Dispatch that the store is ready. */ public void onStoreReady() { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onStoreReady(); - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onStoreReady(); - } catch (Exception e) { - Log.e(LOG_TAG, "onStoreReady " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnStoreReady(); } - @Override public void onAccountInfoUpdate(final MyUser myUser) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onAccountInfoUpdate(myUser); - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onAccountInfoUpdate(myUser); - } catch (Exception e) { - Log.e(LOG_TAG, "onAccountInfoUpdate " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnAccountInfoUpdate(myUser); } - @Override public void onPresenceUpdate(final Event event, final User user) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onPresenceUpdate(event, user); - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onPresenceUpdate(event, user); - } catch (Exception e) { - Log.e(LOG_TAG, "onPresenceUpdate " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnPresenceUpdate(event, user); } /** @@ -1954,7 +1886,6 @@ private boolean ignoreEvent(String roomId) { } } - @Override public void onLiveEvent(final Event event, final RoomState roomState) { if (ignoreEvent(event.roomId)) { return; @@ -1970,77 +1901,20 @@ public void onLiveEvent(final Event event, final RoomState roomState) { } } - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onLiveEvent(event, roomState); - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onLiveEvent(event, roomState); - } catch (Exception e) { - Log.e(LOG_TAG, "onLiveEvent " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnLiveEvent(event, roomState); } - @Override public void onLiveEventsChunkProcessed(final String startToken, final String toToken) { // reset the resource limit exceeded error mResourceLimitExceededError = null; refreshUnreadCounters(); - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onLiveEventsChunkProcessed(startToken, toToken); - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onLiveEventsChunkProcessed(startToken, toToken); - } catch (Exception e) { - Log.e(LOG_TAG, "onLiveEventsChunkProcessed " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnLiveEventsChunkProcessed(startToken, toToken); } - @Override public void onBingEvent(final Event event, final RoomState roomState, final BingRule bingRule) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onBingEvent(event, roomState, bingRule); - } - - if (ignoreEvent(event.roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onBingEvent(event, roomState, bingRule); - } catch (Exception e) { - Log.e(LOG_TAG, "onBingEvent " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnBingEvent(event, roomState, bingRule, ignoreEvent(event.roomId)); } /** @@ -2057,122 +1931,16 @@ public void updateEventState(Event event, Event.SentState newState) { } } - @Override public void onEventSentStateUpdated(final Event event) { - if (ignoreEvent(event.roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onEventSentStateUpdated(event); - } catch (Exception e) { - Log.e(LOG_TAG, "onEventSentStateUpdated " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnEventSentStateUpdated(event, ignoreEvent(event.roomId)); } - @Override public void onEventSent(final Event event, final String prevEventId) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onEventSent(event, prevEventId); - } - - if (ignoreEvent(event.roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onEventSent(event, prevEventId); - } catch (Exception e) { - Log.e(LOG_TAG, "onEventSent " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnEventSent(event, prevEventId, ignoreEvent(event.roomId)); } - @Override public void onBingRulesUpdate() { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onBingRulesUpdate(); - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onBingRulesUpdate(); - } catch (Exception e) { - Log.e(LOG_TAG, "onBingRulesUpdate " + e.getMessage(), e); - } - } - } - }); - } - - /** - * Dispatch the onInitialSyncComplete event. - */ - private void dispatchOnInitialSyncComplete(final String toToken) { - mInitialSyncToToken = toToken; - - refreshUnreadCounters(); - - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onInitialSyncComplete(toToken); - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onInitialSyncComplete(mInitialSyncToToken); - } catch (Exception e) { - Log.e(LOG_TAG, "onInitialSyncComplete " + e.getMessage(), e); - } - } - } - }); - } - - /** - * Dispatch the OnCryptoSyncComplete event. - */ - private void dispatchOnCryptoSyncComplete() { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onCryptoSyncComplete(); - } catch (Exception e) { - Log.e(LOG_TAG, "OnCryptoSyncComplete " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnBingRulesUpdate(); } /** @@ -2184,7 +1952,7 @@ private void startCrypto(final boolean isInitialSync) { getCrypto().start(isInitialSync, new ApiCallback() { @Override public void onSuccess(Void info) { - dispatchOnCryptoSyncComplete(); + onCryptoSyncComplete(); } private void onError(String errorMessage) { @@ -2209,539 +1977,119 @@ public void onUnexpectedError(Exception e) { } } - - @Override public void onInitialSyncComplete(String toToken) { - dispatchOnInitialSyncComplete(toToken); + mInitialSyncToToken = toToken; + + refreshUnreadCounters(); + + mMxEventDispatcher.dispatchOnInitialSyncComplete(toToken); } - @Override public void onSyncError(final MatrixError matrixError) { // Store the resource limit exceeded error if (MatrixError.RESOURCE_LIMIT_EXCEEDED.equals(matrixError.errcode)) { mResourceLimitExceededError = matrixError; } - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onSyncError(matrixError); - } catch (Exception e) { - Log.e(LOG_TAG, "onSyncError " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnSyncError(matrixError); } - @Override public void onCryptoSyncComplete() { + mMxEventDispatcher.dispatchOnCryptoSyncComplete(); } - @Override public void onNewRoom(final String roomId) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onNewRoom(roomId); - } - - if (ignoreEvent(roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onNewRoom(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onNewRoom " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnNewRoom(roomId, ignoreEvent(roomId)); } - @Override public void onJoinRoom(final String roomId) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onJoinRoom(roomId); - } - - if (ignoreEvent(roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onJoinRoom(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onJoinRoom " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnJoinRoom(roomId, ignoreEvent(roomId)); } - @Override + // FIXME Check why this method is never called public void onRoomInitialSyncComplete(final String roomId) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onRoomInitialSyncComplete(roomId); - } - - if (ignoreEvent(roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onRoomInitialSyncComplete(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomInitialSyncComplete " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnRoomInitialSyncComplete(roomId, ignoreEvent(roomId)); } - @Override public void onRoomInternalUpdate(final String roomId) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onRoomInternalUpdate(roomId); - } - - if (ignoreEvent(roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onRoomInternalUpdate(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomInternalUpdate " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnRoomInternalUpdate(roomId, ignoreEvent(roomId)); } - @Override public void onNotificationCountUpdate(final String roomId) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onNotificationCountUpdate(roomId); - } - - if (ignoreEvent(roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onNotificationCountUpdate(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onNotificationCountUpdate " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnNotificationCountUpdate(roomId, ignoreEvent(roomId)); } - @Override public void onLeaveRoom(final String roomId) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onLeaveRoom(roomId); - } - - if (ignoreEvent(roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onLeaveRoom(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onLeaveRoom " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnLeaveRoom(roomId, ignoreEvent(roomId)); } - @Override public void onRoomKick(final String roomId) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onRoomKick(roomId); - } - - if (ignoreEvent(roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onRoomKick(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomKick " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnRoomKick(roomId, ignoreEvent(roomId)); } - @Override public void onReceiptEvent(final String roomId, final List senderIds) { synchronized (mUpdatedRoomIdList) { - // refresh the unread countries at the end of the process chunk + // refresh the unread counter at the end of the process chunk mUpdatedRoomIdList.add(roomId); } - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onReceiptEvent(roomId, senderIds); - } - - if (ignoreEvent(roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onReceiptEvent(roomId, senderIds); - } catch (Exception e) { - Log.e(LOG_TAG, "onReceiptEvent " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnReceiptEvent(roomId, senderIds, ignoreEvent(roomId)); } - @Override public void onRoomTagEvent(final String roomId) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onRoomTagEvent(roomId); - } - - if (ignoreEvent(roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onRoomTagEvent(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomTagEvent " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnRoomTagEvent(roomId, ignoreEvent(roomId)); } - @Override public void onReadMarkerEvent(final String roomId) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onReadMarkerEvent(roomId); - } - - if (ignoreEvent(roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onReadMarkerEvent(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onReadMarkerEvent " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnReadMarkerEvent(roomId, ignoreEvent(roomId)); } - @Override public void onRoomFlush(final String roomId) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onRoomFlush(roomId); - } - - if (ignoreEvent(roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onRoomFlush(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomFlush " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnRoomFlush(roomId, ignoreEvent(roomId)); } - @Override public void onIgnoredUsersListUpdate() { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onIgnoredUsersListUpdate(); - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onIgnoredUsersListUpdate(); - } catch (Exception e) { - Log.e(LOG_TAG, "onIgnoredUsersListUpdate " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnIgnoredUsersListUpdate(); } - @Override public void onToDeviceEvent(final Event event) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onToDeviceEvent(event); - } - - if (ignoreEvent(event.roomId)) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onToDeviceEvent(event); - } catch (Exception e) { - Log.e(LOG_TAG, "OnToDeviceEvent " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnToDeviceEvent(event, ignoreEvent(event.roomId)); } - @Override public void onDirectMessageChatRoomsListUpdate() { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onDirectMessageChatRoomsListUpdate(); - } catch (Exception e) { - Log.e(LOG_TAG, "onDirectMessageChatRoomsListUpdate " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnDirectMessageChatRoomsListUpdate(); } - @Override public void onEventDecrypted(final Event event) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onEventDecrypted(event); - } catch (Exception e) { - Log.e(LOG_TAG, "onDecryptedEvent " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnEventDecrypted(event); } - - @Override public void onNewGroupInvitation(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onNewGroupInvitation(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onNewGroupInvitation " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnNewGroupInvitation(groupId); } - @Override public void onJoinGroup(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onJoinGroup(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onJoinGroup " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnJoinGroup(groupId); } - @Override public void onLeaveGroup(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onLeaveGroup(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onLeaveGroup " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnLeaveGroup(groupId); } - @Override public void onGroupProfileUpdate(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onGroupProfileUpdate(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onGroupProfileUpdate " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnGroupProfileUpdate(groupId); } - @Override public void onGroupRoomsListUpdate(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onGroupRoomsListUpdate(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onGroupRoomsListUpdate " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnGroupRoomsListUpdate(groupId); } - @Override public void onGroupUsersListUpdate(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onGroupUsersListUpdate(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onGroupUsersListUpdate " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnGroupUsersListUpdate(groupId); } - @Override public void onGroupInvitedUsersListUpdate(final String groupId) { - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onGroupInvitedUsersListUpdate(groupId); - } catch (Exception e) { - Log.e(LOG_TAG, "onGroupInvitedUsersListUpdate " + e.getMessage(), e); - } - } - } - }); + mMxEventDispatcher.dispatchOnGroupInvitedUsersListUpdate(groupId); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java new file mode 100644 index 000000000..381bced16 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java @@ -0,0 +1,836 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk; + +import android.os.Looper; + +import org.matrix.androidsdk.data.MyUser; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.listeners.IMXEventListener; +import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.rest.model.MatrixError; +import org.matrix.androidsdk.rest.model.User; +import org.matrix.androidsdk.rest.model.bingrules.BingRule; +import org.matrix.androidsdk.util.Log; +import org.matrix.androidsdk.util.MXOsHandler; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Dispatcher for MXDataHandler + * This class store a list of listener and dispatch event to every listener on the Ui Thread + */ +/* package */ class MxEventDispatcher { + private static final String LOG_TAG = MxEventDispatcher.class.getSimpleName(); + + private final MXOsHandler mUiHandler; + + private IMXEventListener mCryptoEventsListener = null; + private final Set mEventListeners = new HashSet<>(); + + MxEventDispatcher() { + mUiHandler = new MXOsHandler(Looper.getMainLooper()); + } + + /* ========================================================================================== + * Public utilities + * ========================================================================================== */ + + /** + * Set the crypto events listener + * + * @param listener the listener + */ + public void setCryptoEventsListener(IMXEventListener listener) { + mCryptoEventsListener = listener; + } + + /** + * Add a listener to the listeners list. + * + * @param listener the listener to add. + */ + public void addListener(IMXEventListener listener) { + mEventListeners.add(listener); + } + + /** + * Remove a listener from the listeners list. + * + * @param listener to remove. + */ + public void removeListener(IMXEventListener listener) { + mEventListeners.remove(listener); + } + + /** + * Remove any listener + */ + public void clearListeners() { + mEventListeners.clear(); + } + + /* ========================================================================================== + * Dispatchers + * ========================================================================================== */ + + public void dispatchOnStoreReady() { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onStoreReady(); + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onStoreReady(); + } catch (Exception e) { + Log.e(LOG_TAG, "onStoreReady " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnAccountInfoUpdate(final MyUser myUser) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onAccountInfoUpdate(myUser); + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onAccountInfoUpdate(myUser); + } catch (Exception e) { + Log.e(LOG_TAG, "onAccountInfoUpdate " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnPresenceUpdate(final Event event, final User user) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onPresenceUpdate(event, user); + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onPresenceUpdate(event, user); + } catch (Exception e) { + Log.e(LOG_TAG, "onPresenceUpdate " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnLiveEvent(final Event event, final RoomState roomState) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onLiveEvent(event, roomState); + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onLiveEvent(event, roomState); + } catch (Exception e) { + Log.e(LOG_TAG, "onLiveEvent " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnLiveEventsChunkProcessed(final String startToken, final String toToken) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onLiveEventsChunkProcessed(startToken, toToken); + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onLiveEventsChunkProcessed(startToken, toToken); + } catch (Exception e) { + Log.e(LOG_TAG, "onLiveEventsChunkProcessed " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnBingEvent(final Event event, final RoomState roomState, final BingRule bingRule, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onBingEvent(event, roomState, bingRule); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onBingEvent(event, roomState, bingRule); + } catch (Exception e) { + Log.e(LOG_TAG, "onBingEvent " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnEventSentStateUpdated(final Event event, boolean ignoreEvent) { + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onEventSentStateUpdated(event); + } catch (Exception e) { + Log.e(LOG_TAG, "onEventSentStateUpdated " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnEventSent(final Event event, final String prevEventId, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onEventSent(event, prevEventId); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onEventSent(event, prevEventId); + } catch (Exception e) { + Log.e(LOG_TAG, "onEventSent " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnBingRulesUpdate() { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onBingRulesUpdate(); + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onBingRulesUpdate(); + } catch (Exception e) { + Log.e(LOG_TAG, "onBingRulesUpdate " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnInitialSyncComplete(final String toToken) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onInitialSyncComplete(toToken); + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onInitialSyncComplete(toToken); + } catch (Exception e) { + Log.e(LOG_TAG, "onInitialSyncComplete " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnCryptoSyncComplete() { + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onCryptoSyncComplete(); + } catch (Exception e) { + Log.e(LOG_TAG, "OnCryptoSyncComplete " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnSyncError(final MatrixError matrixError) { + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onSyncError(matrixError); + } catch (Exception e) { + Log.e(LOG_TAG, "onSyncError " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnNewRoom(final String roomId, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onNewRoom(roomId); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onNewRoom(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onNewRoom " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnJoinRoom(final String roomId, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onJoinRoom(roomId); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onJoinRoom(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onJoinRoom " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnRoomInitialSyncComplete(final String roomId, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onRoomInitialSyncComplete(roomId); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onRoomInitialSyncComplete(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onRoomInitialSyncComplete " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnRoomInternalUpdate(final String roomId, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onRoomInternalUpdate(roomId); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onRoomInternalUpdate(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onRoomInternalUpdate " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnLeaveRoom(final String roomId, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onLeaveRoom(roomId); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onLeaveRoom(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onLeaveRoom " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnRoomKick(final String roomId, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onRoomKick(roomId); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onRoomKick(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onRoomKick " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnReceiptEvent(final String roomId, final List senderIds, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onReceiptEvent(roomId, senderIds); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onReceiptEvent(roomId, senderIds); + } catch (Exception e) { + Log.e(LOG_TAG, "onReceiptEvent " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnRoomTagEvent(final String roomId, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onRoomTagEvent(roomId); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onRoomTagEvent(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onRoomTagEvent " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnReadMarkerEvent(final String roomId, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onReadMarkerEvent(roomId); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onReadMarkerEvent(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onReadMarkerEvent " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnRoomFlush(final String roomId, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onRoomFlush(roomId); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onRoomFlush(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onRoomFlush " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnIgnoredUsersListUpdate() { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onIgnoredUsersListUpdate(); + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onIgnoredUsersListUpdate(); + } catch (Exception e) { + Log.e(LOG_TAG, "onIgnoredUsersListUpdate " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnToDeviceEvent(final Event event, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onToDeviceEvent(event); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onToDeviceEvent(event); + } catch (Exception e) { + Log.e(LOG_TAG, "OnToDeviceEvent " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnDirectMessageChatRoomsListUpdate() { + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onDirectMessageChatRoomsListUpdate(); + } catch (Exception e) { + Log.e(LOG_TAG, "onDirectMessageChatRoomsListUpdate " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnEventDecrypted(final Event event) { + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onEventDecrypted(event); + } catch (Exception e) { + Log.e(LOG_TAG, "onDecryptedEvent " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnNewGroupInvitation(final String groupId) { + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onNewGroupInvitation(groupId); + } catch (Exception e) { + Log.e(LOG_TAG, "onNewGroupInvitation " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnJoinGroup(final String groupId) { + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onJoinGroup(groupId); + } catch (Exception e) { + Log.e(LOG_TAG, "onJoinGroup " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnLeaveGroup(final String groupId) { + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onLeaveGroup(groupId); + } catch (Exception e) { + Log.e(LOG_TAG, "onLeaveGroup " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnGroupProfileUpdate(final String groupId) { + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onGroupProfileUpdate(groupId); + } catch (Exception e) { + Log.e(LOG_TAG, "onGroupProfileUpdate " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnGroupRoomsListUpdate(final String groupId) { + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onGroupRoomsListUpdate(groupId); + } catch (Exception e) { + Log.e(LOG_TAG, "onGroupRoomsListUpdate " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnGroupUsersListUpdate(final String groupId) { + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onGroupUsersListUpdate(groupId); + } catch (Exception e) { + Log.e(LOG_TAG, "onGroupUsersListUpdate " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnGroupInvitedUsersListUpdate(final String groupId) { + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onGroupInvitedUsersListUpdate(groupId); + } catch (Exception e) { + Log.e(LOG_TAG, "onGroupInvitedUsersListUpdate " + e.getMessage(), e); + } + } + } + }); + } + + public void dispatchOnNotificationCountUpdate(final String roomId, boolean ignoreEvent) { + if (null != mCryptoEventsListener) { + mCryptoEventsListener.onNotificationCountUpdate(roomId); + } + + if (ignoreEvent) { + return; + } + + final List eventListeners = getListenersSnapshot(); + + mUiHandler.post(new Runnable() { + @Override + public void run() { + for (IMXEventListener listener : eventListeners) { + try { + listener.onNotificationCountUpdate(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onNotificationCountUpdate " + e.getMessage(), e); + } + } + } + }); + } + + /* ========================================================================================== + * Private + * ========================================================================================== */ + + /** + * @return the current MXEvents listeners. + */ + private List getListenersSnapshot() { + List eventListeners; + + synchronized (this) { + eventListeners = new ArrayList<>(mEventListeners); + } + + return eventListeners; + } +} From 688f318b5feb6badc619284084f2265b8458797e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 10:41:12 +0200 Subject: [PATCH 134/236] Fix a potential memory leak when crypto is closed --- .../main/java/org/matrix/androidsdk/MXDataHandler.java | 6 +++--- .../java/org/matrix/androidsdk/MxEventDispatcher.java | 9 ++++++--- .../main/java/org/matrix/androidsdk/crypto/MXCrypto.java | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index e57df0bdd..3deca52af 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -591,11 +591,11 @@ public BingRulesManager getBingRulesManager() { } /** - * Set the crypto events listener + * Set the crypto events listener, or remove it * - * @param listener the listener + * @param listener the listener or null to remove the listener */ - public void setCryptoEventsListener(IMXEventListener listener) { + public void setCryptoEventsListener(@Nullable IMXEventListener listener) { mMxEventDispatcher.setCryptoEventsListener(listener); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java index 381bced16..fe51b6959 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java @@ -17,6 +17,7 @@ package org.matrix.androidsdk; import android.os.Looper; +import android.support.annotation.Nullable; import org.matrix.androidsdk.data.MyUser; import org.matrix.androidsdk.data.RoomState; @@ -42,7 +43,9 @@ private final MXOsHandler mUiHandler; + @Nullable private IMXEventListener mCryptoEventsListener = null; + private final Set mEventListeners = new HashSet<>(); MxEventDispatcher() { @@ -54,11 +57,11 @@ * ========================================================================================== */ /** - * Set the crypto events listener + * Set the crypto events listener, or remove it * - * @param listener the listener + * @param listener the listener or null to remove the listener */ - public void setCryptoEventsListener(IMXEventListener listener) { + public void setCryptoEventsListener(@Nullable IMXEventListener listener) { mCryptoEventsListener = listener; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java index dcbbd2963..4f27cddf0 100755 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java @@ -547,7 +547,7 @@ public void onUnexpectedError(Exception e) { */ public void close() { if (null != mEncryptingHandlerThread) { - mSession.getDataHandler().removeListener(mEventListener); + mSession.getDataHandler().setCryptoEventsListener(null); getEncryptingThreadHandler().post(new Runnable() { @Override public void run() { From 26d6a1342e56ab2483b84d427a4ac57494d73956 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 10:45:54 +0200 Subject: [PATCH 135/236] Remove unnecessary call to crypto event listener methods --- .../matrix/androidsdk/MxEventDispatcher.java | 80 ------------------- .../matrix/androidsdk/crypto/MXCrypto.java | 4 + 2 files changed, 4 insertions(+), 80 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java index fe51b6959..9dbd0ea10 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java @@ -95,10 +95,6 @@ public void clearListeners() { * ========================================================================================== */ public void dispatchOnStoreReady() { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onStoreReady(); - } - final List eventListeners = getListenersSnapshot(); mUiHandler.post(new Runnable() { @@ -116,10 +112,6 @@ public void run() { } public void dispatchOnAccountInfoUpdate(final MyUser myUser) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onAccountInfoUpdate(myUser); - } - final List eventListeners = getListenersSnapshot(); mUiHandler.post(new Runnable() { @@ -137,10 +129,6 @@ public void run() { } public void dispatchOnPresenceUpdate(final Event event, final User user) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onPresenceUpdate(event, user); - } - final List eventListeners = getListenersSnapshot(); mUiHandler.post(new Runnable() { @@ -179,10 +167,6 @@ public void run() { } public void dispatchOnLiveEventsChunkProcessed(final String startToken, final String toToken) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onLiveEventsChunkProcessed(startToken, toToken); - } - final List eventListeners = getListenersSnapshot(); mUiHandler.post(new Runnable() { @@ -200,10 +184,6 @@ public void run() { } public void dispatchOnBingEvent(final Event event, final RoomState roomState, final BingRule bingRule, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onBingEvent(event, roomState, bingRule); - } - if (ignoreEvent) { return; } @@ -246,10 +226,6 @@ public void run() { } public void dispatchOnEventSent(final Event event, final String prevEventId, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onEventSent(event, prevEventId); - } - if (ignoreEvent) { return; } @@ -271,10 +247,6 @@ public void run() { } public void dispatchOnBingRulesUpdate() { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onBingRulesUpdate(); - } - final List eventListeners = getListenersSnapshot(); mUiHandler.post(new Runnable() { @@ -292,10 +264,6 @@ public void run() { } public void dispatchOnInitialSyncComplete(final String toToken) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onInitialSyncComplete(toToken); - } - final List eventListeners = getListenersSnapshot(); mUiHandler.post(new Runnable() { @@ -347,10 +315,6 @@ public void run() { } public void dispatchOnNewRoom(final String roomId, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onNewRoom(roomId); - } - if (ignoreEvent) { return; } @@ -372,10 +336,6 @@ public void run() { } public void dispatchOnJoinRoom(final String roomId, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onJoinRoom(roomId); - } - if (ignoreEvent) { return; } @@ -397,10 +357,6 @@ public void run() { } public void dispatchOnRoomInitialSyncComplete(final String roomId, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onRoomInitialSyncComplete(roomId); - } - if (ignoreEvent) { return; } @@ -422,10 +378,6 @@ public void run() { } public void dispatchOnRoomInternalUpdate(final String roomId, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onRoomInternalUpdate(roomId); - } - if (ignoreEvent) { return; } @@ -447,10 +399,6 @@ public void run() { } public void dispatchOnLeaveRoom(final String roomId, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onLeaveRoom(roomId); - } - if (ignoreEvent) { return; } @@ -472,10 +420,6 @@ public void run() { } public void dispatchOnRoomKick(final String roomId, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onRoomKick(roomId); - } - if (ignoreEvent) { return; } @@ -497,10 +441,6 @@ public void run() { } public void dispatchOnReceiptEvent(final String roomId, final List senderIds, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onReceiptEvent(roomId, senderIds); - } - if (ignoreEvent) { return; } @@ -522,10 +462,6 @@ public void run() { } public void dispatchOnRoomTagEvent(final String roomId, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onRoomTagEvent(roomId); - } - if (ignoreEvent) { return; } @@ -547,10 +483,6 @@ public void run() { } public void dispatchOnReadMarkerEvent(final String roomId, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onReadMarkerEvent(roomId); - } - if (ignoreEvent) { return; } @@ -572,10 +504,6 @@ public void run() { } public void dispatchOnRoomFlush(final String roomId, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onRoomFlush(roomId); - } - if (ignoreEvent) { return; } @@ -597,10 +525,6 @@ public void run() { } public void dispatchOnIgnoredUsersListUpdate() { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onIgnoredUsersListUpdate(); - } - final List eventListeners = getListenersSnapshot(); mUiHandler.post(new Runnable() { @@ -796,10 +720,6 @@ public void run() { } public void dispatchOnNotificationCountUpdate(final String roomId, boolean ignoreEvent) { - if (null != mCryptoEventsListener) { - mCryptoEventsListener.onNotificationCountUpdate(roomId); - } - if (ignoreEvent) { return; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java index 4f27cddf0..99de55cc9 100755 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java @@ -146,6 +146,10 @@ public void onNetworkConnectionUpdate(boolean isConnected) { }; private final MXEventListener mEventListener = new MXEventListener() { + /* + * Warning, if a method is added here, the corresponding call has to be also added in MxEventDispatcher + */ + @Override public void onToDeviceEvent(Event event) { MXCrypto.this.onToDeviceEvent(event); From 73b613b5bcff75fae7cb4022357ff7e588f32f55 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 10:50:09 +0200 Subject: [PATCH 136/236] RoomSummary contains the user membership (instead of booleans) --- .../org/matrix/androidsdk/data/RoomSummary.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index e25cd1c70..a20d8e14b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -80,8 +80,7 @@ public class RoomSummary implements java.io.Serializable { private String mUserId = null; // Info from sync, depending on the room position in the sync - private boolean mIsInInvitedRooms = false; - private boolean mIsInJoinedRooms = false; + private String mUserMembership; /** * Tell if the room is a user conference user one @@ -287,30 +286,28 @@ public RoomState getLatestRoomState() { * @return true if the current user is invited */ public boolean isInvited() { - return mIsInInvitedRooms; + return RoomMember.MEMBERSHIP_INVITE.equals(mUserMembership); } /** * To call when the room is in the invited section of the sync response */ public void setIsInvited() { - mIsInInvitedRooms = true; - mIsInJoinedRooms = false; + mUserMembership = RoomMember.MEMBERSHIP_INVITE; } /** * To call when the room is in the joined section of the sync response */ public void setIsJoined() { - mIsInInvitedRooms = false; - mIsInJoinedRooms = true; + mUserMembership = RoomMember.MEMBERSHIP_JOIN; } /** * @return true if the current user is invited */ public boolean isJoined() { - return mIsInJoinedRooms; + return RoomMember.MEMBERSHIP_JOIN.equals(mUserMembership); } /** From 33529c61958e1a32cddbfdcdcaaa09f906367b3f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 11:17:33 +0200 Subject: [PATCH 137/236] Create a new interface for request wich cannot fail --- .../androidsdk/rest/callback/ApiCallback.java | 17 +++++------- .../rest/callback/ApiSuccessCallback.java | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiSuccessCallback.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiCallback.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiCallback.java index 6a4028ffd..5a3afab3e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiCallback.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiCallback.java @@ -1,12 +1,13 @@ -/* +/* * Copyright 2014 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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. @@ -20,12 +21,6 @@ * * @param the type of information to return on success */ -public interface ApiCallback extends ApiFailureCallback { +public interface ApiCallback extends ApiSuccessCallback, ApiFailureCallback { - /** - * Called if the API call is successful. - * - * @param info the returned information - */ - void onSuccess(T info); } \ No newline at end of file diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiSuccessCallback.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiSuccessCallback.java new file mode 100644 index 000000000..c1f92639d --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiSuccessCallback.java @@ -0,0 +1,26 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.callback; + +public interface ApiSuccessCallback { + /** + * Called if the result is successful. + * + * @param info the returned information + */ + void onSuccess(T info); +} From efad24d4ef976393bdd598bb33095a665b24efc9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 11:42:41 +0200 Subject: [PATCH 138/236] Create class TokensChunkEvents --- .../org/matrix/androidsdk/MXDataHandler.java | 6 +-- .../matrix/androidsdk/data/DataRetriever.java | 52 +++++++++---------- .../matrix/androidsdk/data/EventTimeline.java | 10 ++-- .../java/org/matrix/androidsdk/data/Room.java | 8 +-- .../androidsdk/data/store/IMXStore.java | 16 +++--- .../androidsdk/data/store/MXFileStore.java | 6 +-- .../androidsdk/data/store/MXMemoryStore.java | 22 ++++---- .../matrix/androidsdk/rest/api/RoomsApi.java | 20 +++---- .../rest/client/RoomsRestClient.java | 10 ++-- .../androidsdk/rest/model/ChunkResponse.java | 25 +++++++++ .../rest/model/TokensChunkEvents.java | 20 +++++++ .../rest/model/TokensChunkResponse.java | 6 +-- .../rest/model/sync/RoomResponse.java | 5 +- 13 files changed, 127 insertions(+), 79 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ChunkResponse.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/TokensChunkEvents.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 3deca52af..3970a2c04 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -59,7 +59,7 @@ import org.matrix.androidsdk.rest.model.ReceiptData; import org.matrix.androidsdk.rest.model.RoomAliasDescription; import org.matrix.androidsdk.rest.model.RoomMember; -import org.matrix.androidsdk.rest.model.TokensChunkResponse; +import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.bingrules.BingRule; import org.matrix.androidsdk.rest.model.bingrules.Condition; @@ -951,9 +951,9 @@ public void onSuccess(RoomAliasDescription info) { */ public void getMembersAsync(final String roomId, final ApiCallback> callback) { mRoomsRestClient.getRoomMembers(roomId, getStore().getEventStreamToken(), null, RoomMember.MEMBERSHIP_LEAVE, - new SimpleApiCallback>(callback) { + new SimpleApiCallback(callback) { @Override - public void onSuccess(TokensChunkResponse info) { + public void onSuccess(TokensChunkEvents info) { Room room = getRoom(roomId); if (info.chunk != null) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java index 6123e5f48..7d3acc3db 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java @@ -25,7 +25,7 @@ import org.matrix.androidsdk.rest.client.RoomsRestClient; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.MatrixError; -import org.matrix.androidsdk.rest.model.TokensChunkResponse; +import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.util.FilterUtil; import org.matrix.androidsdk.util.Log; @@ -120,7 +120,7 @@ public void backPaginate(final IMXStore store, final String token, final int limit, final boolean withLazyLoading, - final ApiCallback> callback) { + final ApiCallback callback) { // reach the marker end if (TextUtils.equals(token, Event.PAGINATE_BACK_TOKEN_END)) { // nothing more to provide @@ -134,7 +134,7 @@ public void backPaginate(final IMXStore store, public void run() { handler.postDelayed(new Runnable() { public void run() { - callback.onSuccess(new TokensChunkResponse()); + callback.onSuccess(new TokensChunkEvents()); } }, 0); } @@ -147,13 +147,13 @@ public void run() { Log.d(LOG_TAG, "## backPaginate() : starts for roomId " + roomId); - TokensChunkResponse storageResponse = store.getEarlierMessages(roomId, token, limit); + TokensChunkEvents storageResponse = store.getEarlierMessages(roomId, token, limit); putPendingToken(mPendingBackwardRequestTokenByRoomId, roomId, token); if (storageResponse != null) { final android.os.Handler handler = new android.os.Handler(Looper.getMainLooper()); - final TokensChunkResponse fStorageResponse = storageResponse; + final TokensChunkEvents fStorageResponse = storageResponse; Log.d(LOG_TAG, "## backPaginate() : some data has been retrieved into the local storage (" + fStorageResponse.chunk.size() + " events)"); @@ -183,9 +183,9 @@ public void run() { Log.d(LOG_TAG, "## backPaginate() : trigger a remote request"); mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, limit, FilterUtil.createRoomEventFilter(withLazyLoading), - new SimpleApiCallback>(callback) { + new SimpleApiCallback(callback) { @Override - public void onSuccess(TokensChunkResponse events) { + public void onSuccess(TokensChunkEvents tokensChunkEvents) { String expectedToken = getPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); Log.d(LOG_TAG, "## backPaginate() succeeds : roomId " + roomId + " token " + token + " vs " + expectedToken); @@ -196,27 +196,27 @@ public void onSuccess(TokensChunkResponse events) { // Watch for the one event overlap Event oldestEvent = store.getOldestEvent(roomId); - if (events.chunk.size() != 0) { - events.chunk.get(0).mToken = events.start; + if (tokensChunkEvents.chunk.size() != 0) { + tokensChunkEvents.chunk.get(0).mToken = tokensChunkEvents.start; // there is no more data on server side - if (null == events.end) { - events.end = Event.PAGINATE_BACK_TOKEN_END; + if (null == tokensChunkEvents.end) { + tokensChunkEvents.end = Event.PAGINATE_BACK_TOKEN_END; } - events.chunk.get(events.chunk.size() - 1).mToken = events.end; + tokensChunkEvents.chunk.get(tokensChunkEvents.chunk.size() - 1).mToken = tokensChunkEvents.end; - Event firstReturnedEvent = events.chunk.get(0); + Event firstReturnedEvent = tokensChunkEvents.chunk.get(0); if ((oldestEvent != null) && (firstReturnedEvent != null) && TextUtils.equals(oldestEvent.eventId, firstReturnedEvent.eventId)) { - events.chunk.remove(0); + tokensChunkEvents.chunk.remove(0); } - store.storeRoomEvents(roomId, events, EventTimeline.Direction.BACKWARDS); + store.storeRoomEvents(roomId, tokensChunkEvents, EventTimeline.Direction.BACKWARDS); } - Log.d(LOG_TAG, "## backPaginate() succeed : roomId " + roomId + " token " + token + " got " + events.chunk.size()); - callback.onSuccess(events); + Log.d(LOG_TAG, "## backPaginate() succeed : roomId " + roomId + " token " + token + " got " + tokensChunkEvents.chunk.size()); + callback.onSuccess(tokensChunkEvents); } } @@ -279,18 +279,18 @@ private void forwardPaginate(final IMXStore store, final String roomId, final String token, final boolean withLazyLoading, - final ApiCallback> callback) { + final ApiCallback callback) { putPendingToken(mPendingForwardRequestTokenByRoomId, roomId, token); mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.FORWARDS, RoomsRestClient.DEFAULT_MESSAGES_PAGINATION_LIMIT, FilterUtil.createRoomEventFilter(withLazyLoading), - new SimpleApiCallback>(callback) { + new SimpleApiCallback(callback) { @Override - public void onSuccess(TokensChunkResponse events) { + public void onSuccess(TokensChunkEvents tokensChunkEvents) { if (TextUtils.equals(getPendingToken(mPendingForwardRequestTokenByRoomId, roomId), token)) { clearPendingToken(mPendingForwardRequestTokenByRoomId, roomId); - store.storeRoomEvents(roomId, events, EventTimeline.Direction.FORWARDS); - callback.onSuccess(events); + store.storeRoomEvents(roomId, tokensChunkEvents, EventTimeline.Direction.FORWARDS); + callback.onSuccess(tokensChunkEvents); } } }); @@ -311,7 +311,7 @@ public void paginate(final IMXStore store, final String token, final EventTimeline.Direction direction, final boolean withLazyLoading, - final ApiCallback> callback) { + final ApiCallback callback) { if (direction == EventTimeline.Direction.BACKWARDS) { backPaginate(store, roomId, token, RoomsRestClient.DEFAULT_MESSAGES_PAGINATION_LIMIT, withLazyLoading, callback); } else { @@ -333,13 +333,13 @@ public void requestServerRoomHistory(final String roomId, final String token, final int paginationCount, final boolean withLazyLoading, - final ApiCallback> callback) { + final ApiCallback callback) { putPendingToken(mPendingRemoteRequestTokenByRoomId, roomId, token); mRestClient.getRoomMessagesFrom(roomId, token, EventTimeline.Direction.BACKWARDS, paginationCount, FilterUtil.createRoomEventFilter(withLazyLoading), - new SimpleApiCallback>(callback) { + new SimpleApiCallback(callback) { @Override - public void onSuccess(TokensChunkResponse info) { + public void onSuccess(TokensChunkEvents info) { if (TextUtils.equals(getPendingToken(mPendingRemoteRequestTokenByRoomId, roomId), token)) { if (info.chunk.size() != 0) { info.chunk.get(0).mToken = info.start; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index d6360f707..06631f316 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -36,7 +36,7 @@ import org.matrix.androidsdk.rest.model.MatrixError; import org.matrix.androidsdk.rest.model.ReceiptData; import org.matrix.androidsdk.rest.model.RoomMember; -import org.matrix.androidsdk.rest.model.TokensChunkResponse; +import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.rest.model.bingrules.BingRule; import org.matrix.androidsdk.rest.model.sync.InvitedRoomSync; import org.matrix.androidsdk.rest.model.sync.RoomSync; @@ -1246,9 +1246,9 @@ public void run() { } mDataHandler.getDataRetriever().backPaginate(mStore, mRoomId, getBackState().getToken(), eventCount, mDataHandler.isLazyLoadingEnabled(), - new SimpleApiCallback>(callback) { + new SimpleApiCallback(callback) { @Override - public void onSuccess(TokensChunkResponse response) { + public void onSuccess(TokensChunkEvents response) { if (mDataHandler.isAlive()) { if (null != response.chunk) { @@ -1337,9 +1337,9 @@ public boolean forwardPaginate(final ApiCallback callback) { mIsForwardPaginating = true; mDataHandler.getDataRetriever().paginate(mStore, mRoomId, mForwardsPaginationToken, Direction.FORWARDS, mDataHandler.isLazyLoadingEnabled(), - new SimpleApiCallback>(callback) { + new SimpleApiCallback(callback) { @Override - public void onSuccess(TokensChunkResponse response) { + public void onSuccess(TokensChunkEvents response) { if (mDataHandler.isAlive()) { Log.d(LOG_TAG, "forwardPaginate : " + response.chunk.size() + " are retrieved."); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 81b7990f0..c674f0cbb 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -59,7 +59,7 @@ import org.matrix.androidsdk.rest.model.PowerLevels; import org.matrix.androidsdk.rest.model.ReceiptData; import org.matrix.androidsdk.rest.model.RoomMember; -import org.matrix.androidsdk.rest.model.TokensChunkResponse; +import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.message.FileInfo; import org.matrix.androidsdk.rest.model.message.FileMessage; @@ -397,12 +397,12 @@ public void storeOutgoingEvent(Event event) { */ public void requestServerRoomHistory(final String token, final int paginationCount, - final ApiCallback> callback) { + final ApiCallback callback) { mDataHandler.getDataRetriever() .requestServerRoomHistory(getRoomId(), token, paginationCount, mDataHandler.isLazyLoadingEnabled(), - new SimpleApiCallback>(callback) { + new SimpleApiCallback(callback) { @Override - public void onSuccess(TokensChunkResponse info) { + public void onSuccess(TokensChunkEvents info) { callback.onSuccess(info); } }); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java index a9a1f5900..ae32c0cca 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java @@ -30,7 +30,7 @@ import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.ReceiptData; import org.matrix.androidsdk.rest.model.RoomMember; -import org.matrix.androidsdk.rest.model.TokensChunkResponse; +import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.group.Group; import org.matrix.androidsdk.rest.model.pid.ThirdPartyIdentifier; @@ -257,11 +257,11 @@ public interface IMXStore { /** * Store a block of room events either live or from pagination. * - * @param roomId the room id - * @param eventsResponse The events to be stored. - * @param direction the direction; forwards for live, backwards for pagination + * @param roomId the room id + * @param tokensChunkEvents the events to be stored. + * @param direction the direction; forwards for live, backwards for pagination */ - void storeRoomEvents(String roomId, TokensChunkResponse eventsResponse, EventTimeline.Direction direction); + void storeRoomEvents(String roomId, TokensChunkEvents tokensChunkEvents, EventTimeline.Direction direction); /** * Store the back token of a room. @@ -348,7 +348,7 @@ public interface IMXStore { * @param limit the maximum number of messages to retrieve. * @return A collection of events. null if there is no cached event. */ - TokensChunkResponse getEarlierMessages(final String roomId, final String fromToken, final int limit); + TokensChunkEvents getEarlierMessages(final String roomId, final String fromToken, final int limit); /** * Get the oldest event from the given room (to prevent pagination overlap). @@ -561,6 +561,7 @@ public interface IMXStore { /** * Delete a group + * * @param groupId the group id to delete */ void deleteGroup(String groupId); @@ -580,18 +581,21 @@ public interface IMXStore { /** * Set the URL preview status + * * @param value the URL preview status */ void setURLPreviewEnabled(boolean value); /** * Tells if the global URL preview is enabled. + * * @return true if it is enabled */ boolean isURLPreviewEnabled(); /** * Update the rooms list which don't have URL previews + * * @param roomIds the room ids list */ void setRoomsWithoutURLPreview(Set roomIds); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java index dc10226fd..3d0123cab 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java @@ -33,7 +33,7 @@ import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.ReceiptData; import org.matrix.androidsdk.rest.model.RoomMember; -import org.matrix.androidsdk.rest.model.TokensChunkResponse; +import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.group.Group; import org.matrix.androidsdk.rest.model.pid.ThirdPartyIdentifier; @@ -806,7 +806,7 @@ public void flushRoomEvents(String roomId) { } @Override - public void storeRoomEvents(String roomId, TokensChunkResponse eventsResponse, EventTimeline.Direction direction) { + public void storeRoomEvents(String roomId, TokensChunkEvents tokensChunkEvents, EventTimeline.Direction direction) { boolean canStore = true; // do not flush the room messages file @@ -823,7 +823,7 @@ public void storeRoomEvents(String roomId, TokensChunkResponse eventsResp } } - super.storeRoomEvents(roomId, eventsResponse, direction); + super.storeRoomEvents(roomId, tokensChunkEvents, direction); if (canStore) { mRoomsToCommitForMessages.add(roomId); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java index d751c187e..5b1611015 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java @@ -34,7 +34,7 @@ import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.ReceiptData; import org.matrix.androidsdk.rest.model.RoomMember; -import org.matrix.androidsdk.rest.model.TokensChunkResponse; +import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.group.Group; import org.matrix.androidsdk.rest.model.login.Credentials; @@ -757,7 +757,7 @@ public void flushRoomEvents(String roomId) { } @Override - public void storeRoomEvents(String roomId, TokensChunkResponse eventsResponse, EventTimeline.Direction direction) { + public void storeRoomEvents(String roomId, TokensChunkEvents tokensChunkEvents, EventTimeline.Direction direction) { try { if (null != roomId) { synchronized (mRoomEventsLock) { @@ -768,9 +768,9 @@ public void storeRoomEvents(String roomId, TokensChunkResponse eventsResp } if (direction == EventTimeline.Direction.FORWARDS) { - mRoomTokens.put(roomId, eventsResponse.start); + mRoomTokens.put(roomId, tokensChunkEvents.start); - for (Event event : eventsResponse.chunk) { + for (Event event : tokensChunkEvents.chunk) { events.put(event.eventId, event); } } else { // BACKWARD @@ -779,19 +779,19 @@ public void storeRoomEvents(String roomId, TokensChunkResponse eventsResp // no stored events if (events.size() == 0) { // insert the catchup events in reverse order - for (int index = eventsResponse.chunk.size() - 1; index >= 0; index--) { - Event backEvent = eventsResponse.chunk.get(index); + for (int index = tokensChunkEvents.chunk.size() - 1; index >= 0; index--) { + Event backEvent = tokensChunkEvents.chunk.get(index); events.put(backEvent.eventId, backEvent); } // define a token - mRoomTokens.put(roomId, eventsResponse.start); + mRoomTokens.put(roomId, tokensChunkEvents.start); } else { LinkedHashMap events2 = new LinkedHashMap<>(); // insert the catchup events in reverse order - for (int index = eventsResponse.chunk.size() - 1; index >= 0; index--) { - Event backEvent = eventsResponse.chunk.get(index); + for (int index = tokensChunkEvents.chunk.size() - 1; index >= 0; index--) { + Event backEvent = tokensChunkEvents.chunk.get(index); events2.put(backEvent.eventId, backEvent); } @@ -925,7 +925,7 @@ public Collection getRoomMessages(final String roomId) { } @Override - public TokensChunkResponse getEarlierMessages(final String roomId, final String fromToken, final int limit) { + public TokensChunkEvents getEarlierMessages(final String roomId, final String fromToken, final int limit) { // For now, we return everything we have for the original null token request // For older requests (providing a token), returning null for now if (null != roomId) { @@ -952,7 +952,7 @@ public TokensChunkResponse getEarlierMessages(final String roomId, final // search from the latest to the oldest events Collections.reverse(eventsList); - TokensChunkResponse response = new TokensChunkResponse<>(); + TokensChunkEvents response = new TokensChunkEvents(); // start the latest event and there is enough events to provide to the caller ? if ((null == fromToken) && (eventsList.size() <= limit)) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index f796d219c..709476ef3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -33,7 +33,7 @@ import org.matrix.androidsdk.rest.model.ReportContentParams; import org.matrix.androidsdk.rest.model.RoomAliasDescription; import org.matrix.androidsdk.rest.model.RoomMember; -import org.matrix.androidsdk.rest.model.TokensChunkResponse; +import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.rest.model.Typing; import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.message.Message; @@ -238,11 +238,11 @@ Call sendStateEvent(@Path("roomId") String roomId, * @param filter A JSON RoomEventFilter to filter returned events with. Optional. */ @GET("rooms/{roomId}/messages") - Call> getRoomMessagesFrom(@Path("roomId") String roomId, - @Query("from") String from, - @Query("dir") String dir, - @Query("limit") int limit, - @Nullable @Query("filter") String filter); + Call getRoomMessagesFrom(@Path("roomId") String roomId, + @Query("from") String from, + @Query("dir") String dir, + @Query("limit") int limit, + @Nullable @Query("filter") String filter); /** * Get the initial information concerning a specific room. @@ -402,8 +402,8 @@ Call updateAccountData(@Path("userId") String userId, * @param notMembership to exclude one type of membership (optional) */ @GET("rooms/{roomId}/members") - Call> getMembers(@Path("roomId") String roomId, - @Nullable @Query("at") String syncToken, - @Nullable @Query("membership") String membership, - @Nullable @Query("not_membership") String notMembership); + Call getMembers(@Path("roomId") String roomId, + @Nullable @Query("at") String syncToken, + @Nullable @Query("membership") String membership, + @Nullable @Query("not_membership") String notMembership); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index b5209f601..8841b5fda 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -43,7 +43,7 @@ import org.matrix.androidsdk.rest.model.ReportContentParams; import org.matrix.androidsdk.rest.model.RoomAliasDescription; import org.matrix.androidsdk.rest.model.RoomMember; -import org.matrix.androidsdk.rest.model.TokensChunkResponse; +import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.rest.model.Typing; import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.filter.RoomEventFilter; @@ -145,11 +145,11 @@ public void getRoomMessagesFrom(final String roomId, final EventTimeline.Direction direction, final int limit, @Nullable final RoomEventFilter roomEventFilter, - final ApiCallback> callback) { + final ApiCallback callback) { final String description = "messagesFrom : roomId " + roomId + " fromToken " + fromToken + "with direction " + direction + " with limit " + limit; mApi.getRoomMessagesFrom(roomId, fromToken, (direction == EventTimeline.Direction.BACKWARDS) ? "b" : "f", limit, toJson(roomEventFilter)) - .enqueue(new RestAdapterCallback>(description, mUnsentEventsManager, callback, + .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { @@ -590,11 +590,11 @@ public void getRoomMembers(final String roomId, @Nullable final String syncToken, @Nullable final String membership, @Nullable final String notMembership, - final ApiCallback> callback) { + final ApiCallback callback) { final String description = "getRoomMembers roomId=" + roomId; mApi.getMembers(roomId, syncToken, membership, notMembership) - .enqueue(new RestAdapterCallback>(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { + .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { getRoomMembers(roomId, syncToken, membership, notMembership, callback); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ChunkResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ChunkResponse.java new file mode 100644 index 000000000..6f4efd263 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ChunkResponse.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model; + +import java.util.List; + +/** + * Class representing an API response with start and end tokens and a generically-typed chunk. + */ +public class ChunkResponse { + public List chunk; +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/TokensChunkEvents.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/TokensChunkEvents.java new file mode 100644 index 000000000..dccb0a537 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/TokensChunkEvents.java @@ -0,0 +1,20 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model; + +public class TokensChunkEvents extends TokensChunkResponse { +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/TokensChunkResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/TokensChunkResponse.java index d12810155..4afb3aab3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/TokensChunkResponse.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/TokensChunkResponse.java @@ -1,5 +1,6 @@ /* * Copyright 2014 OpenMarket Ltd + * Copyright 2018 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,13 +16,10 @@ */ package org.matrix.androidsdk.rest.model; -import java.util.List; - /** * Class representing an API response with start and end tokens and a generically-typed chunk. */ -public class TokensChunkResponse { +public class TokensChunkResponse extends ChunkResponse { public String start; public String end; - public List chunk; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomResponse.java index 3058cb67b..01ef28d19 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomResponse.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomResponse.java @@ -1,5 +1,6 @@ /* * Copyright 2014 OpenMarket Ltd + * Copyright 2018 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +17,7 @@ package org.matrix.androidsdk.rest.model.sync; import org.matrix.androidsdk.rest.model.Event; -import org.matrix.androidsdk.rest.model.TokensChunkResponse; +import org.matrix.androidsdk.rest.model.TokensChunkEvents; import java.util.List; @@ -28,7 +29,7 @@ public class RoomResponse { public String roomId; // The last recent messages of the room. - public TokensChunkResponse messages; + public TokensChunkEvents messages; // The state events. public List state; From 16df5d0fc3c1832259bc220d34b4c516cc877a3e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 11:52:37 +0200 Subject: [PATCH 139/236] Create class ChunkEvents, to use when the chunk is full --- .../org/matrix/androidsdk/MXDataHandler.java | 6 +++--- .../matrix/androidsdk/rest/api/RoomsApi.java | 9 +++++---- .../rest/client/RoomsRestClient.java | 5 +++-- .../androidsdk/rest/model/ChunkEvents.java | 20 +++++++++++++++++++ 4 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ChunkEvents.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 3970a2c04..2505517f1 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -54,12 +54,12 @@ import org.matrix.androidsdk.rest.client.RoomsRestClient; import org.matrix.androidsdk.rest.client.ThirdPidRestClient; import org.matrix.androidsdk.rest.json.ConditionDeserializer; +import org.matrix.androidsdk.rest.model.ChunkEvents; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.MatrixError; import org.matrix.androidsdk.rest.model.ReceiptData; import org.matrix.androidsdk.rest.model.RoomAliasDescription; import org.matrix.androidsdk.rest.model.RoomMember; -import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.bingrules.BingRule; import org.matrix.androidsdk.rest.model.bingrules.Condition; @@ -951,9 +951,9 @@ public void onSuccess(RoomAliasDescription info) { */ public void getMembersAsync(final String roomId, final ApiCallback> callback) { mRoomsRestClient.getRoomMembers(roomId, getStore().getEventStreamToken(), null, RoomMember.MEMBERSHIP_LEAVE, - new SimpleApiCallback(callback) { + new SimpleApiCallback(callback) { @Override - public void onSuccess(TokensChunkEvents info) { + public void onSuccess(ChunkEvents info) { Room room = getRoom(roomId); if (info.chunk != null) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index 709476ef3..593381685 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -24,6 +24,7 @@ import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.rest.model.BannedUser; +import org.matrix.androidsdk.rest.model.ChunkEvents; import org.matrix.androidsdk.rest.model.CreateRoomParams; import org.matrix.androidsdk.rest.model.CreateRoomResponse; import org.matrix.androidsdk.rest.model.CreatedEvent; @@ -402,8 +403,8 @@ Call updateAccountData(@Path("userId") String userId, * @param notMembership to exclude one type of membership (optional) */ @GET("rooms/{roomId}/members") - Call getMembers(@Path("roomId") String roomId, - @Nullable @Query("at") String syncToken, - @Nullable @Query("membership") String membership, - @Nullable @Query("not_membership") String notMembership); + Call getMembers(@Path("roomId") String roomId, + @Nullable @Query("at") String syncToken, + @Nullable @Query("membership") String membership, + @Nullable @Query("not_membership") String notMembership); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index 8841b5fda..79ac34ceb 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -33,6 +33,7 @@ import org.matrix.androidsdk.rest.callback.RestAdapterCallback; import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.model.BannedUser; +import org.matrix.androidsdk.rest.model.ChunkEvents; import org.matrix.androidsdk.rest.model.CreateRoomParams; import org.matrix.androidsdk.rest.model.CreateRoomResponse; import org.matrix.androidsdk.rest.model.CreatedEvent; @@ -590,11 +591,11 @@ public void getRoomMembers(final String roomId, @Nullable final String syncToken, @Nullable final String membership, @Nullable final String notMembership, - final ApiCallback callback) { + final ApiCallback callback) { final String description = "getRoomMembers roomId=" + roomId; mApi.getMembers(roomId, syncToken, membership, notMembership) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { + .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { getRoomMembers(roomId, syncToken, membership, notMembership, callback); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ChunkEvents.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ChunkEvents.java new file mode 100644 index 000000000..4617ac2f6 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/ChunkEvents.java @@ -0,0 +1,20 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model; + +public class ChunkEvents extends ChunkResponse { +} From f4bddf1bf84244d2910280fc12ca63a74274b968 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 12:11:33 +0200 Subject: [PATCH 140/236] Rename 'alias' to 'canonicalAlias' --- .../org/matrix/androidsdk/MXDataHandler.java | 2 +- .../java/org/matrix/androidsdk/data/Room.java | 2 +- .../org/matrix/androidsdk/data/RoomState.java | 29 +++++++++++++------ .../rest/model/group/GroupRoom.java | 4 +-- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 2505517f1..64ef8a1b6 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -900,7 +900,7 @@ public void roomIdByAlias(final String roomAlias, final ApiCallback call Collection rooms = getStore().getRooms(); for (Room room : rooms) { - if (TextUtils.equals(room.getState().alias, roomAlias)) { + if (TextUtils.equals(room.getState().getCanonicalAlias(), roomAlias)) { roomId = room.getRoomId(); break; } else { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index c674f0cbb..0e3028aea 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -852,7 +852,7 @@ public void updateCanonicalAlias(final String aCanonicalAlias, final ApiCallback mDataHandler.getDataRetriever().getRoomsRestClient().updateCanonicalAlias(getRoomId(), fCanonicalAlias, new RoomInfoUpdateCallback(callback) { @Override public void onSuccess(Void info) { - getState().alias = aCanonicalAlias; + getState().setCanonicalAlias(aCanonicalAlias); super.onSuccess(info); } }); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index d2ffe07b4..c7208650b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -22,6 +22,7 @@ import android.text.TextUtils; import com.google.gson.JsonObject; +import com.google.gson.annotations.SerializedName; import org.matrix.androidsdk.MXDataHandler; import org.matrix.androidsdk.call.MXCallsManager; @@ -103,7 +104,8 @@ public class RoomState implements Externalizable { private Map> mStateEvents = new HashMap<>(); // The canonical alias of the room - public String alias; + @SerializedName("canonical_alias") + private String canonicalAlias; // The name of the room as provided by the home server. public String name; @@ -683,7 +685,7 @@ public RoomState deepCopy() { copy.setPowerLevels((powerLevels == null) ? null : powerLevels.deepCopy()); copy.aliases = (aliases == null) ? null : new ArrayList<>(aliases); copy.mAliasesByDomain = new HashMap<>(mAliasesByDomain); - copy.alias = alias; + copy.canonicalAlias = canonicalAlias; copy.name = name; copy.topic = topic; copy.url = url; @@ -727,8 +729,17 @@ public RoomState deepCopy() { /** * @return the room canonical alias */ - public String getAlias() { - return alias; + public String getCanonicalAlias() { + return canonicalAlias; + } + + /** + * Update the canonical alias of a room + * + * @param newCanonicalAlias the new canonical alias + */ + public void setCanonicalAlias(String newCanonicalAlias) { + canonicalAlias = newCanonicalAlias; } /** @@ -905,7 +916,7 @@ public boolean applyState(IMXStore store, Event event, EventTimeline.Direction d } } else if (Event.EVENT_TYPE_STATE_CANONICAL_ALIAS.equals(eventType)) { // SPEC-125 - alias = JsonUtils.toRoomState(contentToConsider).alias; + canonicalAlias = JsonUtils.toRoomState(contentToConsider).canonicalAlias; } else if (Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY.equals(eventType)) { // SPEC-134 history_visibility = JsonUtils.toRoomState(contentToConsider).history_visibility; @@ -1132,7 +1143,7 @@ public void readExternal(ObjectInput input) throws IOException, ClassNotFoundExc } if (input.readBoolean()) { - alias = input.readUTF(); + canonicalAlias = input.readUTF(); } if (input.readBoolean()) { @@ -1246,9 +1257,9 @@ public void writeExternal(ObjectOutput output) throws IOException { output.writeObject(mStateEvents); - output.writeBoolean(null != alias); - if (null != alias) { - output.writeUTF(alias); + output.writeBoolean(null != canonicalAlias); + if (null != canonicalAlias) { + output.writeUTF(canonicalAlias); } output.writeBoolean(null != name); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupRoom.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupRoom.java index f4b3bbfe1..9a240e18b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupRoom.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupRoom.java @@ -32,8 +32,8 @@ public String getDisplayName() { return name; } - if (!TextUtils.isEmpty(getAlias())) { - return getAlias(); + if (!TextUtils.isEmpty(getCanonicalAlias())) { + return getCanonicalAlias(); } return roomId; From 77b64befe7e5b74d1aeb2dc23eef2543d23d806d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 13:34:37 +0200 Subject: [PATCH 141/236] LazyLoading: take care of getMemberByEventId() --- .../java/org/matrix/androidsdk/data/EventTimeline.java | 1 + .../main/java/org/matrix/androidsdk/data/RoomState.java | 9 ++------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index 06631f316..c5b1d0061 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -1573,6 +1573,7 @@ public void onSuccess(List stateEvents) { // It used to have many out of memory errors because they are too many stored small memory objects. // see https://github.com/matrix-org/matrix-android-sdk/issues/196 + // Note: if lazy loading is on, getMemberByEventId() can return null, but it is ok, because we just want to update our cache RoomMember member = mState.getMemberByEventId(eventId); if (member != null) { Log.d(LOG_TAG, "checkStateEventRedaction: the current room members list has been modified by the event redaction"); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index c7208650b..55c49ba2e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -518,11 +518,11 @@ public RoomMember getMember(String userId) { /** * Retrieve a room member from its original event id. + * It can return null if the lazy loading is enabled and if the member is not loaded yet. * * @param eventId the event id. - * @return the linked member it exists. + * @return the linked member if it exists and if it is loaded. */ - // TODO Change this? Can return null if all members are not loaded yet @Nullable public RoomMember getMemberByEventId(String eventId) { RoomMember member = null; @@ -536,11 +536,6 @@ public RoomMember getMemberByEventId(String eventId) { } } - if (member == null) { - // TODO LazyLoading - Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Null member for event '" + eventId + "' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); - } - return member; } From 3a9f7052b7ef509ac582d007d3f12d0a7c6c2167 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 13:35:54 +0200 Subject: [PATCH 142/236] Copy user membership --- .../src/main/java/org/matrix/androidsdk/data/RoomSummary.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index a20d8e14b..ce39cf793 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -146,6 +146,8 @@ public RoomSummary(@Nullable RoomSummary fromSummary, mHeroes.addAll(fromSummary.mHeroes); mJoinedMembersCountFromSyncRoomSummary = fromSummary.mJoinedMembersCountFromSyncRoomSummary; mInvitedMembersCountFromSyncRoomSummary = fromSummary.mInvitedMembersCountFromSyncRoomSummary; + + mUserMembership = fromSummary.mUserMembership; } } From d51011736115b1a92ea58c993ad352d87481c15b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 13:43:36 +0200 Subject: [PATCH 143/236] Add TODOs --- .../org/matrix/androidsdk/rest/client/ProfileRestClient.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/ProfileRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/ProfileRestClient.java index 1204c7a81..c678b4e1f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/ProfileRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/ProfileRestClient.java @@ -96,6 +96,7 @@ public void updateDisplayname(final String newName, final ApiCallback call //final String description = "updateDisplayname newName : " + newName; final String description = "update display name"; + // TODO Do not create a User for this User user = new User(); user.displayname = newName; @@ -145,6 +146,7 @@ public void updateAvatarUrl(final String newUrl, final ApiCallback callbac //final String description = "updateAvatarUrl newUrl : " + newUrl; final String description = "updateAvatarUrl"; + // TODO Do not create a User for this User user = new User(); user.setAvatarUrl(newUrl); From ddfacbce4f66a4708abea408774c4ccbff1227f7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 14:15:49 +0200 Subject: [PATCH 144/236] Format --- .../org/matrix/androidsdk/lazyloading/RoomStateTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index 55d02c9ba..1cf5e5b25 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -19,8 +19,10 @@ import android.text.TextUtils; import org.junit.Assert; +import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.data.EventTimeline; import org.matrix.androidsdk.data.Room; @@ -33,6 +35,7 @@ import java.util.concurrent.CountDownLatch; @RunWith(AndroidJUnit4.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) public class RoomStateTest { private CommonTestHelper mTestHelper = new CommonTestHelper(); @@ -107,7 +110,7 @@ public void RoomState_BackPaginate_ShouldLoadAllMembers() throws Exception { @Test public void RoomState_BackPaginate_LazyLoading() throws Exception { - RoomState_BackPaginate(true); + RoomState_BackPaginate(true); } private void RoomState_BackPaginate(final boolean withLazyLoading) throws Exception { @@ -165,7 +168,7 @@ public void RoomState_Permalink_ShouldLoadAllMembers() throws Exception { @Test public void RoomState_Permalink_LazyLoading() throws Exception { - RoomState_Permalink(true); + RoomState_Permalink(true); } private void RoomState_Permalink(final boolean withLazyLoading) throws Exception { From b119bb0b31c6b2d3e1b9c055e76289299bfaa141 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 14:19:16 +0200 Subject: [PATCH 145/236] Fix curl issue with `!` --- .../androidsdk/interceptors/CurlLoggingInterceptor.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java b/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java index d8882e2da..90d01c2f7 100644 --- a/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java +++ b/matrix-sdk/src/debug/java/org/matrix/androidsdk/interceptors/CurlLoggingInterceptor.java @@ -95,11 +95,10 @@ public Response intercept(Chain chain) throws IOException { curlCmd += " -H " + "\"" + name + ": " + value + "\""; } - curlCmd += ((compressed) ? " --compressed " : " ") + request.url().toString() - // Escape '!' because it is interpreted by the shell prompt - .replaceAll("!", "\\!") + curlCmd += ((compressed) ? " --compressed " : " ") + "'" + request.url().toString() // Replace localhost for emulator by localhost for shell - .replaceAll("://10.0.2.2:8080/", "://127.0.0.1:8080/"); + .replaceAll("://10.0.2.2:8080/", "://127.0.0.1:8080/") + + "'"; // Add Json formatting curlCmd += " | python -m json.tool"; From 04281152a64087f79ade9a49db4a8c44d268836e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 14:55:17 +0200 Subject: [PATCH 146/236] Init user agent --- .../org/matrix/androidsdk/lazyloading/RoomStateTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index 1cf5e5b25..cf3323202 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -15,14 +15,17 @@ */ package org.matrix.androidsdk.lazyloading; +import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import android.text.TextUtils; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; +import org.matrix.androidsdk.RestClient; import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.data.EventTimeline; import org.matrix.androidsdk.data.Room; @@ -41,6 +44,11 @@ public class RoomStateTest { private CommonTestHelper mTestHelper = new CommonTestHelper(); private LazyLoadingTestHelper mLazyLoadingTestHelper = new LazyLoadingTestHelper(mTestHelper); + @BeforeClass + public static void init() { + RestClient.initUserAgent(InstrumentationRegistry.getContext()); + } + @Test public void RoomState_InitialSync_ShouldLoadAllMembers() throws Exception { RoomState_InitialSync(false); From 816c7fe08b883c075d0a4f1983400311f5781359 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 15:21:56 +0200 Subject: [PATCH 147/236] Remove dead code: onRoomInitialSyncComplete() is never called --- .../org/matrix/androidsdk/MXDataHandler.java | 5 ----- .../matrix/androidsdk/MxEventDispatcher.java | 21 ------------------- .../java/org/matrix/androidsdk/data/Room.java | 12 ----------- .../listeners/IMXEventListener.java | 8 ------- .../androidsdk/listeners/MXEventListener.java | 4 ---- 5 files changed, 50 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 64ef8a1b6..27dbb50d8 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -2006,11 +2006,6 @@ public void onJoinRoom(final String roomId) { mMxEventDispatcher.dispatchOnJoinRoom(roomId, ignoreEvent(roomId)); } - // FIXME Check why this method is never called - public void onRoomInitialSyncComplete(final String roomId) { - mMxEventDispatcher.dispatchOnRoomInitialSyncComplete(roomId, ignoreEvent(roomId)); - } - public void onRoomInternalUpdate(final String roomId) { mMxEventDispatcher.dispatchOnRoomInternalUpdate(roomId, ignoreEvent(roomId)); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java index 9dbd0ea10..89939d9ba 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MxEventDispatcher.java @@ -356,27 +356,6 @@ public void run() { }); } - public void dispatchOnRoomInitialSyncComplete(final String roomId, boolean ignoreEvent) { - if (ignoreEvent) { - return; - } - - final List eventListeners = getListenersSnapshot(); - - mUiHandler.post(new Runnable() { - @Override - public void run() { - for (IMXEventListener listener : eventListeners) { - try { - listener.onRoomInitialSyncComplete(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomInitialSyncComplete " + e.getMessage(), e); - } - } - } - }); - } - public void dispatchOnRoomInternalUpdate(final String roomId, boolean ignoreEvent) { if (ignoreEvent) { return; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 0e3028aea..f03209e3e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -2122,18 +2122,6 @@ public void onEventSent(final Event event, final String prevEventId) { } } - @Override - public void onRoomInitialSyncComplete(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), roomId)) { - try { - eventListener.onRoomInitialSyncComplete(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomInitialSyncComplete exception " + e.getMessage(), e); - } - } - } - @Override public void onRoomInternalUpdate(String roomId) { // Filter out events for other rooms diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/IMXEventListener.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/IMXEventListener.java index 41848a5eb..a40350572 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/IMXEventListener.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/IMXEventListener.java @@ -153,14 +153,6 @@ public interface IMXEventListener { */ void onRoomFlush(String roomId); - /** - * The room initial sync is completed. - * It is triggered after retrieving the room info and performing a first requestHistory - * - * @param roomId the roomID - */ - void onRoomInitialSyncComplete(String roomId); - /** * The room data has been internally updated. * It could be triggered when a request failed. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MXEventListener.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MXEventListener.java index f5231156f..a3eb614c1 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MXEventListener.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MXEventListener.java @@ -92,10 +92,6 @@ public void onNewRoom(String roomId) { public void onJoinRoom(String roomId) { } - @Override - public void onRoomInitialSyncComplete(String roomId) { - } - @Override public void onRoomInternalUpdate(String roomId) { } From 0d0f2b9d17cae1934103d3957fdb936851330438 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 17:29:22 +0200 Subject: [PATCH 148/236] Handle `state` in /messages --- .../matrix/androidsdk/data/EventTimeline.java | 48 ++++++++++++++----- .../matrix/androidsdk/rest/api/RoomsApi.java | 2 +- .../matrix/androidsdk/rest/model/Event.java | 4 +- .../rest/model/TokensChunkEvents.java | 8 ++++ 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index c5b1d0061..fc799fbb3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -20,6 +20,7 @@ import android.os.AsyncTask; import android.os.Looper; +import android.support.annotation.Nullable; import android.text.TextUtils; import com.google.gson.JsonObject; @@ -1048,13 +1049,28 @@ private void manageBackEvents(int maxEventCount, final ApiCallback call /** * Add some events in a dedicated direction. * - * @param events the events list - * @param direction the direction + * @param events the events list + * @param stateEvents the received state events (in case of lazy loading of room members) + * @param direction the direction */ - private void addPaginationEvents(List events, Direction direction) { + private void addPaginationEvents(List events, + @Nullable List stateEvents, + Direction direction) { RoomSummary summary = mStore.getSummary(mRoomId); boolean shouldCommitStore = false; + // Process additional state events (this happens in case of lazy loading) + if (stateEvents != null) { + for (Event stateEvent : stateEvents) { + if (direction == Direction.BACKWARDS) { + // Enrich the timeline root state with the additional state events observed during back pagination + processStateEvent(stateEvent, Direction.FORWARDS); + } + + processStateEvent(stateEvent, direction); + } + } + // the backward events have a dedicated management to avoid providing too many events for each request for (Event event : events) { boolean processedEvent = true; @@ -1098,15 +1114,19 @@ private void addPaginationEvents(List events, Direction direction) { /** * Add some events in a dedicated direction. * - * @param events the events list - * @param direction the direction - * @param callback the callback. + * @param events the events list + * @param stateEvents the received state events (in case of lazy loading of room members) + * @param direction the direction + * @param callback the callback. */ - private void addPaginationEvents(final List events, final Direction direction, final ApiCallback callback) { + private void addPaginationEvents(final List events, + @Nullable final List stateEvents, + final Direction direction, + final ApiCallback callback) { AsyncTask task = new AsyncTask() { @Override protected Void doInBackground(Void... params) { - addPaginationEvents(events, direction); + addPaginationEvents(events, stateEvents, direction); return null; } @@ -1274,7 +1294,10 @@ public void onSuccess(TokensChunkEvents response) { } } - addPaginationEvents((null == response.chunk) ? new ArrayList() : response.chunk, Direction.BACKWARDS, callback); + addPaginationEvents((null == response.chunk) ? new ArrayList() : response.chunk, + response.stateEvents, + Direction.BACKWARDS, + callback); } else { Log.d(LOG_TAG, "mDataHandler is not active."); @@ -1346,7 +1369,10 @@ public void onSuccess(TokensChunkEvents response) { mHasReachedHomeServerForwardsPaginationEnd = (0 == response.chunk.size()) && TextUtils.equals(response.end, response.start); mForwardsPaginationToken = response.end; - addPaginationEvents(response.chunk, Direction.FORWARDS, callback); + addPaginationEvents(response.chunk, + response.stateEvents, + Direction.FORWARDS, + callback); mIsForwardPaginating = false; } else { @@ -1450,7 +1476,7 @@ protected Void doInBackground(Void... params) { events.addAll(eventContext.eventsBefore); // add events after - addPaginationEvents(events, Direction.BACKWARDS); + addPaginationEvents(events, null, Direction.BACKWARDS); return null; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index 593381685..5c0634f03 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -230,7 +230,7 @@ Call sendStateEvent(@Path("roomId") String roomId, Call createRoom(@Body CreateRoomParams createRoomRequest); /** - * Get a list of messages starting from a reference.. + * Get a list of messages starting from a reference. * * @param roomId the room id * @param from the token identifying where to start. Required. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java index d2b9c1380..7e5b5c171 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java @@ -23,6 +23,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.google.gson.annotations.SerializedName; import org.matrix.androidsdk.crypto.MXCryptoError; import org.matrix.androidsdk.crypto.MXEventDecryptionResult; @@ -80,7 +81,7 @@ public enum SentState { // when there is no more message to be paginated in a room // the server returns a null token. - // defines by a non null one to ben able tp store it. + // defines by a non null one to be able to store it. public static final String PAGINATE_BACK_TOKEN_END = "PAGINATE_BACK_TOKEN_END"; public static final String EVENT_TYPE_PRESENCE = "m.presence"; @@ -148,6 +149,7 @@ public enum SentState { public Long age; // Specific to state events + @SerializedName("state_key") public String stateKey; // Contains optional extra information about the event. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/TokensChunkEvents.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/TokensChunkEvents.java index dccb0a537..b01617bc4 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/TokensChunkEvents.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/TokensChunkEvents.java @@ -16,5 +16,13 @@ package org.matrix.androidsdk.rest.model; +import com.google.gson.annotations.SerializedName; + +import java.util.List; + public class TokensChunkEvents extends TokensChunkResponse { + + // With LazyLoading, we can have state events here + @SerializedName("state") + public List stateEvents; } From e3376584b872328f45a108cc82c5991c8f69a780 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 17:29:40 +0200 Subject: [PATCH 149/236] Add TODO --- .../src/main/java/org/matrix/androidsdk/RestClient.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/RestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/RestClient.java index 656c8c657..fc02ec8a5 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/RestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/RestClient.java @@ -23,6 +23,7 @@ import android.content.pm.PackageManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Pair; @@ -336,6 +337,7 @@ private void refreshConnectionTimeout(NetworkConnectivityReceiver networkConnect Log.d(LOG_TAG, "## refreshConnectionTimeout() : update the requests timeout to 1 ms"); } + // FIXME It has no effect to the rest client mOkHttpClient = builder.build(); } @@ -360,6 +362,7 @@ protected void setConnectionTimeout(int aTimeoutMs) { } if (timeoutMs != mOkHttpClient.connectTimeoutMillis()) { + // FIXME It has no effect to the rest client mOkHttpClient = mOkHttpClient.newBuilder().connectTimeout(timeoutMs, TimeUnit.MILLISECONDS).build(); } } @@ -413,6 +416,7 @@ protected RestClient() { * * @param api the api object */ + @VisibleForTesting() protected void setApi(T api) { mApi = api; } From 949d9673b9059e0f50834a5c6493a9f1e276ee7b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Sep 2018 18:00:30 +0200 Subject: [PATCH 150/236] Fix test RoomState_BackPaginate --- .../androidsdk/lazyloading/RoomStateTest.java | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index cf3323202..3dfc18013 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -132,36 +132,36 @@ private void RoomState_BackPaginate(final boolean withLazyLoading) throws Except @Override public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { - if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { - messageCount++; + messageCount++; + if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { Log.d("TAG", "Receiving message #" + messageCount + ": " + JsonUtils.toMessage(event.getContent()).body); - - if (messageCount <= 50) { - Assert.assertNotNull(liveTimeline.getState().getMember(data.aliceSession.getMyUserId())); - - // With LazyLoading, Bob and Sam are not known by Alice yet - Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.bobSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.samSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, roomState.getMember(data.bobSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); - } else if (messageCount <= 100) { - // Bob is known now - Assert.assertNotNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); - - // With LazyLoading, Sam is not known by Alice yet - Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.samSession.getMyUserId()) == null); - Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); - } else if (messageCount == 101) { - // All users are known now - Assert.assertNotNull(liveTimeline.getState().getMember(data.aliceSession.getMyUserId())); - Assert.assertNotNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); - Assert.assertNotNull(liveTimeline.getState().getMember(data.samSession.getMyUserId())); - - lock.countDown(); - } } else { - Log.d("TAG", "Receiving other event: " + event.getType()); + Log.d("TAG", "Receiving event: #" + messageCount + " of type " + event.getType()); + } + + if (messageCount == 10) { + Assert.assertNotNull(liveTimeline.getState().getMember(data.aliceSession.getMyUserId())); + + // With LazyLoading, Bob and Sam are not known by Alice yet + Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.bobSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.bobSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); + } else if (messageCount == 50) { + // Bob is known now + Assert.assertNotNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); + + // With LazyLoading, Sam is not known by Alice yet + Assert.assertEquals(withLazyLoading, liveTimeline.getState().getMember(data.samSession.getMyUserId()) == null); + Assert.assertEquals(withLazyLoading, roomState.getMember(data.samSession.getMyUserId()) == null); + } else if (messageCount == 105) { + // All users are known now + Assert.assertNotNull(liveTimeline.getState().getMember(data.aliceSession.getMyUserId())); + Assert.assertNotNull(liveTimeline.getState().getMember(data.bobSession.getMyUserId())); + Assert.assertNotNull(liveTimeline.getState().getMember(data.samSession.getMyUserId())); + + lock.countDown(); } } }); From 3eac4561d6dffe1dd6fd788e73e2457da942bf1b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 12 Sep 2018 10:19:01 +0200 Subject: [PATCH 151/236] Fix issue with canonical alias --- .../src/main/java/org/matrix/androidsdk/data/RoomState.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 55c49ba2e..c02f1b3de 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -103,9 +103,9 @@ public class RoomState implements Externalizable { // private Map> mStateEvents = new HashMap<>(); - // The canonical alias of the room - @SerializedName("canonical_alias") - private String canonicalAlias; + // The canonical alias of the room. Keep it public for Gson, because private fields are excluded. + @SerializedName("alias") + public String canonicalAlias; // The name of the room as provided by the home server. public String name; From 80e8e7993df4dad293b7a66d49670c6425d82daf Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 12 Sep 2018 10:26:21 +0200 Subject: [PATCH 152/236] Correct way to know it the user is in a room --- .../java/org/matrix/androidsdk/data/store/MXMemoryStore.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java index 5b1611015..8b3882d91 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java @@ -1013,8 +1013,7 @@ public Collection getSummaries() { for (String roomId : mRoomSummaries.keySet()) { Room room = mRooms.get(roomId); if (null != room) { - if (null == room.getMember(mCredentials.userId)) { - // TODO it happens with LazyLoading, fix this + if (!room.isJoined()) { Log.e(LOG_TAG, "## getSummaries() : a summary exists for the roomId " + roomId + " but the user is not anymore a member"); } else { summaries.add(mRoomSummaries.get(roomId)); From 027d731c7cd9103426887f9d0dc5687cbd12538f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 12 Sep 2018 10:30:02 +0200 Subject: [PATCH 153/236] Remove useless field (it's now in RoomSummary) --- .../org/matrix/androidsdk/data/RoomState.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index c02f1b3de..883410b79 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -181,11 +181,6 @@ public class RoomState implements Externalizable { */ private final Map mMembersWithThirdPartyInviteTokenCache = new HashMap<>(); - /** - * Additional and optional metadata got from initialSync - */ - private String mMembership; - /** * Tell if the roomstate if a live one. */ @@ -693,7 +688,6 @@ public RoomState deepCopy() { copy.token = token; copy.groups = groups; copy.mDataHandler = mDataHandler; - copy.mMembership = mMembership; copy.mIsLive = mIsLive; copy.mAllMembersAreLoaded = mAllMembersAreLoaded; copy.algorithm = algorithm; @@ -1207,10 +1201,6 @@ public void readExternal(ObjectInput input) throws IOException, ClassNotFoundExc mMembersWithThirdPartyInviteTokenCache.put(r.getThirdPartyInviteToken(), r); } - if (input.readBoolean()) { - mMembership = input.readUTF(); - } - mIsLive = input.readBoolean(); mAllMembersAreLoaded = input.readBoolean(); @@ -1324,11 +1314,6 @@ public void writeExternal(ObjectOutput output) throws IOException { output.writeObject(new ArrayList<>(mThirdPartyInvites.values())); output.writeObject(new ArrayList<>(mMembersWithThirdPartyInviteTokenCache.values())); - output.writeBoolean(null != mMembership); - if (null != mMembership) { - output.writeUTF(mMembership); - } - output.writeBoolean(mIsLive); output.writeBoolean(mAllMembersAreLoaded); From 695644eeaa5751f092a06b7490f11fa0086aaa67 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 12 Sep 2018 10:30:18 +0200 Subject: [PATCH 154/236] Add final keyword --- .../src/main/java/org/matrix/androidsdk/data/RoomState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 883410b79..a756b5e69 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -170,7 +170,7 @@ public class RoomState implements Externalizable { // true if all members are loaded private boolean mAllMembersAreLoaded; - private List>> mGetAllMembersCallbacks = new ArrayList<>(); + private final List>> mGetAllMembersCallbacks = new ArrayList<>(); // the third party invite members private final Map mThirdPartyInvites = new HashMap<>(); From b18337ff4d9adaa4eadd30d1b2941dbcc8e57911 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 12 Sep 2018 12:38:13 +0200 Subject: [PATCH 155/236] Create class RoomDirectoryVisibility to avoid using a RoomState --- .../matrix/androidsdk/crypto/CryptoTest.java | 9 ++++--- .../java/org/matrix/androidsdk/MXSession.java | 3 ++- .../java/org/matrix/androidsdk/data/Room.java | 9 +++---- .../org/matrix/androidsdk/data/RoomState.java | 6 ++--- .../matrix/androidsdk/rest/api/RoomsApi.java | 10 ++++---- .../rest/client/RoomsRestClient.java | 13 +++++----- .../rest/model/RoomDirectoryVisibility.java | 24 +++++++++++++++++++ .../matrix/androidsdk/util/EventUtils.java | 4 ++-- 8 files changed, 51 insertions(+), 27 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomDirectoryVisibility.java diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index e69183dc1..8be5d7ee4 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -40,7 +40,6 @@ import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.common.SessionAndRoomId; import org.matrix.androidsdk.common.TestApiCallback; -import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.common.Triple; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXOlmSessionResult; @@ -56,6 +55,7 @@ import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.MatrixError; +import org.matrix.androidsdk.rest.model.RoomDirectoryVisibility; import org.matrix.androidsdk.rest.model.RoomMember; import org.matrix.androidsdk.rest.model.login.Credentials; import org.matrix.androidsdk.rest.model.message.Message; @@ -69,7 +69,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @@ -2536,7 +2535,7 @@ public void test25_testLeftAndJoinedBob() throws Exception { bobSession.getCrypto().setWarnOnUnknownDevices(false); CountDownLatch lock0 = new CountDownLatch(1); - aliceSession.createRoom(null, null, RoomState.DIRECTORY_VISIBILITY_PUBLIC, + aliceSession.createRoom(null, null, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PUBLIC, null, RoomState.GUEST_ACCESS_CAN_JOIN, null, new TestApiCallback(lock0) { @Override @@ -3011,7 +3010,7 @@ public void onSuccess(Void info) { bobSession.getCrypto().setWarnOnUnknownDevices(false); CountDownLatch lock0 = new CountDownLatch(1); - aliceSession.createRoom(null, null, RoomState.DIRECTORY_VISIBILITY_PUBLIC, + aliceSession.createRoom(null, null, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PUBLIC, null, RoomState.GUEST_ACCESS_CAN_JOIN, null, new TestApiCallback(lock0) { @Override @@ -3142,7 +3141,7 @@ public void onSuccess(Void info) { final String[] aliceRoomId2 = {null}; CountDownLatch lock3 = new CountDownLatch(1); - aliceSession2.createRoom(null, null, RoomState.DIRECTORY_VISIBILITY_PUBLIC, + aliceSession2.createRoom(null, null, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PUBLIC, null, RoomState.GUEST_ACCESS_CAN_JOIN, null, new TestApiCallback(lock3) { @Override diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index 402f9f220..18da5e2f9 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -71,6 +71,7 @@ import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.MatrixError; import org.matrix.androidsdk.rest.model.ReceiptData; +import org.matrix.androidsdk.rest.model.RoomDirectoryVisibility; import org.matrix.androidsdk.rest.model.RoomMember; import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.Versions; @@ -1193,7 +1194,7 @@ public void createRoom(final ApiCallback callback) { * @param callback the async callback once the room is ready */ public void createRoom(String name, String topic, String alias, final ApiCallback callback) { - createRoom(name, topic, RoomState.DIRECTORY_VISIBILITY_PRIVATE, alias, RoomState.GUEST_ACCESS_CAN_JOIN, null, callback); + createRoom(name, topic, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PRIVATE, alias, RoomState.GUEST_ACCESS_CAN_JOIN, null, callback); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index f03209e3e..93d586cd8 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -58,6 +58,7 @@ import org.matrix.androidsdk.rest.model.MatrixError; import org.matrix.androidsdk.rest.model.PowerLevels; import org.matrix.androidsdk.rest.model.ReceiptData; +import org.matrix.androidsdk.rest.model.RoomDirectoryVisibility; import org.matrix.androidsdk.rest.model.RoomMember; import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.rest.model.User; @@ -1084,16 +1085,16 @@ public void getDirectoryVisibility(final String roomId, final ApiCallback(callback) { + roomRestApi.getDirectoryVisibility(roomId, new SimpleApiCallback(callback) { @Override - public void onSuccess(RoomState roomState) { + public void onSuccess(RoomDirectoryVisibility roomDirectoryVisibility) { RoomState currentRoomState = getState(); if (null != currentRoomState) { - currentRoomState.visibility = roomState.visibility; + currentRoomState.visibility = roomDirectoryVisibility.visibility; } if (null != callback) { - callback.onSuccess(roomState.visibility); + callback.onSuccess(roomDirectoryVisibility.visibility); } } }); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index a756b5e69..ebfb0ffcd 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -32,6 +32,7 @@ import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.PowerLevels; import org.matrix.androidsdk.rest.model.RoomCreateContent; +import org.matrix.androidsdk.rest.model.RoomDirectoryVisibility; import org.matrix.androidsdk.rest.model.RoomMember; import org.matrix.androidsdk.rest.model.RoomPinnedEventsContent; import org.matrix.androidsdk.rest.model.RoomTombstoneContent; @@ -59,9 +60,6 @@ public class RoomState implements Externalizable { private static final String LOG_TAG = RoomState.class.getSimpleName(); private static final long serialVersionUID = -6019932024524988201L; - public static final String DIRECTORY_VISIBILITY_PRIVATE = "private"; - public static final String DIRECTORY_VISIBILITY_PUBLIC = "public"; - public static final String JOIN_RULE_PUBLIC = "public"; public static final String JOIN_RULE_INVITE = "invite"; @@ -1032,7 +1030,7 @@ public boolean applyState(IMXStore store, Event event, EventTimeline.Direction d * @return true if the room is a public one */ public boolean isPublic() { - return TextUtils.equals((null != visibility) ? visibility : join_rule, DIRECTORY_VISIBILITY_PUBLIC); + return TextUtils.equals((null != visibility) ? visibility : join_rule, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PUBLIC); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java index 5c0634f03..8240480e6 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/api/RoomsApi.java @@ -22,7 +22,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.rest.model.BannedUser; import org.matrix.androidsdk.rest.model.ChunkEvents; import org.matrix.androidsdk.rest.model.CreateRoomParams; @@ -33,6 +32,7 @@ import org.matrix.androidsdk.rest.model.PowerLevels; import org.matrix.androidsdk.rest.model.ReportContentParams; import org.matrix.androidsdk.rest.model.RoomAliasDescription; +import org.matrix.androidsdk.rest.model.RoomDirectoryVisibility; import org.matrix.androidsdk.rest.model.RoomMember; import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.rest.model.Typing; @@ -380,11 +380,11 @@ Call updateAccountData(@Path("userId") String userId, * Set the visibility of the given room in the list directory. If the visibility is set to public, the room * name is listed among the directory list. * - * @param roomId the room id where to apply the request - * @param content the put params containing the new "visibility" field + * @param roomId the room id where to apply the request + * @param roomDirectoryVisibility the put params containing the new "visibility" field */ @PUT("directory/list/room/{roomId}") - Call setRoomDirectoryVisibility(@Path("roomId") String roomId, Map content); + Call setRoomDirectoryVisibility(@Path("roomId") String roomId, RoomDirectoryVisibility roomDirectoryVisibility); /** * Get the visibility of the given room in the list directory. @@ -392,7 +392,7 @@ Call updateAccountData(@Path("userId") String userId, * @param roomId the room id where to apply the request */ @GET("directory/list/room/{roomId}") - Call getRoomDirectoryVisibility(@Path("roomId") String roomId); + Call getRoomDirectoryVisibility(@Path("roomId") String roomId); /** * Get all members of a room diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index 79ac34ceb..444df63a5 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -43,6 +43,7 @@ import org.matrix.androidsdk.rest.model.PowerLevels; import org.matrix.androidsdk.rest.model.ReportContentParams; import org.matrix.androidsdk.rest.model.RoomAliasDescription; +import org.matrix.androidsdk.rest.model.RoomDirectoryVisibility; import org.matrix.androidsdk.rest.model.RoomMember; import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.rest.model.Typing; @@ -547,10 +548,10 @@ public void onRetry() { public void updateDirectoryVisibility(final String aRoomId, final String aDirectoryVisibility, final ApiCallback callback) { final String description = "updateRoomDirectoryVisibility : roomId=" + aRoomId + " visibility=" + aDirectoryVisibility; - Map params = new HashMap<>(); - params.put("visibility", aDirectoryVisibility); + RoomDirectoryVisibility roomDirectoryVisibility = new RoomDirectoryVisibility(); + roomDirectoryVisibility.visibility = aDirectoryVisibility; - mApi.setRoomDirectoryVisibility(aRoomId, params) + mApi.setRoomDirectoryVisibility(aRoomId, roomDirectoryVisibility) .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { @@ -564,13 +565,13 @@ public void onRetry() { * Get the directory visibility of the room (see {@link #updateDirectoryVisibility(String, String, ApiCallback)}). * * @param aRoomId the room ID - * @param callback on success callback containing a RoomState object populated with the directory visibility + * @param callback on success callback containing a the room directory visibility */ - public void getDirectoryVisibility(final String aRoomId, final ApiCallback callback) { + public void getDirectoryVisibility(final String aRoomId, final ApiCallback callback) { final String description = "getDirectoryVisibility roomId=" + aRoomId; mApi.getRoomDirectoryVisibility(aRoomId) - .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { + .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { @Override public void onRetry() { getDirectoryVisibility(aRoomId, callback); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomDirectoryVisibility.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomDirectoryVisibility.java new file mode 100644 index 000000000..4378cee23 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomDirectoryVisibility.java @@ -0,0 +1,24 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model; + +public class RoomDirectoryVisibility { + public static final String DIRECTORY_VISIBILITY_PRIVATE = "private"; + public static final String DIRECTORY_VISIBILITY_PUBLIC = "public"; + + public String visibility; +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/EventUtils.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/EventUtils.java index 5fd75781c..55489b8a3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/EventUtils.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/EventUtils.java @@ -20,8 +20,8 @@ import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.data.Room; -import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.rest.model.RoomDirectoryVisibility; import org.matrix.androidsdk.rest.model.bingrules.BingRule; import java.util.regex.Pattern; @@ -96,7 +96,7 @@ public static boolean shouldNotify(MXSession session, Event event, String active } Room room = session.getDataHandler().getRoom(event.roomId); - return RoomState.DIRECTORY_VISIBILITY_PRIVATE.equals(room.getVisibility()) + return RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PRIVATE.equals(room.getVisibility()) && !TextUtils.equals(event.getSender(), session.getCredentials().userId); } From 681981593e8c58d63fb94724b835ca70266f314c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 12 Sep 2018 15:30:19 +0200 Subject: [PATCH 156/236] Fix issue with back pagination ability --- .../matrix/androidsdk/data/EventTimeline.java | 16 +++++++++------- .../org/matrix/androidsdk/data/RoomState.java | 18 ++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index fc799fbb3..426d57725 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -1169,10 +1169,14 @@ public void run() { * @return true if a back pagination can be triggered. */ public boolean canBackPaginate() { - return !mIsBackPaginating && // One at a time please - mState.canBackPaginated(mDataHandler.getUserId()) && // history_visibility flag management - mCanBackPaginate && // If we have already reached the end of history - mRoom.isReady(); // If the room is not finished being set up + // One at a time please + return !mIsBackPaginating + // history_visibility flag management + && mState.canBackPaginate(mRoom.isJoined(), mRoom.isInvited()) + // If we have already reached the end of history + && mCanBackPaginate + // If the room is not finished being set up + && mRoom.isReady(); } /** @@ -1205,10 +1209,8 @@ public boolean backPaginate(final int eventCount, final ApiCallback cal * @return true if request starts */ public boolean backPaginate(final int eventCount, final boolean useCachedOnly, final ApiCallback callback) { - final String myUserId = mDataHandler.getUserId(); - if (!canBackPaginate()) { - Log.d(LOG_TAG, "cannot requestHistory " + mIsBackPaginating + " " + !getState().canBackPaginated(myUserId) + Log.d(LOG_TAG, "cannot requestHistory " + mIsBackPaginating + " " + !getState().canBackPaginate(mRoom.isJoined(), mRoom.isInvited()) + " " + !mCanBackPaginate + " " + !mRoom.isReady()); return false; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index ebfb0ffcd..959a6423e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -647,19 +647,17 @@ public int getHighlightCount() { /** * Check if the user userId can back paginate. * - * @param userId the user Id. - * @return true if the user can backpaginate. + * @param isJoined true is user is in the room + * @param isInvited true is user is invited to the room + * @return true if the user can back paginate. */ - public boolean canBackPaginated(String userId) { - RoomMember member = getMember(userId); - String membership = (null != member) ? member.membership : ""; + public boolean canBackPaginate(boolean isJoined, boolean isInvited) { String visibility = TextUtils.isEmpty(history_visibility) ? HISTORY_VISIBILITY_SHARED : history_visibility; - return visibility.equals(HISTORY_VISIBILITY_WORLD_READABLE) || - visibility.equals(HISTORY_VISIBILITY_SHARED) || - (RoomMember.MEMBERSHIP_JOIN.equals(membership)) /*&&visibility == invited or joined */ || - (RoomMember.MEMBERSHIP_INVITE.equals(membership) && visibility.equals(HISTORY_VISIBILITY_INVITED)) - ; + return isJoined + || visibility.equals(HISTORY_VISIBILITY_WORLD_READABLE) + || visibility.equals(HISTORY_VISIBILITY_SHARED) + || (visibility.equals(HISTORY_VISIBILITY_INVITED) && isInvited); } /** From 3a7d26d87e73c943a8dd1e1e7bb5fa76a0f2560a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 12 Sep 2018 16:33:42 +0200 Subject: [PATCH 157/236] Create class MxRoomEventListener to reduce size of class Room --- .../java/org/matrix/androidsdk/data/Room.java | 193 +------------- .../listeners/MxRoomEventListener.java | 237 ++++++++++++++++++ 2 files changed, 239 insertions(+), 191 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MxRoomEventListener.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 93d586cd8..1ef1439b3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -47,6 +47,7 @@ import org.matrix.androidsdk.db.MXMediasCache; import org.matrix.androidsdk.listeners.IMXEventListener; import org.matrix.androidsdk.listeners.MXEventListener; +import org.matrix.androidsdk.listeners.MxRoomEventListener; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.client.AccountDataRestClient; @@ -61,7 +62,6 @@ import org.matrix.androidsdk.rest.model.RoomDirectoryVisibility; import org.matrix.androidsdk.rest.model.RoomMember; import org.matrix.androidsdk.rest.model.TokensChunkEvents; -import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.message.FileInfo; import org.matrix.androidsdk.rest.model.message.FileMessage; import org.matrix.androidsdk.rest.model.message.ImageInfo; @@ -2053,196 +2053,7 @@ public void addEventListener(final IMXEventListener eventListener) { } // Create a global listener that we'll add to the data handler - IMXEventListener globalListener = new MXEventListener() { - @Override - public void onPresenceUpdate(Event event, User user) { - // Only pass event through if the user is a member of the room - if (getMember(user.user_id) != null) { - try { - eventListener.onPresenceUpdate(event, user); - } catch (Exception e) { - Log.e(LOG_TAG, "onPresenceUpdate exception " + e.getMessage(), e); - } - } - } - - @Override - public void onLiveEvent(Event event, RoomState roomState) { - // Filter out events for other rooms and events while we are joining (before the room is ready) - if (TextUtils.equals(getRoomId(), event.roomId) && mIsReady) { - try { - eventListener.onLiveEvent(event, roomState); - } catch (Exception e) { - Log.e(LOG_TAG, "onLiveEvent exception " + e.getMessage(), e); - } - } - } - - @Override - public void onLiveEventsChunkProcessed(String fromToken, String toToken) { - try { - eventListener.onLiveEventsChunkProcessed(fromToken, toToken); - } catch (Exception e) { - Log.e(LOG_TAG, "onLiveEventsChunkProcessed exception " + e.getMessage(), e); - } - } - - @Override - public void onEventSentStateUpdated(Event event) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), event.roomId)) { - try { - eventListener.onEventSentStateUpdated(event); - } catch (Exception e) { - Log.e(LOG_TAG, "onEventSentStateUpdated exception " + e.getMessage(), e); - } - } - } - - @Override - public void onEventDecrypted(Event event) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), event.roomId)) { - try { - eventListener.onEventDecrypted(event); - } catch (Exception e) { - Log.e(LOG_TAG, "onDecryptedEvent exception " + e.getMessage(), e); - } - } - } - - @Override - public void onEventSent(final Event event, final String prevEventId) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), event.roomId)) { - try { - eventListener.onEventSent(event, prevEventId); - } catch (Exception e) { - Log.e(LOG_TAG, "onEventSent exception " + e.getMessage(), e); - } - } - } - - @Override - public void onRoomInternalUpdate(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), roomId)) { - try { - eventListener.onRoomInternalUpdate(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomInternalUpdate exception " + e.getMessage(), e); - } - } - } - - @Override - public void onNotificationCountUpdate(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), roomId)) { - try { - eventListener.onNotificationCountUpdate(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onNotificationCountUpdate exception " + e.getMessage(), e); - } - } - } - - @Override - public void onNewRoom(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), roomId)) { - try { - eventListener.onNewRoom(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onNewRoom exception " + e.getMessage(), e); - } - } - } - - @Override - public void onJoinRoom(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), roomId)) { - try { - eventListener.onJoinRoom(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onJoinRoom exception " + e.getMessage(), e); - } - } - } - - @Override - public void onReceiptEvent(String roomId, List senderIds) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), roomId)) { - try { - eventListener.onReceiptEvent(roomId, senderIds); - } catch (Exception e) { - Log.e(LOG_TAG, "onReceiptEvent exception " + e.getMessage(), e); - } - } - } - - @Override - public void onRoomTagEvent(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), roomId)) { - try { - eventListener.onRoomTagEvent(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomTagEvent exception " + e.getMessage(), e); - } - } - } - - @Override - public void onReadMarkerEvent(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), roomId)) { - try { - eventListener.onReadMarkerEvent(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onReadMarkerEvent exception " + e.getMessage(), e); - } - } - } - - @Override - public void onRoomFlush(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), roomId)) { - try { - eventListener.onRoomFlush(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomFlush exception " + e.getMessage(), e); - } - } - } - - @Override - public void onLeaveRoom(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), roomId)) { - try { - eventListener.onLeaveRoom(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onLeaveRoom exception " + e.getMessage(), e); - } - } - } - - @Override - public void onRoomKick(String roomId) { - // Filter out events for other rooms - if (TextUtils.equals(getRoomId(), roomId)) { - try { - eventListener.onRoomKick(roomId); - } catch (Exception e) { - Log.e(LOG_TAG, "onRoomKick exception " + e.getMessage(), e); - } - } - } - }; + IMXEventListener globalListener = new MxRoomEventListener(this, eventListener); mEventListeners.put(eventListener, globalListener); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MxRoomEventListener.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MxRoomEventListener.java new file mode 100644 index 000000000..f20efac69 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MxRoomEventListener.java @@ -0,0 +1,237 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.listeners; + +import android.support.annotation.NonNull; +import android.text.TextUtils; + +import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.rest.model.User; +import org.matrix.androidsdk.util.Log; + +import java.util.List; + +/** + * A listener which filter event for a specific room + */ +public class MxRoomEventListener extends MXEventListener { + + private static final String LOG_TAG = MxRoomEventListener.class.getSimpleName(); + + private final String mRoomId; + private final IMXEventListener mEventListener; + private final Room mRoom; + + public MxRoomEventListener(@NonNull Room room, + @NonNull IMXEventListener eventListener) { + mRoom = room; + mRoomId = room.getRoomId(); + mEventListener = eventListener; + } + + @Override + public void onPresenceUpdate(Event event, User user) { + // Only pass event through if the user is a member of the room + // FIXME LazyLoading. We cannot rely on getMember nullity anymore + if (mRoom.getMember(user.user_id) != null) { + try { + mEventListener.onPresenceUpdate(event, user); + } catch (Exception e) { + Log.e(LOG_TAG, "onPresenceUpdate exception " + e.getMessage(), e); + } + } + } + + @Override + public void onLiveEvent(Event event, RoomState roomState) { + // Filter out events for other rooms and events while we are joining (before the room is ready) + if (TextUtils.equals(mRoomId, event.roomId) && mRoom.isReady()) { + try { + mEventListener.onLiveEvent(event, roomState); + } catch (Exception e) { + Log.e(LOG_TAG, "onLiveEvent exception " + e.getMessage(), e); + } + } + } + + @Override + public void onLiveEventsChunkProcessed(String fromToken, String toToken) { + try { + mEventListener.onLiveEventsChunkProcessed(fromToken, toToken); + } catch (Exception e) { + Log.e(LOG_TAG, "onLiveEventsChunkProcessed exception " + e.getMessage(), e); + } + } + + @Override + public void onEventSentStateUpdated(Event event) { + // Filter out events for other rooms + if (TextUtils.equals(mRoomId, event.roomId)) { + try { + mEventListener.onEventSentStateUpdated(event); + } catch (Exception e) { + Log.e(LOG_TAG, "onEventSentStateUpdated exception " + e.getMessage(), e); + } + } + } + + @Override + public void onEventDecrypted(Event event) { + // Filter out events for other rooms + if (TextUtils.equals(mRoomId, event.roomId)) { + try { + mEventListener.onEventDecrypted(event); + } catch (Exception e) { + Log.e(LOG_TAG, "onDecryptedEvent exception " + e.getMessage(), e); + } + } + } + + @Override + public void onEventSent(final Event event, final String prevEventId) { + // Filter out events for other rooms + if (TextUtils.equals(mRoomId, event.roomId)) { + try { + mEventListener.onEventSent(event, prevEventId); + } catch (Exception e) { + Log.e(LOG_TAG, "onEventSent exception " + e.getMessage(), e); + } + } + } + + @Override + public void onRoomInternalUpdate(String roomId) { + // Filter out events for other rooms + if (TextUtils.equals(mRoomId, roomId)) { + try { + mEventListener.onRoomInternalUpdate(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onRoomInternalUpdate exception " + e.getMessage(), e); + } + } + } + + @Override + public void onNotificationCountUpdate(String roomId) { + // Filter out events for other rooms + if (TextUtils.equals(mRoomId, roomId)) { + try { + mEventListener.onNotificationCountUpdate(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onNotificationCountUpdate exception " + e.getMessage(), e); + } + } + } + + @Override + public void onNewRoom(String roomId) { + // Filter out events for other rooms + if (TextUtils.equals(mRoomId, roomId)) { + try { + mEventListener.onNewRoom(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onNewRoom exception " + e.getMessage(), e); + } + } + } + + @Override + public void onJoinRoom(String roomId) { + // Filter out events for other rooms + if (TextUtils.equals(mRoomId, roomId)) { + try { + mEventListener.onJoinRoom(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onJoinRoom exception " + e.getMessage(), e); + } + } + } + + @Override + public void onReceiptEvent(String roomId, List senderIds) { + // Filter out events for other rooms + if (TextUtils.equals(mRoomId, roomId)) { + try { + mEventListener.onReceiptEvent(roomId, senderIds); + } catch (Exception e) { + Log.e(LOG_TAG, "onReceiptEvent exception " + e.getMessage(), e); + } + } + } + + @Override + public void onRoomTagEvent(String roomId) { + // Filter out events for other rooms + if (TextUtils.equals(mRoomId, roomId)) { + try { + mEventListener.onRoomTagEvent(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onRoomTagEvent exception " + e.getMessage(), e); + } + } + } + + @Override + public void onReadMarkerEvent(String roomId) { + // Filter out events for other rooms + if (TextUtils.equals(mRoomId, roomId)) { + try { + mEventListener.onReadMarkerEvent(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onReadMarkerEvent exception " + e.getMessage(), e); + } + } + } + + @Override + public void onRoomFlush(String roomId) { + // Filter out events for other rooms + if (TextUtils.equals(mRoomId, roomId)) { + try { + mEventListener.onRoomFlush(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onRoomFlush exception " + e.getMessage(), e); + } + } + } + + @Override + public void onLeaveRoom(String roomId) { + // Filter out events for other rooms + if (TextUtils.equals(mRoomId, roomId)) { + try { + mEventListener.onLeaveRoom(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onLeaveRoom exception " + e.getMessage(), e); + } + } + } + + @Override + public void onRoomKick(String roomId) { + // Filter out events for other rooms + if (TextUtils.equals(mRoomId, roomId)) { + try { + mEventListener.onRoomKick(roomId); + } catch (Exception e) { + Log.e(LOG_TAG, "onRoomKick exception " + e.getMessage(), e); + } + } + } +} From 3572991ea0af88ce45c4fd3b368bd383b536d18d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 12 Sep 2018 17:35:55 +0200 Subject: [PATCH 158/236] typo --- .../matrix/androidsdk/fragments/MatrixMessagesFragment.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java index 89f46d623..69021eed7 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java @@ -103,6 +103,7 @@ public interface MatrixMessagesListener { // The listener to send messages back private MatrixMessagesListener mMatrixMessagesListener; + // The adapted listener to register to the SDK private final IMXEventListener mEventListener = new MXEventListener() { @Override @@ -298,7 +299,7 @@ public void onResume() { private void sendInitialMessagesLoaded() { final android.os.Handler handler = new android.os.Handler(Looper.getMainLooper()); - // add a delay to avoid calling MatrixListFragment before it is fully initialized + // add a delay to avoid calling MatrixMessageListFragment before it is fully initialized handler.postDelayed(new Runnable() { @Override public void run() { From 61601d635ab25f2f4aeac860961010864115b80c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 12 Sep 2018 17:40:37 +0200 Subject: [PATCH 159/236] Fix issue with read receipt avatar not displayed --- .../androidsdk/adapters/AbstractMessagesAdapter.java | 11 +++++++++++ .../fragments/MatrixMessageListFragment.java | 11 +++++++++++ .../androidsdk/rest/callback/SimpleApiCallback.java | 3 ++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/adapters/AbstractMessagesAdapter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/adapters/AbstractMessagesAdapter.java index 135ee32eb..ac39c84fe 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/adapters/AbstractMessagesAdapter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/adapters/AbstractMessagesAdapter.java @@ -1,5 +1,6 @@ /* * Copyright 2017 Vector Creations Ltd + * Copyright 2018 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +21,9 @@ import android.widget.ArrayAdapter; import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.rest.model.RoomMember; + +import java.util.List; /** * Abstract implementation of messages list @@ -182,4 +186,11 @@ public AbstractMessagesAdapter(Context context, int view) { * Notify that some bing rules could have been updated. */ public abstract void onBingRulesUpdate(); + + /** + * Give the list of retrieved room members. + * + * @param roomMembers the full list of room members. The state of the room may not contain all user when lazy loading is enabled. + */ + public abstract void setLiveRoomMembers(List roomMembers); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java index 3b5c92edf..6a00b6dc4 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java @@ -58,6 +58,7 @@ import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.MatrixError; import org.matrix.androidsdk.rest.model.ReceiptData; +import org.matrix.androidsdk.rest.model.RoomMember; import org.matrix.androidsdk.rest.model.message.MediaMessage; import org.matrix.androidsdk.rest.model.message.Message; import org.matrix.androidsdk.rest.model.search.SearchResponse; @@ -540,6 +541,16 @@ public boolean onTouch(View v, MotionEvent event) { mDisplayAllEvents = isDisplayAllEvents(); + // Ensure all RoomMember are loaded (ignore error) + mRoom.getMembersAsync(new SimpleApiCallback>() { + @Override + public void onSuccess(List info) { + if (isAdded()) { + mAdapter.setLiveRoomMembers(info); + } + } + }); + return v; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/SimpleApiCallback.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/SimpleApiCallback.java index 3bc01f94c..714c4ce81 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/SimpleApiCallback.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/SimpleApiCallback.java @@ -1,6 +1,7 @@ /* * Copyright 2014 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 From 6be06a3d7cb1a5f6ca139d50d731637ab236b429 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 12 Sep 2018 19:11:14 +0200 Subject: [PATCH 160/236] Align the message list to the bottom of the screen --- .../fragment_matrix_message_list_fragment.xml | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/matrix-sdk/src/main/res/layout/fragment_matrix_message_list_fragment.xml b/matrix-sdk/src/main/res/layout/fragment_matrix_message_list_fragment.xml index 5ff4fc30c..a0590cdeb 100644 --- a/matrix-sdk/src/main/res/layout/fragment_matrix_message_list_fragment.xml +++ b/matrix-sdk/src/main/res/layout/fragment_matrix_message_list_fragment.xml @@ -1,20 +1,23 @@ - + + android:transcriptMode="normal" + tools:layout_height="120dp" /> - \ No newline at end of file + \ No newline at end of file From ea352ad48808157148d7493f80809743f9070d70 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 13 Sep 2018 09:42:46 +0200 Subject: [PATCH 161/236] Better code for typings --- .../java/org/matrix/androidsdk/data/Room.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 1ef1439b3..72da92447 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -262,7 +262,7 @@ private void handleEphemeralEvents(List events) { if (event.roomId != null) { List senders = handleReceiptEvent(event); - if ((null != senders) && (senders.size() > 0)) { + if (senders != null && !senders.isEmpty()) { mDataHandler.onReceiptEvent(event.roomId, senders); } } @@ -270,19 +270,20 @@ private void handleEphemeralEvents(List events) { JsonObject eventContent = event.getContentAsJsonObject(); if (eventContent.has("user_ids")) { - synchronized (Room.this) { - mTypingUsers = null; + synchronized (mTypingUsers) { + mTypingUsers.clear(); + + List typingUsers = null; try { - mTypingUsers = (new Gson()).fromJson(eventContent.get("user_ids"), new TypeToken>() { + typingUsers = (new Gson()).fromJson(eventContent.get("user_ids"), new TypeToken>() { }.getType()); } catch (Exception e) { Log.e(LOG_TAG, "## handleEphemeralEvents() : exception " + e.getMessage(), e); } - // avoid null list - if (null == mTypingUsers) { - mTypingUsers = new ArrayList<>(); + if (typingUsers != null) { + mTypingUsers.addAll(typingUsers); } } } @@ -1578,18 +1579,20 @@ public void refreshUnreadCounter() { //================================================================================ // userIds list - private List mTypingUsers = new ArrayList<>(); + @NonNull + private final List mTypingUsers = new ArrayList<>(); /** * Get typing users * * @return the userIds list */ + @NonNull public List getTypingUsers() { List typingUsers; - synchronized (Room.this) { - typingUsers = (null == mTypingUsers) ? new ArrayList() : new ArrayList<>(mTypingUsers); + synchronized (mTypingUsers) { + typingUsers = new ArrayList<>(mTypingUsers); } return typingUsers; From ae11a5a08c3e9e654a09acd54986065564d703fc Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 13 Sep 2018 11:57:39 +0200 Subject: [PATCH 162/236] Fix issue of missing invitation --- .../java/org/matrix/androidsdk/data/store/MXMemoryStore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java index 8b3882d91..2be2eae86 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java @@ -1013,7 +1013,7 @@ public Collection getSummaries() { for (String roomId : mRoomSummaries.keySet()) { Room room = mRooms.get(roomId); if (null != room) { - if (!room.isJoined()) { + if (!room.isJoined() && !room.isInvited()) { Log.e(LOG_TAG, "## getSummaries() : a summary exists for the roomId " + roomId + " but the user is not anymore a member"); } else { summaries.add(mRoomSummaries.get(roomId)); From 83b7467b4bcce63d6faf6fe2bd1e28124680de2d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 13 Sep 2018 15:11:47 +0200 Subject: [PATCH 163/236] RoomSummary: code style --- .../matrix/androidsdk/data/RoomSummary.java | 47 +++++++++---------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index ce39cf793..82fc9e070 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -174,13 +174,13 @@ public static boolean isSupportedEvent(Event event) { msgType = element.getAsString(); } - isSupported = TextUtils.equals(msgType, Message.MSGTYPE_TEXT) || - TextUtils.equals(msgType, Message.MSGTYPE_EMOTE) || - TextUtils.equals(msgType, Message.MSGTYPE_NOTICE) || - TextUtils.equals(msgType, Message.MSGTYPE_IMAGE) || - TextUtils.equals(msgType, Message.MSGTYPE_AUDIO) || - TextUtils.equals(msgType, Message.MSGTYPE_VIDEO) || - TextUtils.equals(msgType, Message.MSGTYPE_FILE); + isSupported = TextUtils.equals(msgType, Message.MSGTYPE_TEXT) + || TextUtils.equals(msgType, Message.MSGTYPE_EMOTE) + || TextUtils.equals(msgType, Message.MSGTYPE_NOTICE) + || TextUtils.equals(msgType, Message.MSGTYPE_IMAGE) + || TextUtils.equals(msgType, Message.MSGTYPE_AUDIO) + || TextUtils.equals(msgType, Message.MSGTYPE_VIDEO) + || TextUtils.equals(msgType, Message.MSGTYPE_FILE); if (!isSupported && !TextUtils.isEmpty(msgType)) { Log.e(LOG_TAG, "isSupportedEvent : Unsupported msg type " + msgType); @@ -191,26 +191,25 @@ public static boolean isSupportedEvent(Event event) { } else if (TextUtils.equals(Event.EVENT_TYPE_MESSAGE_ENCRYPTED, type)) { isSupported = event.hasContentFields(); } else if (!TextUtils.isEmpty(type)) { - isSupported = TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_TOPIC, type) || - TextUtils.equals(Event.EVENT_TYPE_MESSAGE_ENCRYPTED, type) || - TextUtils.equals(Event.EVENT_TYPE_MESSAGE_ENCRYPTION, type) || - TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_NAME, type) || - TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_MEMBER, type) || - TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_CREATE, type) || - TextUtils.equals(Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY, type) || - TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_THIRD_PARTY_INVITE, type) || - TextUtils.equals(Event.EVENT_TYPE_STICKER, type) || - (event.isCallEvent() && !Event.EVENT_TYPE_CALL_CANDIDATES.equals(type)); + isSupported = TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_TOPIC, type) + || TextUtils.equals(Event.EVENT_TYPE_MESSAGE_ENCRYPTED, type) + || TextUtils.equals(Event.EVENT_TYPE_MESSAGE_ENCRYPTION, type) + || TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_NAME, type) + || TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_MEMBER, type) + || TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_CREATE, type) + || TextUtils.equals(Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY, type) + || TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_THIRD_PARTY_INVITE, type) + || TextUtils.equals(Event.EVENT_TYPE_STICKER, type) + || (event.isCallEvent() && !Event.EVENT_TYPE_CALL_CANDIDATES.equals(type)); if (!isSupported) { // some events are known to be never traced // avoid warning when it is not required. - if (!TextUtils.equals(Event.EVENT_TYPE_TYPING, type) && - !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_POWER_LEVELS, type) && - !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_JOIN_RULES, type) && - !TextUtils.equals(Event.EVENT_TYPE_STATE_CANONICAL_ALIAS, type) && - !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_ALIASES, type) - ) { + if (!TextUtils.equals(Event.EVENT_TYPE_TYPING, type) + && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_POWER_LEVELS, type) + && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_JOIN_RULES, type) + && !TextUtils.equals(Event.EVENT_TYPE_STATE_CANONICAL_ALIAS, type) + && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_ALIASES, type)) { Log.e(LOG_TAG, "isSupportedEvent : Unsupported event type " + type); } } else if (TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_MEMBER, type)) { @@ -370,7 +369,7 @@ public RoomSummary setLatestReceivedEvent(Event event) { } /** - * Set the latest tracked event (e.g. the latest m.room.message) + * Set the latest RoomState * * @param roomState The room state of the latest event. * @return This summary for chaining calls. From 4b723f64664252b88c0549d54e58800f3e91bd32 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 13 Sep 2018 15:26:06 +0200 Subject: [PATCH 164/236] RoomSummary: flatter algo --- .../matrix/androidsdk/data/RoomSummary.java | 85 +++++++++---------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index 82fc9e070..65b7d14ba 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -190,7 +190,36 @@ public static boolean isSupportedEvent(Event event) { } } else if (TextUtils.equals(Event.EVENT_TYPE_MESSAGE_ENCRYPTED, type)) { isSupported = event.hasContentFields(); - } else if (!TextUtils.isEmpty(type)) { + } else if (TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_MEMBER, type)) { + JsonObject eventContentAsJsonObject = event.getContentAsJsonObject(); + + if (null != eventContentAsJsonObject) { + if (eventContentAsJsonObject.entrySet().isEmpty()) { + Log.d(LOG_TAG, "isSupportedEvent : room member with no content is not supported"); + } else { + // do not display the avatar / display name update + EventContent prevEventContent = event.getPrevContent(); + EventContent eventContent = event.getEventContent(); + + String membership = null; + String preMembership = null; + + if (null != prevEventContent) { + membership = eventContent.membership; + } + + if (null != prevEventContent) { + preMembership = prevEventContent.membership; + } + + isSupported = (null == membership) || !TextUtils.equals(membership, preMembership); + + if (!isSupported) { + Log.d(LOG_TAG, "isSupportedEvent : do not support avatar display name update"); + } + } + } + } else { isSupported = TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_TOPIC, type) || TextUtils.equals(Event.EVENT_TYPE_MESSAGE_ENCRYPTED, type) || TextUtils.equals(Event.EVENT_TYPE_MESSAGE_ENCRYPTION, type) @@ -200,48 +229,18 @@ public static boolean isSupportedEvent(Event event) { || TextUtils.equals(Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY, type) || TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_THIRD_PARTY_INVITE, type) || TextUtils.equals(Event.EVENT_TYPE_STICKER, type) - || (event.isCallEvent() && !Event.EVENT_TYPE_CALL_CANDIDATES.equals(type)); - - if (!isSupported) { - // some events are known to be never traced - // avoid warning when it is not required. - if (!TextUtils.equals(Event.EVENT_TYPE_TYPING, type) - && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_POWER_LEVELS, type) - && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_JOIN_RULES, type) - && !TextUtils.equals(Event.EVENT_TYPE_STATE_CANONICAL_ALIAS, type) - && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_ALIASES, type)) { - Log.e(LOG_TAG, "isSupportedEvent : Unsupported event type " + type); - } - } else if (TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_MEMBER, type)) { - JsonObject eventContentAsJsonObject = event.getContentAsJsonObject(); - - if (null != eventContentAsJsonObject) { - if (0 == eventContentAsJsonObject.entrySet().size()) { - isSupported = false; - Log.d(LOG_TAG, "isSupportedEvent : room member with no content is not supported"); - } else { - // do not display the avatar / display name update - EventContent prevEventContent = event.getPrevContent(); - EventContent eventContent = event.getEventContent(); - - String membership = null; - String preMembership = null; - - if (null != prevEventContent) { - membership = eventContent.membership; - } - - if (null != prevEventContent) { - preMembership = prevEventContent.membership; - } - - isSupported = (null == membership) || !TextUtils.equals(membership, preMembership); - - if (!isSupported) { - Log.d(LOG_TAG, "isSupportedEvent : do not support avatar display name update"); - } - } - } + || (event.isCallEvent() && !TextUtils.isEmpty(type) && !Event.EVENT_TYPE_CALL_CANDIDATES.equals(type)); + } + + if (!isSupported) { + // some events are known to be never traced + // avoid warning when it is not required. + if (!TextUtils.equals(Event.EVENT_TYPE_TYPING, type) + && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_POWER_LEVELS, type) + && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_JOIN_RULES, type) + && !TextUtils.equals(Event.EVENT_TYPE_STATE_CANONICAL_ALIAS, type) + && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_ALIASES, type)) { + Log.e(LOG_TAG, "isSupportedEvent : Unsupported event type " + type); } } From 59f8974e80926a7a4fb0ecb3872c05fd83fa4121 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 13 Sep 2018 15:30:58 +0200 Subject: [PATCH 165/236] RoomSummary: better if test --- .../main/java/org/matrix/androidsdk/data/RoomSummary.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index 65b7d14ba..be0972575 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -204,15 +204,15 @@ public static boolean isSupportedEvent(Event event) { String membership = null; String preMembership = null; - if (null != prevEventContent) { + if (eventContent != null) { membership = eventContent.membership; } - if (null != prevEventContent) { + if (prevEventContent != null) { preMembership = prevEventContent.membership; } - isSupported = (null == membership) || !TextUtils.equals(membership, preMembership); + isSupported = !TextUtils.equals(membership, preMembership); if (!isSupported) { Log.d(LOG_TAG, "isSupportedEvent : do not support avatar display name update"); From 4d12ef75c71886d0dc284572eb4d93c04b00a04c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 13 Sep 2018 15:35:08 +0200 Subject: [PATCH 166/236] RoomSummary: qdd known exceptions (fix #2584) --- .../main/java/org/matrix/androidsdk/data/RoomSummary.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index be0972575..5bfb7ecd8 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -239,7 +239,11 @@ public static boolean isSupportedEvent(Event event) { && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_POWER_LEVELS, type) && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_JOIN_RULES, type) && !TextUtils.equals(Event.EVENT_TYPE_STATE_CANONICAL_ALIAS, type) - && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_ALIASES, type)) { + && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_ALIASES, type) + && !TextUtils.equals(Event.EVENT_TYPE_URL_PREVIEW, type) + && !TextUtils.equals(Event.EVENT_TYPE_STATE_RELATED_GROUPS, type) + && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_GUEST_ACCESS, type) + && !TextUtils.equals(Event.EVENT_TYPE_REDACTION, type)) { Log.e(LOG_TAG, "isSupportedEvent : Unsupported event type " + type); } } From fa94f30670421078d7f87721c42161513d60e74e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 14 Sep 2018 14:37:10 +0200 Subject: [PATCH 167/236] Add a method from riot to extract id from a Matrix permalink --- .../androidsdk/util/PermalinkUtils.java | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/PermalinkUtils.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/PermalinkUtils.java index 2df2979b6..87ca9d4b1 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/PermalinkUtils.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/PermalinkUtils.java @@ -23,7 +23,7 @@ import org.matrix.androidsdk.rest.model.Event; /** - * Useful methods to create permalink + * Useful methods to deals with Matrix permalink */ public class PermalinkUtils { @@ -31,7 +31,7 @@ public class PermalinkUtils { /** * Creates a permalink for an event. - * Ex: https://matrix.to/#/!nbzmcXAqpxBXjAdgoX:matrix.org/$1531497316352799BevdV:matrix.org + * Ex: "https://matrix.to/#/!nbzmcXAqpxBXjAdgoX:matrix.org/$1531497316352799BevdV:matrix.org" * * @param event the event * @return the permalink, or null in case of error @@ -47,7 +47,7 @@ public static String createPermalink(Event event) { /** * Creates a permalink for an id (can be a user Id, Room Id, etc.). - * Ex: https://matrix.to/#/@benoit:matrix.org + * Ex: "https://matrix.to/#/@benoit:matrix.org" * * @param id the id * @return the permalink, or null in case of error @@ -63,17 +63,34 @@ public static String createPermalink(String id) { /** * Creates a permalink for an event. If you have an event you can use {@link #createPermalink(Event)} - * Ex: https://matrix.to/#/!nbzmcXAqpxBXjAdgoX:matrix.org/$1531497316352799BevdV:matrix.org + * Ex: "https://matrix.to/#/!nbzmcXAqpxBXjAdgoX:matrix.org/$1531497316352799BevdV:matrix.org" * * @param roomId the id of the room * @param eventId the id of the event * @return the permalink */ - @Nullable + @NonNull public static String createPermalink(@NonNull String roomId, @NonNull String eventId) { return MATRIX_TO_URL_BASE + escape(roomId) + "/" + escape(eventId); } + /** + * Extract the linked id from the universal link + * + * @param url the universal link, Ex: "https://matrix.to/#/@benoit:matrix.org" + * @return the id from the url, ex: "@benoit:matrix.org", or null if the url is not a permalink + */ + public static String getLinkedId(@Nullable String url) { + boolean isSupported = url != null && url.startsWith(MATRIX_TO_URL_BASE); + + if (isSupported) { + return url.substring(MATRIX_TO_URL_BASE.length()); + } + + return null; + } + + /** * Escape '/' in id, because it is used as a separator * From ab2b09386f5c9eb27b16f4222125a950cd5f3e50 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 14 Sep 2018 16:20:23 +0200 Subject: [PATCH 168/236] Add TODO --- .../java/org/matrix/androidsdk/rest/client/RoomsRestClient.java | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index 444df63a5..5de6acd41 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -170,6 +170,7 @@ public void onRetry() { public void inviteUserToRoom(final String roomId, final String userId, final ApiCallback callback) { final String description = "inviteToRoom : roomId " + roomId + " userId " + userId; + // TODO Do not create a User for this User user = new User(); user.user_id = userId; From 95ebf87dce6572b02fad98015b27a1b4f5c36dc9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 14 Sep 2018 16:21:16 +0200 Subject: [PATCH 169/236] /members result does not erase known members anymore. Also store User --- .../java/org/matrix/androidsdk/data/RoomState.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 959a6423e..a4cbc8d73 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -289,10 +289,19 @@ public void getMembersAsync(ApiCallback> callback) { public void onSuccess(List info) { Log.d(LOG_TAG, "getMembers has returned " + info.size() + " users."); + IMXStore store = ((MXDataHandler) mDataHandler).getStore(); List res; for (RoomMember member : info) { - setMember(member.getUserId(), member); + // Do not erase already known members form the sync + if (getMember(member.getUserId()) == null) { + setMember(member.getUserId(), member); + + // Also create a User + if (store != null) { + store.updateUserWithRoomMemberEvent(member); + } + } } synchronized (mGetAllMembersCallbacks) { From 61184404e7206ec9960a155b0611e0000884755f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 14 Sep 2018 16:29:25 +0200 Subject: [PATCH 170/236] Fix bad if --- .../androidsdk/fragments/MatrixMessageListFragment.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java index 6a00b6dc4..aae0b3923 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java @@ -23,6 +23,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; @@ -449,7 +450,7 @@ public void onCreate(Bundle savedInstanceState) { } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d(LOG_TAG, "onCreateView"); View defaultView = super.onCreateView(inflater, container, savedInstanceState); @@ -491,7 +492,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa // only init the adapter if it wasn't before, so we can preserve messages/position. mAdapter = createMessagesAdapter(); - if (null == getMXMediasCache()) { + if (null == mAdapter) { throw new RuntimeException("Must have valid default MessagesAdapter."); } } else if (null != savedInstanceState) { From fe8cd8ff995b079c2ca794aab815a7634d44d1f4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 14 Sep 2018 17:58:36 +0200 Subject: [PATCH 171/236] better code --- .../adapters/AbstractMessagesAdapter.java | 2 +- .../fragments/MatrixMessageListFragment.java | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/adapters/AbstractMessagesAdapter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/adapters/AbstractMessagesAdapter.java index ac39c84fe..42ce20fe6 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/adapters/AbstractMessagesAdapter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/adapters/AbstractMessagesAdapter.java @@ -45,7 +45,7 @@ public AbstractMessagesAdapter(Context context, int view) { * Add a row and refresh the adapter if it is required. * * @param row the row to append - * @param refresh tru to refresh the display. + * @param refresh true to refresh the display. */ public abstract void add(MessageRow row, boolean refresh); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java index aae0b3923..67207cde3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java @@ -929,18 +929,18 @@ public void onUnexpectedError(Exception e) { */ protected boolean canAddEvent(final Event event) { final String type = event.getType(); - return mDisplayAllEvents || - Event.EVENT_TYPE_MESSAGE.equals(type) || - Event.EVENT_TYPE_MESSAGE_ENCRYPTED.equals(type) || - Event.EVENT_TYPE_MESSAGE_ENCRYPTION.equals(type) || - Event.EVENT_TYPE_STATE_ROOM_NAME.equals(type) || - Event.EVENT_TYPE_STATE_ROOM_TOPIC.equals(type) || - Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(type) || - Event.EVENT_TYPE_STATE_ROOM_THIRD_PARTY_INVITE.equals(type) || - Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY.equals(type) || - Event.EVENT_TYPE_STICKER.equals(type) || - Event.EVENT_TYPE_STATE_ROOM_CREATE.equals(type) || - (event.isCallEvent() && !Event.EVENT_TYPE_CALL_CANDIDATES.equals(type)); + return mDisplayAllEvents + || Event.EVENT_TYPE_MESSAGE.equals(type) + || Event.EVENT_TYPE_MESSAGE_ENCRYPTED.equals(type) + || Event.EVENT_TYPE_MESSAGE_ENCRYPTION.equals(type) + || Event.EVENT_TYPE_STATE_ROOM_NAME.equals(type) + || Event.EVENT_TYPE_STATE_ROOM_TOPIC.equals(type) + || Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(type) + || Event.EVENT_TYPE_STATE_ROOM_THIRD_PARTY_INVITE.equals(type) + || Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY.equals(type) + || Event.EVENT_TYPE_STICKER.equals(type) + || Event.EVENT_TYPE_STATE_ROOM_CREATE.equals(type) + || (event.isCallEvent() && !Event.EVENT_TYPE_CALL_CANDIDATES.equals(type)); } //============================================================================================================== From e9c4bf4d5c78634b48f2cd1f808160a7ff54d3c7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 17 Sep 2018 10:39:09 +0200 Subject: [PATCH 172/236] Fix performance issue: messages are not aligned to bottom of screen anymore. --- .../main/res/layout/fragment_matrix_message_list_fragment.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/matrix-sdk/src/main/res/layout/fragment_matrix_message_list_fragment.xml b/matrix-sdk/src/main/res/layout/fragment_matrix_message_list_fragment.xml index a0590cdeb..22ce4e9ae 100644 --- a/matrix-sdk/src/main/res/layout/fragment_matrix_message_list_fragment.xml +++ b/matrix-sdk/src/main/res/layout/fragment_matrix_message_list_fragment.xml @@ -9,8 +9,7 @@ Date: Mon, 17 Sep 2018 13:51:46 +0200 Subject: [PATCH 173/236] Add comment --- .../src/main/java/org/matrix/androidsdk/data/RoomState.java | 1 + .../org/matrix/androidsdk/view/AutoScrollDownListView.java | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index a4cbc8d73..90c374012 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -185,6 +185,7 @@ public class RoomState implements Externalizable { private boolean mIsLive; // the unitary tests crash when MXDataHandler type is set. + // TODO Try to avoid this ^^ private transient Object mDataHandler = null; // member display cache diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/view/AutoScrollDownListView.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/view/AutoScrollDownListView.java index b916b1a29..428788158 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/view/AutoScrollDownListView.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/view/AutoScrollDownListView.java @@ -1,6 +1,7 @@ /* * Copyright 2014 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -24,6 +25,7 @@ /** * The listView automatically scrolls down when its height is updated. * It is used to scroll the list when the keyboard is displayed + * Note that the list scrolls down automatically thank to android:transcriptMode="normal" in the XML */ public class AutoScrollDownListView extends ListView { private static final String LOG_TAG = AutoScrollDownListView.class.getSimpleName(); From e9a7e62a3c9c165c87af6051fb9e6b0aadf9b347 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 17 Sep 2018 14:28:28 +0200 Subject: [PATCH 174/236] Remove unused classes --- .../rest/model/MessageFeedback.java | 21 ----------- .../androidsdk/rest/model/StrippedState.java | 37 ------------------- 2 files changed, 58 deletions(-) delete mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/MessageFeedback.java delete mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/StrippedState.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/MessageFeedback.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/MessageFeedback.java deleted file mode 100644 index 397cb15a8..000000000 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/MessageFeedback.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * - * 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 org.matrix.androidsdk.rest.model; - -public class MessageFeedback { - public String type; - public String targetEventId; -} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/StrippedState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/StrippedState.java deleted file mode 100644 index 706fa2707..000000000 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/StrippedState.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * - * 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 org.matrix.androidsdk.rest.model; - -/** - * subclass representing a subset of the state of the room at the time of the invite, if membership is invite - */ -public class StrippedState implements java.io.Serializable { - - /** - * The content for the event. - */ - EventContent content; - - /** - * The type for the event. One of: ["m.room.join_rules", "m.room.canonical_alias", "m.room.avatar", "m.room.name"] - */ - String type; - - /** - * The state_key for the event - */ - String state_key; -} \ No newline at end of file From 1a4690066207d32458300029965fbb0a8f20c4e0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 17 Sep 2018 14:30:47 +0200 Subject: [PATCH 175/236] Avoid using internal RoomState class to parse data received from the server --- .../org/matrix/androidsdk/data/RoomState.java | 25 +++++----- .../androidsdk/rest/model/StateEvent.java | 50 +++++++++++++++++++ .../org/matrix/androidsdk/util/JsonUtils.java | 8 +-- 3 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/StateEvent.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 90c374012..b1d91bd77 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -101,9 +101,8 @@ public class RoomState implements Externalizable { // private Map> mStateEvents = new HashMap<>(); - // The canonical alias of the room. Keep it public for Gson, because private fields are excluded. - @SerializedName("alias") - public String canonicalAlias; + // The canonical alias of the room. + private String canonicalAlias; // The name of the room as provided by the home server. public String name; @@ -876,19 +875,19 @@ public boolean applyState(IMXStore store, Event event, EventTimeline.Direction d try { if (Event.EVENT_TYPE_STATE_ROOM_NAME.equals(eventType)) { - name = JsonUtils.toRoomState(contentToConsider).name; + name = JsonUtils.toStateEvent(contentToConsider).name; } else if (Event.EVENT_TYPE_STATE_ROOM_TOPIC.equals(eventType)) { - topic = JsonUtils.toRoomState(contentToConsider).topic; + topic = JsonUtils.toStateEvent(contentToConsider).topic; } else if (Event.EVENT_TYPE_STATE_ROOM_CREATE.equals(eventType)) { mRoomCreateContent = JsonUtils.toRoomCreateContent(contentToConsider); } else if (Event.EVENT_TYPE_STATE_ROOM_JOIN_RULES.equals(eventType)) { - join_rule = JsonUtils.toRoomState(contentToConsider).join_rule; + join_rule = JsonUtils.toStateEvent(contentToConsider).joinRule; } else if (Event.EVENT_TYPE_STATE_ROOM_GUEST_ACCESS.equals(eventType)) { - guest_access = JsonUtils.toRoomState(contentToConsider).guest_access; + guest_access = JsonUtils.toStateEvent(contentToConsider).guestAccess; } else if (Event.EVENT_TYPE_STATE_ROOM_ALIASES.equals(eventType)) { if (!TextUtils.isEmpty(event.stateKey)) { // backward compatibility - aliases = JsonUtils.toRoomState(contentToConsider).aliases; + aliases = JsonUtils.toStateEvent(contentToConsider).aliases; // sanity check if (null != aliases) { @@ -899,7 +898,7 @@ public boolean applyState(IMXStore store, Event event, EventTimeline.Direction d } } } else if (Event.EVENT_TYPE_MESSAGE_ENCRYPTION.equals(eventType)) { - algorithm = JsonUtils.toRoomState(contentToConsider).algorithm; + algorithm = JsonUtils.toStateEvent(contentToConsider).algorithm; // When a client receives an m.room.encryption event as above, it should set a flag to indicate that messages sent // in the room should be encrypted. @@ -911,14 +910,14 @@ public boolean applyState(IMXStore store, Event event, EventTimeline.Direction d } } else if (Event.EVENT_TYPE_STATE_CANONICAL_ALIAS.equals(eventType)) { // SPEC-125 - canonicalAlias = JsonUtils.toRoomState(contentToConsider).canonicalAlias; + canonicalAlias = JsonUtils.toStateEvent(contentToConsider).canonicalAlias; } else if (Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY.equals(eventType)) { // SPEC-134 - history_visibility = JsonUtils.toRoomState(contentToConsider).history_visibility; + history_visibility = JsonUtils.toStateEvent(contentToConsider).historyVisibility; } else if (Event.EVENT_TYPE_STATE_ROOM_AVATAR.equals(eventType)) { - url = JsonUtils.toRoomState(contentToConsider).url; + url = JsonUtils.toStateEvent(contentToConsider).url; } else if (Event.EVENT_TYPE_STATE_RELATED_GROUPS.equals(eventType)) { - groups = JsonUtils.toRoomState(contentToConsider).groups; + groups = JsonUtils.toStateEvent(contentToConsider).groups; } else if (Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(eventType)) { RoomMember member = JsonUtils.toRoomMember(contentToConsider); String userId = event.stateKey; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/StateEvent.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/StateEvent.java new file mode 100644 index 000000000..25efa3d6a --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/StateEvent.java @@ -0,0 +1,50 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.rest.model; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +/** + * Class representing a state event content + * Usually, only one field is not null, depending of the type of the Event. + */ +public class StateEvent { + public String name; + + public String topic; + + @SerializedName("join_rule") + public String joinRule; + + @SerializedName("guest_access") + public String guestAccess; + + @SerializedName("alias") + public String canonicalAlias; + + public List aliases; + + public String algorithm; + + @SerializedName("history_visibility") + public String historyVisibility; + + public String url; + + public List groups; +} \ No newline at end of file diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java index d66668164..2ab142c0a 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/JsonUtils.java @@ -26,7 +26,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.rest.json.BooleanDeserializer; import org.matrix.androidsdk.rest.json.ConditionDeserializer; import org.matrix.androidsdk.rest.json.MatrixFieldNamingStrategy; @@ -40,6 +39,7 @@ import org.matrix.androidsdk.rest.model.RoomPinnedEventsContent; import org.matrix.androidsdk.rest.model.RoomTags; import org.matrix.androidsdk.rest.model.RoomTombstoneContent; +import org.matrix.androidsdk.rest.model.StateEvent; import org.matrix.androidsdk.rest.model.User; import org.matrix.androidsdk.rest.model.bingrules.Condition; import org.matrix.androidsdk.rest.model.crypto.EncryptedEventContent; @@ -112,14 +112,14 @@ public static Gson getGson(boolean withNullSerialization) { } /** - * Convert a JSON object to a room state. + * Convert a JSON object to a state event. * The result is never null. * * @param jsonObject the json to convert * @return a room state */ - public static RoomState toRoomState(JsonElement jsonObject) { - return toClass(jsonObject, RoomState.class); + public static StateEvent toStateEvent(JsonElement jsonObject) { + return toClass(jsonObject, StateEvent.class); } /** From 57b18c23090e9c3943c07ab45347ed0c1e788e38 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 17 Sep 2018 14:31:01 +0200 Subject: [PATCH 176/236] typo --- .../main/java/org/matrix/androidsdk/rest/model/AuthParams.java | 2 +- .../java/org/matrix/androidsdk/rest/model/EventContent.java | 2 +- .../java/org/matrix/androidsdk/rest/model/RedactedBecause.java | 2 +- .../java/org/matrix/androidsdk/rest/model/RedactedContent.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/AuthParams.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/AuthParams.java index 53e14b6d6..56b98108e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/AuthParams.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/AuthParams.java @@ -18,7 +18,7 @@ import java.util.Map; /** - * Class to define the authentification parameters + * Class to define the authentication parameters */ public class AuthParams { // diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/EventContent.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/EventContent.java index ea5614dd6..c7348a83b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/EventContent.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/EventContent.java @@ -28,7 +28,7 @@ public class EventContent implements java.io.Serializable { public String displayname; /** - * The avatar URL for this user, if any. T + * The avatar URL for this user, if any. */ public String avatar_url; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RedactedBecause.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RedactedBecause.java index 8fa9f4d6f..1496f5315 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RedactedBecause.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RedactedBecause.java @@ -20,7 +20,7 @@ */ public class RedactedBecause implements java.io.Serializable { - // should be m.room.redaction" + // should be m.room.redaction" public String type; // diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RedactedContent.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RedactedContent.java index 9573226c3..ec9a0c614 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RedactedContent.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RedactedContent.java @@ -20,6 +20,6 @@ */ public class RedactedContent implements java.io.Serializable { - // the redaction reason + // the redaction reason public String reason; } \ No newline at end of file From faaf05b64f0db83582f9124815ad7283ee387b4c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 17 Sep 2018 14:50:39 +0200 Subject: [PATCH 177/236] Remove unused class --- .../rest/model/group/GetRoomsResponse.java | 30 ------------------- 1 file changed, 30 deletions(-) delete mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GetRoomsResponse.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GetRoomsResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GetRoomsResponse.java deleted file mode 100644 index baf1eb79c..000000000 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GetRoomsResponse.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2014 OpenMarket Ltd - * - * 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 org.matrix.androidsdk.rest.model.group; - -import org.matrix.androidsdk.rest.model.publicroom.PublicRoom; - -import java.util.List; - -/** - * Get rooms list response - */ -public class GetRoomsResponse { - /** - * Rooms list - */ - public List chunk; -} From a2f65d8f93c6eef7f664a4dd8eca659c67cd2d35 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 17 Sep 2018 15:50:21 +0200 Subject: [PATCH 178/236] Better model for PublicRoom and GroupRoom --- .../androidsdk/data/RoomPreviewData.java | 23 +++++++++++++++ .../rest/model/group/GroupRoom.java | 4 +-- .../rest/model/publicroom/PublicRoom.java | 29 +++++++++++++++---- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomPreviewData.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomPreviewData.java index 0b1d6c491..7a909ffa3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomPreviewData.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomPreviewData.java @@ -18,12 +18,14 @@ import android.os.AsyncTask; import android.os.Looper; +import android.support.annotation.Nullable; import android.text.TextUtils; import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.MatrixError; +import org.matrix.androidsdk.rest.model.publicroom.PublicRoom; import org.matrix.androidsdk.rest.model.sync.RoomResponse; import org.matrix.androidsdk.util.Log; @@ -57,6 +59,9 @@ public class RoomPreviewData { // the room state private RoomState mRoomState; + // If the RoomState cannot be retrieved, this may contains some data + private PublicRoom mPublicRoom; + // the initial sync data private RoomResponse mRoomResponse; @@ -88,10 +93,19 @@ public RoomPreviewData(MXSession session, String roomId, String eventId, String /** * @return the room state */ + @Nullable public RoomState getRoomState() { return mRoomState; } + /** + * @return the public room data + */ + @Nullable + public PublicRoom getPublicRoom() { + return mPublicRoom; + } + /** * Update the room state. * @@ -248,4 +262,13 @@ public void onUnexpectedError(Exception e) { } }); } + + /** + * Set Public RoomData, In case RoomState cannot be retrieved + * + * @param publicRoom + */ + public void setPublicRoom(PublicRoom publicRoom) { + mPublicRoom = publicRoom; + } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupRoom.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupRoom.java index 9a240e18b..e86f78ab1 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupRoom.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/group/GroupRoom.java @@ -32,8 +32,8 @@ public String getDisplayName() { return name; } - if (!TextUtils.isEmpty(getCanonicalAlias())) { - return getCanonicalAlias(); + if (!TextUtils.isEmpty(canonicalAlias)) { + return canonicalAlias; } return roomId; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/publicroom/PublicRoom.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/publicroom/PublicRoom.java index 3ea636f0a..4bd9b6605 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/publicroom/PublicRoom.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/publicroom/PublicRoom.java @@ -15,22 +15,39 @@ */ package org.matrix.androidsdk.rest.model.publicroom; -import org.matrix.androidsdk.data.RoomState; +import com.google.gson.annotations.SerializedName; + +import java.util.List; /** * Class representing the objects returned by /publicRooms call. */ -public class PublicRoom extends RoomState implements java.io.Serializable { +public class PublicRoom { + + public List aliases; + + @SerializedName("canonical_alias") + public String canonicalAlias; + + public String name; // number of members which have joined the room (the members list is not provided) + @SerializedName("num_joined_members") public int numJoinedMembers; - // the server name - public String serverName; + @SerializedName("room_id") + public String roomId; + + public String topic; // true when the room history is visible (room preview) - public Boolean worldReadable; + @SerializedName("world_readable") + public boolean worldReadable; // a guest can join the room - public Boolean guestCanJoin; + @SerializedName("guest_can_join") + public boolean guestCanJoin; + + @SerializedName("avatar_url") + public String avatarUrl; } From eb87e1aaa7b631d0a60e013ef03353d389d13d42 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 17 Sep 2018 18:25:57 +0200 Subject: [PATCH 179/236] Fix crash on global search screen --- .../fragments/MatrixMessageListFragment.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java index 67207cde3..89c9a93f2 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java @@ -543,14 +543,17 @@ public boolean onTouch(View v, MotionEvent event) { mDisplayAllEvents = isDisplayAllEvents(); // Ensure all RoomMember are loaded (ignore error) - mRoom.getMembersAsync(new SimpleApiCallback>() { - @Override - public void onSuccess(List info) { - if (isAdded()) { - mAdapter.setLiveRoomMembers(info); + // mRoom can be null for global search + if (mRoom != null) { + mRoom.getMembersAsync(new SimpleApiCallback>() { + @Override + public void onSuccess(List info) { + if (isAdded()) { + mAdapter.setLiveRoomMembers(info); + } } - } - }); + }); + } return v; } From 8b71cfae1e6ed90a17e64565783ba88bdabbc2b4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Sep 2018 09:34:08 +0200 Subject: [PATCH 180/236] Add Fixme --- .../org/matrix/androidsdk/rest/model/message/ImageMessage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/message/ImageMessage.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/message/ImageMessage.java index 5548ff10e..1d764ce5b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/message/ImageMessage.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/message/ImageMessage.java @@ -35,7 +35,7 @@ public ImageMessage() { /** * Make a deep copy of this ImageMessage. - * + * FIXME Remove this? * @return the copy */ public ImageMessage deepCopy() { From 299a0c4a1768efbca2c61abe45152e8b80f7b69d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Sep 2018 10:15:02 +0200 Subject: [PATCH 181/236] Ganfra review: split long method --- .../java/org/matrix/androidsdk/MXSession.java | 227 +++++++++++------- 1 file changed, 135 insertions(+), 92 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index 18da5e2f9..1d88aade8 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -1720,122 +1720,118 @@ public Double tagOrderToBeAtIndex(int index, int originIndex, String tag) { * @param aParticipantUserId the participant user id * @param callback the asynchronous callback */ - public void toggleDirectChatRoom(final String roomId, String aParticipantUserId, final ApiCallback callback) { + public void toggleDirectChatRoom(final String roomId, + @Nullable final String aParticipantUserId, + final ApiCallback callback) { IMXStore store = getDataHandler().getStore(); Room room = store.getRoom(roomId); if (null != room) { - // if the room was not yet seen as direct chat - if (!getDataHandler().getDirectChatRoomIdsList().contains(roomId)) { + if (getDataHandler().getDirectChatRoomIdsList().contains(roomId)) { + // The room is already seen as direct chat + removeDirectChatRoomFromAccountData(roomId, callback); + } else { + // The room was not yet seen as direct chat if (null == aParticipantUserId) { - room.getActiveMembersAsync(new SimpleApiCallback>(callback) { + searchOtherUserInRoomToCreateDirectChat(room, new SimpleApiCallback(callback) { @Override - public void onSuccess(List members) { - // should never happen but it was reported by a GA issue - if (members.isEmpty()) { - return; - } - - RoomMember directChatMember = null; - - if (members.size() > 1) { - // sort algo: oldest join first, then oldest invited - Collections.sort(members, new Comparator() { - @Override - public int compare(RoomMember r1, RoomMember r2) { - int res; - long diff; - - if (RoomMember.MEMBERSHIP_JOIN.equals(r2.membership) && RoomMember.MEMBERSHIP_INVITE.equals(r1.membership)) { - res = 1; - } else if (r2.membership.equals(r1.membership)) { - diff = r1.getOriginServerTs() - r2.getOriginServerTs(); - res = (0 == diff) ? 0 : ((diff > 0) ? 1 : -1); - } else { - res = -1; - } - return res; - } - }); - - int nextIndexSearch = 0; - - // take the oldest join member - if (!TextUtils.equals(members.get(0).getUserId(), getMyUserId())) { - if (RoomMember.MEMBERSHIP_JOIN.equals(members.get(0).membership)) { - directChatMember = members.get(0); - } - } else { - nextIndexSearch = 1; - if (RoomMember.MEMBERSHIP_JOIN.equals(members.get(1).membership)) { - directChatMember = members.get(1); - } - } - - // no join member found, test the oldest join member - if (null == directChatMember) { - if (RoomMember.MEMBERSHIP_INVITE.equals(members.get(nextIndexSearch).membership)) { - directChatMember = members.get(nextIndexSearch); - } - } - } - - // last option: get the logged user - if (null == directChatMember) { - directChatMember = members.get(0); - } - - toggleDirectChatRoomStep2(roomId, directChatMember.getUserId(), callback); + public void onSuccess(String info) { + addDirectChatRoomToAccountData(roomId, info, callback); } }); } else { - toggleDirectChatRoomStep2(roomId, aParticipantUserId, callback); + addDirectChatRoomToAccountData(roomId, aParticipantUserId, callback); } - } else { - Map> params; + } + } else { + if (callback != null) { + callback.onUnexpectedError(new Exception("Unknown room")); + } + } + } - if (null != store.getDirectChatRoomsDict()) { - params = new HashMap<>(store.getDirectChatRoomsDict()); - } else { - params = new HashMap<>(); - } + /** + * Search another user in the room to create a direct chat + * + * @param room the room to search in + * @param callback the callback to get the selected user id + */ + private void searchOtherUserInRoomToCreateDirectChat(@NonNull final Room room, + @NonNull final ApiCallback callback) { + room.getActiveMembersAsync(new SimpleApiCallback>(callback) { + @Override + public void onSuccess(List members) { + // should never happen but it was reported by a GA issue + if (members.isEmpty()) { + callback.onUnexpectedError(new Exception("Error")); - // remove the current room from the direct chat list rooms - if (null != store.getDirectChatRoomsDict()) { - List keysList = new ArrayList<>(params.keySet()); + return; + } - for (String key : keysList) { - List roomIdsList = params.get(key); - if (roomIdsList.contains(roomId)) { - roomIdsList.remove(roomId); + RoomMember directChatMember = null; - if (roomIdsList.isEmpty()) { - // Remove this entry - params.remove(key); + if (members.size() > 1) { + // sort algo: oldest join first, then oldest invited + Collections.sort(members, new Comparator() { + @Override + public int compare(RoomMember r1, RoomMember r2) { + int res; + long diff; + + if (RoomMember.MEMBERSHIP_JOIN.equals(r2.membership) && RoomMember.MEMBERSHIP_INVITE.equals(r1.membership)) { + res = 1; + } else if (r2.membership.equals(r1.membership)) { + diff = r1.getOriginServerTs() - r2.getOriginServerTs(); + res = (0 == diff) ? 0 : ((diff > 0) ? 1 : -1); + } else { + res = -1; } + return res; + } + }); + + int nextIndexSearch = 0; + + // take the oldest join member + if (!TextUtils.equals(members.get(0).getUserId(), getMyUserId())) { + if (RoomMember.MEMBERSHIP_JOIN.equals(members.get(0).membership)) { + directChatMember = members.get(0); + } + } else { + nextIndexSearch = 1; + if (RoomMember.MEMBERSHIP_JOIN.equals(members.get(1).membership)) { + directChatMember = members.get(1); + } + } + + // no join member found, test the oldest join member + if (null == directChatMember) { + if (RoomMember.MEMBERSHIP_INVITE.equals(members.get(nextIndexSearch).membership)) { + directChatMember = members.get(nextIndexSearch); } } - } else { - // should not happen: if the room has to be removed, it means the room has been - // previously detected as being part of the listOfList - Log.e(LOG_TAG, "## toggleDirectChatRoom(): failed to remove a direct chat room (not seen as direct chat room)"); - return; } - // Store and upload the updated map - getDataHandler().setDirectChatRoomsMap(params, callback); + // last option: get the logged user + if (null == directChatMember) { + directChatMember = members.get(0); + } + + callback.onSuccess(directChatMember.getUserId()); } - } + }); } /** - * @param roomId - * @param chosenUserId - * @param callback + * Add the room to the direct chat room list in AccountData + * + * @param roomId the room roomId + * @param chosenUserId userId of the direct chat room + * @param callback the asynchronous callback */ - private void toggleDirectChatRoomStep2(String roomId, - @NonNull String chosenUserId, - ApiCallback callback) { + private void addDirectChatRoomToAccountData(String roomId, + @NonNull String chosenUserId, + ApiCallback callback) { IMXStore store = getDataHandler().getStore(); Map> params; @@ -1859,6 +1855,53 @@ private void toggleDirectChatRoomStep2(String roomId, getDataHandler().setDirectChatRoomsMap(params, callback); } + /** + * Remove the room to the direct chat room list in AccountData + * + * @param roomId the room roomId + * @param callback the asynchronous callback + */ + private void removeDirectChatRoomFromAccountData(String roomId, + ApiCallback callback) { + IMXStore store = getDataHandler().getStore(); + + Map> params; + + if (null != store.getDirectChatRoomsDict()) { + params = new HashMap<>(store.getDirectChatRoomsDict()); + } else { + params = new HashMap<>(); + } + + // remove the current room from the direct chat list rooms + if (null != store.getDirectChatRoomsDict()) { + List keysList = new ArrayList<>(params.keySet()); + + for (String key : keysList) { + List roomIdsList = params.get(key); + if (roomIdsList.contains(roomId)) { + roomIdsList.remove(roomId); + + if (roomIdsList.isEmpty()) { + // Remove this entry + params.remove(key); + } + } + } + } else { + // should not happen: if the room has to be removed, it means the room has been + // previously detected as being part of the listOfList + Log.e(LOG_TAG, "## removeDirectChatRoomFromAccountData(): failed to remove a direct chat room (not seen as direct chat room)"); + if (callback != null) { + callback.onUnexpectedError(new Exception("Error")); + } + return; + } + + // Store and upload the updated map + getDataHandler().setDirectChatRoomsMap(params, callback); + } + /** * Update the account password * From 03439f98385cf92bd56b665124576d8c12453ecb Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Sep 2018 10:31:43 +0200 Subject: [PATCH 182/236] Ganfra review: remove useless synchronized --- .../main/java/org/matrix/androidsdk/data/RoomState.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index b1d91bd77..ed9e2921f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -22,7 +22,6 @@ import android.text.TextUtils; import com.google.gson.JsonObject; -import com.google.gson.annotations.SerializedName; import org.matrix.androidsdk.MXDataHandler; import org.matrix.androidsdk.call.MXCallsManager; @@ -306,10 +305,8 @@ public void onSuccess(List info) { synchronized (mGetAllMembersCallbacks) { for (ApiCallback> apiCallback : mGetAllMembersCallbacks) { - synchronized (this) { - // make a copy to avoid concurrency modifications - res = new ArrayList<>(mMembers.values()); - } + // make a copy to avoid concurrency modifications + res = new ArrayList<>(mMembers.values()); apiCallback.onSuccess(res); } From 12bcad9dc654c30c0c55c9a4ab646908759abed8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Sep 2018 10:41:29 +0200 Subject: [PATCH 183/236] Ganfra review: introduce static list of supported type and known unsupported type --- .../matrix/androidsdk/data/RoomSummary.java | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index 5bfb7ecd8..3a8a21ac3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -34,6 +34,7 @@ import org.matrix.androidsdk.util.Log; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -47,6 +48,30 @@ public class RoomSummary implements java.io.Serializable { private static final long serialVersionUID = -3683013938626566489L; + // list of supported types + private static final List sSupportedType = Arrays.asList( + Event.EVENT_TYPE_STATE_ROOM_TOPIC, + Event.EVENT_TYPE_MESSAGE_ENCRYPTED, + Event.EVENT_TYPE_MESSAGE_ENCRYPTION, + Event.EVENT_TYPE_STATE_ROOM_NAME, + Event.EVENT_TYPE_STATE_ROOM_MEMBER, + Event.EVENT_TYPE_STATE_ROOM_CREATE, + Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY, + Event.EVENT_TYPE_STATE_ROOM_THIRD_PARTY_INVITE, + Event.EVENT_TYPE_STICKER); + + // List of known unsupported types + private static final List sKnownUnsupportedType = Arrays.asList( + Event.EVENT_TYPE_TYPING, + Event.EVENT_TYPE_STATE_ROOM_POWER_LEVELS, + Event.EVENT_TYPE_STATE_ROOM_JOIN_RULES, + Event.EVENT_TYPE_STATE_CANONICAL_ALIAS, + Event.EVENT_TYPE_STATE_ROOM_ALIASES, + Event.EVENT_TYPE_URL_PREVIEW, + Event.EVENT_TYPE_STATE_RELATED_GROUPS, + Event.EVENT_TYPE_STATE_ROOM_GUEST_ACCESS, + Event.EVENT_TYPE_REDACTION); + private String mRoomId = null; private String mTopic = null; private Event mLatestReceivedEvent = null; @@ -220,30 +245,14 @@ public static boolean isSupportedEvent(Event event) { } } } else { - isSupported = TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_TOPIC, type) - || TextUtils.equals(Event.EVENT_TYPE_MESSAGE_ENCRYPTED, type) - || TextUtils.equals(Event.EVENT_TYPE_MESSAGE_ENCRYPTION, type) - || TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_NAME, type) - || TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_MEMBER, type) - || TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_CREATE, type) - || TextUtils.equals(Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY, type) - || TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_THIRD_PARTY_INVITE, type) - || TextUtils.equals(Event.EVENT_TYPE_STICKER, type) + isSupported = sSupportedType.contains(type) || (event.isCallEvent() && !TextUtils.isEmpty(type) && !Event.EVENT_TYPE_CALL_CANDIDATES.equals(type)); } if (!isSupported) { // some events are known to be never traced // avoid warning when it is not required. - if (!TextUtils.equals(Event.EVENT_TYPE_TYPING, type) - && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_POWER_LEVELS, type) - && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_JOIN_RULES, type) - && !TextUtils.equals(Event.EVENT_TYPE_STATE_CANONICAL_ALIAS, type) - && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_ALIASES, type) - && !TextUtils.equals(Event.EVENT_TYPE_URL_PREVIEW, type) - && !TextUtils.equals(Event.EVENT_TYPE_STATE_RELATED_GROUPS, type) - && !TextUtils.equals(Event.EVENT_TYPE_STATE_ROOM_GUEST_ACCESS, type) - && !TextUtils.equals(Event.EVENT_TYPE_REDACTION, type)) { + if (!sKnownUnsupportedType.contains(type)) { Log.e(LOG_TAG, "isSupportedEvent : Unsupported event type " + type); } } From 097aa6da3b035e369cb7bf56ec7c2dbd8b27ad14 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Sep 2018 10:42:09 +0200 Subject: [PATCH 184/236] Ganfra review: rename MxRoomEventListener to MXRoomEventListener --- .../src/main/java/org/matrix/androidsdk/data/Room.java | 4 ++-- .../{MxRoomEventListener.java => MXRoomEventListener.java} | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/{MxRoomEventListener.java => MXRoomEventListener.java} (97%) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 72da92447..d7de0fae2 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -47,7 +47,7 @@ import org.matrix.androidsdk.db.MXMediasCache; import org.matrix.androidsdk.listeners.IMXEventListener; import org.matrix.androidsdk.listeners.MXEventListener; -import org.matrix.androidsdk.listeners.MxRoomEventListener; +import org.matrix.androidsdk.listeners.MXRoomEventListener; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.client.AccountDataRestClient; @@ -2056,7 +2056,7 @@ public void addEventListener(final IMXEventListener eventListener) { } // Create a global listener that we'll add to the data handler - IMXEventListener globalListener = new MxRoomEventListener(this, eventListener); + IMXEventListener globalListener = new MXRoomEventListener(this, eventListener); mEventListeners.put(eventListener, globalListener); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MxRoomEventListener.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MXRoomEventListener.java similarity index 97% rename from matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MxRoomEventListener.java rename to matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MXRoomEventListener.java index f20efac69..7a92f7db4 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MxRoomEventListener.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/listeners/MXRoomEventListener.java @@ -30,15 +30,15 @@ /** * A listener which filter event for a specific room */ -public class MxRoomEventListener extends MXEventListener { +public class MXRoomEventListener extends MXEventListener { - private static final String LOG_TAG = MxRoomEventListener.class.getSimpleName(); + private static final String LOG_TAG = MXRoomEventListener.class.getSimpleName(); private final String mRoomId; private final IMXEventListener mEventListener; private final Room mRoom; - public MxRoomEventListener(@NonNull Room room, + public MXRoomEventListener(@NonNull Room room, @NonNull IMXEventListener eventListener) { mRoom = room; mRoomId = room.getRoomId(); From f8065622a913b128b61e4c75c9d6cfa162ae1d8a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Sep 2018 10:44:16 +0200 Subject: [PATCH 185/236] Ganfra review: rename ApiSuccessCallback to SuccessCallback --- .../java/org/matrix/androidsdk/rest/callback/ApiCallback.java | 2 +- .../callback/{ApiSuccessCallback.java => SuccessCallback.java} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/{ApiSuccessCallback.java => SuccessCallback.java} (95%) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiCallback.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiCallback.java index 5a3afab3e..079ab44fe 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiCallback.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiCallback.java @@ -21,6 +21,6 @@ * * @param the type of information to return on success */ -public interface ApiCallback extends ApiSuccessCallback, ApiFailureCallback { +public interface ApiCallback extends SuccessCallback, ApiFailureCallback { } \ No newline at end of file diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiSuccessCallback.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/SuccessCallback.java similarity index 95% rename from matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiSuccessCallback.java rename to matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/SuccessCallback.java index c1f92639d..e61af3c3f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/ApiSuccessCallback.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/callback/SuccessCallback.java @@ -16,7 +16,7 @@ package org.matrix.androidsdk.rest.callback; -public interface ApiSuccessCallback { +public interface SuccessCallback { /** * Called if the result is successful. * From 521aa7a81a056bcc70e73e93ee8a455be91c3e57 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Sep 2018 10:48:09 +0200 Subject: [PATCH 186/236] Ganfra review: avoid creating instances of Gson --- .../org/matrix/androidsdk/rest/model/filter/FilterBody.java | 5 +++-- .../matrix/androidsdk/rest/model/filter/RoomEventFilter.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java index 060537194..0c1208208 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/FilterBody.java @@ -16,9 +16,10 @@ */ package org.matrix.androidsdk.rest.model.filter; -import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; +import org.matrix.androidsdk.util.JsonUtils; + import java.util.List; /** @@ -48,6 +49,6 @@ public String toString() { } public String toJSONString() { - return new Gson().toJson(this); + return JsonUtils.getGson(false).toJson(this); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java index aa7b178c5..05510e305 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/filter/RoomEventFilter.java @@ -16,9 +16,10 @@ */ package org.matrix.androidsdk.rest.model.filter; -import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; +import org.matrix.androidsdk.util.JsonUtils; + import java.util.List; /** @@ -63,6 +64,6 @@ public boolean hasData() { } public String toJSONString() { - return new Gson().toJson(this); + return JsonUtils.getGson(false).toJson(this); } } From 5314d7974243c9768828c6c7ca5be3a34149e6e1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Sep 2018 10:49:17 +0200 Subject: [PATCH 187/236] Ganfra review: rename members --- .../java/org/matrix/androidsdk/data/RoomSummary.java | 12 ++++++------ .../androidsdk/rest/model/sync/RoomSyncSummary.java | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java index 3a8a21ac3..3641a239d 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomSummary.java @@ -562,19 +562,19 @@ public void setIsConferenceUserRoom(boolean isConferenceUserRoom) { } public void setRoomSyncSummary(@NonNull RoomSyncSummary roomSyncSummary) { - if (roomSyncSummary.mHeroes != null) { + if (roomSyncSummary.heroes != null) { mHeroes.clear(); - mHeroes.addAll(roomSyncSummary.mHeroes); + mHeroes.addAll(roomSyncSummary.heroes); } - if (roomSyncSummary.mJoinedMembersCount != null) { + if (roomSyncSummary.joinedMembersCount != null) { // Update the value - mJoinedMembersCountFromSyncRoomSummary = roomSyncSummary.mJoinedMembersCount; + mJoinedMembersCountFromSyncRoomSummary = roomSyncSummary.joinedMembersCount; } - if (roomSyncSummary.mInvitedMembersCount != null) { + if (roomSyncSummary.invitedMembersCount != null) { // Update the value - mInvitedMembersCountFromSyncRoomSummary = roomSyncSummary.mInvitedMembersCount; + mInvitedMembersCountFromSyncRoomSummary = roomSyncSummary.invitedMembersCount; } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncSummary.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncSummary.java index 451a035f7..0f8549fd9 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncSummary.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomSyncSummary.java @@ -36,17 +36,17 @@ public class RoomSyncSummary { * the list if helpful for UX */ @SerializedName("m.heroes") - public List mHeroes; + public List heroes; /** * The number of m.room.members in state 'joined' (including the syncing user) (can be null) */ @SerializedName("m.joined_member_count") - public Integer mJoinedMembersCount; + public Integer joinedMembersCount; /** * The number of m.room.members in state 'invited' (can be null) */ @SerializedName("m.invited_member_count") - public Integer mInvitedMembersCount; + public Integer invitedMembersCount; } From 48ecd6d600a7e65950bfcd48052d5c2416d86681 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Sep 2018 11:05:19 +0200 Subject: [PATCH 188/236] Split long lines --- .../androidsdk/call/MXCallsManager.java | 89 ++++++++++--------- .../matrix/androidsdk/crypto/MXCrypto.java | 3 +- .../matrix/androidsdk/data/DataRetriever.java | 4 +- .../java/org/matrix/androidsdk/data/Room.java | 3 +- .../androidsdk/data/store/MXFileStore.java | 4 +- .../rest/client/RoomsRestClient.java | 13 +-- 6 files changed, 63 insertions(+), 53 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java index 9f9f32533..a529c3e63 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java @@ -565,50 +565,53 @@ public void onSuccess(List members) { Log.d(LOG_TAG, "## checkPendingIncomingCalls() : check the unknown devices"); // - mSession.getCrypto().checkUnknownDevices(Arrays.asList(userId1, userId2), new ApiCallback() { - @Override - public void onSuccess(Void anything) { - Log.d(LOG_TAG, "## checkPendingIncomingCalls() : no unknown device"); - dispatchOnIncomingCall(call, null); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "## checkPendingIncomingCalls() : checkUnknownDevices failed " - + e.getMessage(), e); - dispatchOnIncomingCall(call, null); - } - - @Override - public void onMatrixError(MatrixError e) { - MXUsersDevicesMap unknownDevices = null; - - if (e instanceof MXCryptoError) { - MXCryptoError cryptoError = (MXCryptoError) e; - - if (MXCryptoError.UNKNOWN_DEVICES_CODE.equals(cryptoError.errcode)) { - unknownDevices = (MXUsersDevicesMap) cryptoError.mExceptionData; + mSession.getCrypto() + .checkUnknownDevices(Arrays.asList(userId1, userId2), new ApiCallback() { + @Override + public void onSuccess(Void anything) { + Log.d(LOG_TAG, "## checkPendingIncomingCalls() : no unknown device"); + dispatchOnIncomingCall(call, null); } - } - - if (null != unknownDevices) { - Log.d(LOG_TAG, "## checkPendingIncomingCalls() :" + - " checkUnknownDevices found some unknown devices"); - } else { - Log.e(LOG_TAG, "## checkPendingIncomingCalls() :" + - " checkUnknownDevices failed " + e.getMessage()); - } - - dispatchOnIncomingCall(call, unknownDevices); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "## checkPendingIncomingCalls() :" + - " checkUnknownDevices failed " + e.getMessage(), e); - dispatchOnIncomingCall(call, null); - } - }); + + @Override + public void onNetworkError(Exception e) { + Log.e(LOG_TAG, + "## checkPendingIncomingCalls() : checkUnknownDevices failed " + + e.getMessage(), e); + dispatchOnIncomingCall(call, null); + } + + @Override + public void onMatrixError(MatrixError e) { + MXUsersDevicesMap unknownDevices = null; + + if (e instanceof MXCryptoError) { + MXCryptoError cryptoError = (MXCryptoError) e; + + if (MXCryptoError.UNKNOWN_DEVICES_CODE.equals(cryptoError.errcode)) { + unknownDevices = + (MXUsersDevicesMap) cryptoError.mExceptionData; + } + } + + if (null != unknownDevices) { + Log.d(LOG_TAG, "## checkPendingIncomingCalls() :" + + " checkUnknownDevices found some unknown devices"); + } else { + Log.e(LOG_TAG, "## checkPendingIncomingCalls() :" + + " checkUnknownDevices failed " + e.getMessage()); + } + + dispatchOnIncomingCall(call, unknownDevices); + } + + @Override + public void onUnexpectedError(Exception e) { + Log.e(LOG_TAG, "## checkPendingIncomingCalls() :" + + " checkUnknownDevices failed " + e.getMessage(), e); + dispatchOnIncomingCall(call, null); + } + }); } }); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java index 99de55cc9..87383b094 100755 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java @@ -1340,7 +1340,8 @@ public void onUnexpectedError(final Exception e) { getUIHandler().post(new Runnable() { @Override public void run() { - callback.onMatrixError(new MXCryptoError(MXCryptoError.UNABLE_TO_ENCRYPT_ERROR_CODE, MXCryptoError.UNABLE_TO_ENCRYPT, reason)); + callback.onMatrixError(new MXCryptoError(MXCryptoError.UNABLE_TO_ENCRYPT_ERROR_CODE, + MXCryptoError.UNABLE_TO_ENCRYPT, reason)); } }); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java index 7d3acc3db..5dee5ce55 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java @@ -215,7 +215,9 @@ public void onSuccess(TokensChunkEvents tokensChunkEvents) { store.storeRoomEvents(roomId, tokensChunkEvents, EventTimeline.Direction.BACKWARDS); } - Log.d(LOG_TAG, "## backPaginate() succeed : roomId " + roomId + " token " + token + " got " + tokensChunkEvents.chunk.size()); + Log.d(LOG_TAG, "## backPaginate() succeed : roomId " + roomId + + " token " + token + + " got " + tokensChunkEvents.chunk.size()); callback.onSuccess(tokensChunkEvents); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index d7de0fae2..204c2ba4c 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -477,7 +477,8 @@ public void onSuccess(List members) { for (RoomMember member : members) { if (!TextUtils.equals(member.getUserId(), conferenceUserId)) { - if (TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_JOIN) || TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_INVITE)) { + if (TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_JOIN) + || TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_INVITE)) { activeMembers.add(member); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java index 3d0123cab..abd1709b1 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java @@ -504,7 +504,9 @@ public void run() { int membersCount = room.getState().getLoadedMembers().size(); int eventsCount = mRoomEvents.get(roomId).size(); - Log.d(LOG_TAG, " room " + roomId + " : (lazy loaded) membersCount " + membersCount + " - eventsCount " + eventsCount); + Log.d(LOG_TAG, " room " + roomId + + " : (lazy loaded) membersCount " + membersCount + + " - eventsCount " + eventsCount); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index 5de6acd41..f07cc2444 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -572,12 +572,13 @@ public void getDirectoryVisibility(final String aRoomId, final ApiCallback(description, mUnsentEventsManager, callback, new RestAdapterCallback.RequestRetryCallBack() { - @Override - public void onRetry() { - getDirectoryVisibility(aRoomId, callback); - } - })); + .enqueue(new RestAdapterCallback(description, mUnsentEventsManager, callback, + new RestAdapterCallback.RequestRetryCallBack() { + @Override + public void onRetry() { + getDirectoryVisibility(aRoomId, callback); + } + })); } /** From ac2e88fcaf8f9c693577aaa43fcb41191ff835a1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Sep 2018 14:41:13 +0200 Subject: [PATCH 189/236] Cleanup code --- .../java/org/matrix/androidsdk/MXSession.java | 18 ++-- .../androidsdk/call/MXCallsManager.java | 2 +- .../java/org/matrix/androidsdk/data/Room.java | 4 +- .../org/matrix/androidsdk/data/RoomState.java | 4 +- .../rest/model/CreateRoomParams.java | 86 ++++++++++--------- .../androidsdk/rest/model/RoomMember.java | 16 ++-- .../rest/model/sync/InvitedRoomSync.java | 14 +-- .../rest/model/sync/RoomInviteState.java | 5 +- 8 files changed, 78 insertions(+), 71 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java index 1d88aade8..49286e9cd 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXSession.java @@ -36,7 +36,6 @@ import org.matrix.androidsdk.data.DataRetriever; import org.matrix.androidsdk.data.MyUser; import org.matrix.androidsdk.data.Room; -import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.data.RoomSummary; import org.matrix.androidsdk.data.RoomTag; import org.matrix.androidsdk.data.comparator.RoomComparatorWithTag; @@ -1194,25 +1193,23 @@ public void createRoom(final ApiCallback callback) { * @param callback the async callback once the room is ready */ public void createRoom(String name, String topic, String alias, final ApiCallback callback) { - createRoom(name, topic, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PRIVATE, alias, RoomState.GUEST_ACCESS_CAN_JOIN, null, callback); + createRoom(name, topic, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PRIVATE, alias, null, callback); } /** * Create a new room with given properties. Needs the data handler. * - * @param name the room name - * @param topic the room topic - * @param visibility the room visibility - * @param alias the room alias - * @param guestAccess the guest access rule (see {@link RoomState#GUEST_ACCESS_CAN_JOIN} or {@link RoomState#GUEST_ACCESS_FORBIDDEN}) - * @param algorithm the crypto algorithm (null to create an unencrypted room) - * @param callback the async callback once the room is ready + * @param name the room name + * @param topic the room topic + * @param visibility the room visibility + * @param alias the room alias + * @param algorithm the crypto algorithm (null to create an unencrypted room) + * @param callback the async callback once the room is ready */ public void createRoom(String name, String topic, String visibility, String alias, - String guestAccess, String algorithm, final ApiCallback callback) { checkIfAlive(); @@ -1222,7 +1219,6 @@ public void createRoom(String name, params.topic = !TextUtils.isEmpty(topic) ? topic : null; params.visibility = !TextUtils.isEmpty(visibility) ? visibility : null; params.roomAliasName = !TextUtils.isEmpty(alias) ? alias : null; - params.guest_access = !TextUtils.isEmpty(guestAccess) ? guestAccess : null; params.addCryptoAlgorithm(algorithm); createRoom(params, callback); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java index a529c3e63..bd175affb 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java @@ -1118,7 +1118,7 @@ public void run() { CreateRoomParams params = new CreateRoomParams(); params.preset = CreateRoomParams.PRESET_PRIVATE_CHAT; - params.invite = Arrays.asList(conferenceUserId); + params.invitedUserIds = Arrays.asList(conferenceUserId); mSession.createRoom(params, new ApiCallback() { @Override diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 204c2ba4c..1c8a13f38 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -597,8 +597,8 @@ public boolean isDirectChatInvitation() { RoomMember selfMember = state.getMember(mMyUserId); - if ((null != selfMember) && (null != selfMember.is_direct)) { - return selfMember.is_direct; + if ((null != selfMember) && (null != selfMember.isDirect)) { + return selfMember.isDirect; } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index ed9e2921f..fe008ee7a 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -64,11 +64,11 @@ public class RoomState implements Externalizable { /** * room access is granted to guests - **/ + */ public static final String GUEST_ACCESS_CAN_JOIN = "can_join"; /** * room access is denied to guests - **/ + */ public static final String GUEST_ACCESS_FORBIDDEN = "forbidden"; public static final String HISTORY_VISIBILITY_SHARED = "shared"; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/CreateRoomParams.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/CreateRoomParams.java index a7e5690c5..b8739e01f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/CreateRoomParams.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/CreateRoomParams.java @@ -1,13 +1,13 @@ -/* +/* * Copyright 2014 OpenMarket Ltd * Copyright 2018 New Vector Ltd * * 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. @@ -17,8 +17,11 @@ package org.matrix.androidsdk.rest.model; +import android.support.annotation.Nullable; import android.text.TextUtils; +import com.google.gson.annotations.SerializedName; + import org.matrix.androidsdk.HomeServerConnectionConfig; import org.matrix.androidsdk.MXPatterns; import org.matrix.androidsdk.data.RoomState; @@ -51,6 +54,7 @@ public class CreateRoomParams { * The alias will belong on the same homeserver which created the room. * For example, if this was set to "foo" and sent to the homeserver "example.com" the complete room alias would be #foo:example.com. */ + @SerializedName("room_alias_name") public String roomAliasName; /** @@ -65,21 +69,18 @@ public class CreateRoomParams { */ public String topic; - /** - * Whether guests can join the room. One of: ["can_join", "forbidden"] - */ - public String guest_access; - /** * A list of user IDs to invite to the room. * This will tell the server to invite everyone in the list to the newly created room. */ - public List invite; + @SerializedName("invite") + public List invitedUserIds; /** * A list of objects representing third party IDs to invite into the room. */ - public List invite_3pid; + @SerializedName("invite_3pid") + public List invite3pids; /** * Extra keys to be added to the content of the m.room.create. @@ -94,7 +95,8 @@ public class CreateRoomParams { * The expected format of the state events are an object with type, state_key and content keys set. * Takes precedence over events set by presets, but gets overriden by name and topic keys. */ - public List initial_state; + @SerializedName("initial_state") + public List initialStates; /** * Convenience parameter for setting various default state events based on a preset. Must be either: @@ -109,7 +111,8 @@ public class CreateRoomParams { * This flag makes the server set the is_direct flag on the m.room.member events sent to the users in invite and invite_3pid. * See Direct Messaging for more information. */ - public Boolean is_direct; + @SerializedName("is_direct") + public Boolean isDirect; /** * Add the crypto algorithm to the room creation parameters. @@ -125,10 +128,10 @@ public void addCryptoAlgorithm(String algorithm) { contentMap.put("algorithm", algorithm); algoEvent.content = JsonUtils.getGson(false).toJsonTree(contentMap); - if (null == initial_state) { - initial_state = Arrays.asList(algoEvent); + if (null == initialStates) { + initialStates = Arrays.asList(algoEvent); } else { - initial_state.add(algoEvent); + initialStates.add(algoEvent); } } } @@ -137,13 +140,12 @@ public void addCryptoAlgorithm(String algorithm) { * Force the history visibility in the room creation parameters. * * @param historyVisibility the expected history visibility, set null to remove any existing value. - * see {@link RoomState#HISTORY_VISIBILITY_INVITED}, - * {@link RoomState#HISTORY_VISIBILITY_JOINED}, - * {@link RoomState#HISTORY_VISIBILITY_SHARED}, - * {@link RoomState#HISTORY_VISIBILITY_WORLD_READABLE} - * + * see {@link RoomState#HISTORY_VISIBILITY_INVITED}, + * {@link RoomState#HISTORY_VISIBILITY_JOINED}, + * {@link RoomState#HISTORY_VISIBILITY_SHARED}, + * {@link RoomState#HISTORY_VISIBILITY_WORLD_READABLE} */ - public void setHistoryVisibility(String historyVisibility) { + public void setHistoryVisibility(@Nullable String historyVisibility) { if (!TextUtils.isEmpty(historyVisibility)) { Event historyVisibilityEvent = new Event(); historyVisibilityEvent.type = Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY; @@ -152,19 +154,19 @@ public void setHistoryVisibility(String historyVisibility) { contentMap.put("history_visibility", historyVisibility); historyVisibilityEvent.content = JsonUtils.getGson(false).toJsonTree(contentMap); - if (null == initial_state) { - initial_state = Arrays.asList(historyVisibilityEvent); + if (null == initialStates) { + initialStates = Arrays.asList(historyVisibilityEvent); } else { - initial_state.add(historyVisibilityEvent); + initialStates.add(historyVisibilityEvent); } - } else if (!initial_state.isEmpty()) { - final List initialState = new ArrayList<>(); - for (Event event : initial_state) { + } else if (!initialStates.isEmpty()) { + final List newInitialStates = new ArrayList<>(); + for (Event event : initialStates) { if (!event.type.equals(Event.EVENT_TYPE_STATE_HISTORY_VISIBILITY)) { - initialState.add(event); + newInitialStates.add(event); } } - initial_state = initialState; + initialStates = newInitialStates; } } @@ -173,30 +175,30 @@ public void setHistoryVisibility(String historyVisibility) { */ public void setDirectMessage() { preset = CreateRoomParams.PRESET_TRUSTED_PRIVATE_CHAT; - is_direct = true; + isDirect = true; } /** * @return the invite count */ private int getInviteCount() { - return (null == invite) ? 0 : invite.size(); + return (null == invitedUserIds) ? 0 : invitedUserIds.size(); } /** * @return the pid invite count */ private int getInvite3PidCount() { - return (null == invite_3pid) ? 0 : invite_3pid.size(); + return (null == invite3pids) ? 0 : invite3pids.size(); } /** * Tells if the created room can be a direct chat one. * - * @return if it is a direct chat + * @return true if it is a direct chat */ public boolean isDirect() { - return TextUtils.equals(preset, CreateRoomParams.PRESET_TRUSTED_PRIVATE_CHAT) && (null != is_direct) && is_direct && + return TextUtils.equals(preset, CreateRoomParams.PRESET_TRUSTED_PRIVATE_CHAT) && (null != isDirect) && isDirect && (1 == getInviteCount() || (1 == getInvite3PidCount())); } @@ -205,11 +207,11 @@ public boolean isDirect() { */ public String getFirstInvitedUserId() { if (0 != getInviteCount()) { - return invite.get(0); + return invitedUserIds.get(0); } if (0 != getInvite3PidCount()) { - return invite_3pid.get(0).address; + return invite3pids.get(0).address; } return null; @@ -224,8 +226,8 @@ public String getFirstInvitedUserId() { public void addParticipantIds(HomeServerConnectionConfig hsConfig, List ids) { for (String id : ids) { if (android.util.Patterns.EMAIL_ADDRESS.matcher(id).matches()) { - if (null == invite_3pid) { - invite_3pid = new ArrayList<>(); + if (null == invite3pids) { + invite3pids = new ArrayList<>(); } Invite3Pid pid = new Invite3Pid(); @@ -233,15 +235,15 @@ public void addParticipantIds(HomeServerConnectionConfig hsConfig, List pid.medium = ThreePid.MEDIUM_EMAIL; pid.address = id; - invite_3pid.add(pid); + invite3pids.add(pid); } else if (MXPatterns.isUserId(id)) { // do not invite oneself if (!TextUtils.equals(hsConfig.getCredentials().userId, id)) { - if (null == invite) { - invite = new ArrayList<>(); + if (null == invitedUserIds) { + invitedUserIds = new ArrayList<>(); } - invite.add(id); + invitedUserIds.add(id); } } // TODO add phonenumbers when it will be available diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomMember.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomMember.java index 1a1fcbe2e..8006c1474 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomMember.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/RoomMember.java @@ -1,7 +1,8 @@ /* * Copyright 2014 OpenMarket Ltd * Copyright 2017 Vector Creations Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -18,6 +19,8 @@ import android.text.TextUtils; +import com.google.gson.annotations.SerializedName; + import org.matrix.androidsdk.util.ContentManager; import org.matrix.androidsdk.util.Log; @@ -47,7 +50,8 @@ public class RoomMember implements Externalizable { public Invite thirdPartyInvite; // tells that the inviter starts a direct chat room - public Boolean is_direct; + @SerializedName("is_direct") + public Boolean isDirect; private String userId = null; // timestamp of the event which has created this member @@ -80,7 +84,7 @@ public void readExternal(ObjectInput input) throws IOException, ClassNotFoundExc } if (input.readBoolean()) { - is_direct = input.readBoolean(); + isDirect = input.readBoolean(); } if (input.readBoolean()) { @@ -124,9 +128,9 @@ public void writeExternal(ObjectOutput output) throws IOException { output.writeObject(thirdPartyInvite); } - output.writeBoolean(null != is_direct); - if (null != is_direct) { - output.writeBoolean(is_direct); + output.writeBoolean(null != isDirect); + if (null != isDirect) { + output.writeBoolean(isDirect); } output.writeBoolean(null != userId); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/InvitedRoomSync.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/InvitedRoomSync.java index 0707fb214..892e7d9f1 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/InvitedRoomSync.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/InvitedRoomSync.java @@ -1,12 +1,13 @@ -/* +/* * Copyright 2016 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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. @@ -15,8 +16,10 @@ */ package org.matrix.androidsdk.rest.model.sync; +import com.google.gson.annotations.SerializedName; + // InvitedRoomSync represents a room invitation during server sync v2. -public class InvitedRoomSync implements java.io.Serializable { +public class InvitedRoomSync { /** * The state of a room that the user has been invited to. These state events may only have the 'sender', 'type', 'state_key' @@ -25,5 +28,6 @@ public class InvitedRoomSync implements java.io.Serializable { * and one from the archived 'state'. If the client joins the room then the current state will be given as a delta against the * archived 'state' not the 'invite_state'. */ + @SerializedName("invite_state") public RoomInviteState inviteState; } \ No newline at end of file diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomInviteState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomInviteState.java index 7d249f04e..32944f730 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomInviteState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/sync/RoomInviteState.java @@ -1,6 +1,7 @@ /* * Copyright 2016 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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 @@ -20,7 +21,7 @@ import java.util.List; // RoomInviteState represents the state of a room that the user has been invited to. -public class RoomInviteState implements java.io.Serializable { +public class RoomInviteState { /** * List of state events (array of MXEvent). From 0e5ad144f8cd1bbbc90342c7976c6c1b902c0438 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 18 Sep 2018 16:00:25 +0200 Subject: [PATCH 190/236] Code lisibility --- .../org/matrix/androidsdk/MXDataHandler.java | 6 +- .../call/HeadsetConnectionReceiver.java | 10 +- .../androidsdk/call/MXCallsManager.java | 29 ++- .../matrix/androidsdk/crypto/MXCrypto.java | 4 +- .../androidsdk/crypto/MXDeviceList.java | 228 +++++++++--------- .../crypto/MXEncryptedAttachments.java | 20 +- .../MXOutgoingRoomKeyRequestManager.java | 4 +- .../algorithms/megolm/MXMegolmEncryption.java | 6 +- .../java/org/matrix/androidsdk/data/Room.java | 22 +- .../org/matrix/androidsdk/data/RoomState.java | 6 +- .../data/cryptostore/MXFileCryptoStore.java | 21 +- .../androidsdk/data/store/MXFileStore.java | 14 +- .../androidsdk/data/store/MXMemoryStore.java | 11 +- .../fragments/MatrixMessageListFragment.java | 4 +- .../fragments/MatrixMessagesFragment.java | 8 +- .../rest/model/CreateRoomParams.java | 6 +- .../matrix/androidsdk/rest/model/Event.java | 8 +- .../androidsdk/rest/model/MatrixError.java | 26 +- .../matrix/androidsdk/sync/EventsThread.java | 9 +- .../matrix/androidsdk/util/EventDisplay.java | 8 +- tools/check/forbidden_strings_in_code.txt | 5 + 21 files changed, 228 insertions(+), 227 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 27dbb50d8..e624bf2da 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -1362,9 +1362,9 @@ private void manageResponse(final SyncResponse syncResponse, final String fromTo // Handle the to device events before the room ones // to ensure to decrypt them properly - if ((null != syncResponse.toDevice) && - (null != syncResponse.toDevice.events) && - (syncResponse.toDevice.events.size() > 0)) { + 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) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/call/HeadsetConnectionReceiver.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/call/HeadsetConnectionReceiver.java index 45757e9d4..533487405 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/call/HeadsetConnectionReceiver.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/call/HeadsetConnectionReceiver.java @@ -147,11 +147,11 @@ public void onReceive(final Context aContext, final Intent aIntent) { Log.d(LOG_TAG, "## onReceive() : " + aIntent.getExtras()); String action = aIntent.getAction(); - if (TextUtils.equals(action, Intent.ACTION_HEADSET_PLUG) || - TextUtils.equals(action, BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED) || - TextUtils.equals(action, BluetoothAdapter.ACTION_STATE_CHANGED) || - TextUtils.equals(action, BluetoothDevice.ACTION_ACL_CONNECTED) || - TextUtils.equals(action, BluetoothDevice.ACTION_ACL_DISCONNECTED)) { + if (TextUtils.equals(action, Intent.ACTION_HEADSET_PLUG) + || TextUtils.equals(action, BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED) + || TextUtils.equals(action, BluetoothAdapter.ACTION_STATE_CHANGED) + || TextUtils.equals(action, BluetoothDevice.ACTION_ACL_CONNECTED) + || TextUtils.equals(action, BluetoothDevice.ACTION_ACL_DISCONNECTED)) { Boolean newState = null; final boolean isBTHeadsetUpdate; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java index bd175affb..d9664ea53 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/call/MXCallsManager.java @@ -329,17 +329,16 @@ public static boolean isCallInProgress(IMXCall call) { if (null != call) { String callState = call.getCallState(); - res = - TextUtils.equals(callState, IMXCall.CALL_STATE_CREATED) || - TextUtils.equals(callState, IMXCall.CALL_STATE_CREATING_CALL_VIEW) || - TextUtils.equals(callState, IMXCall.CALL_STATE_READY) || - TextUtils.equals(callState, IMXCall.CALL_STATE_WAIT_LOCAL_MEDIA) || - TextUtils.equals(callState, IMXCall.CALL_STATE_WAIT_CREATE_OFFER) || - TextUtils.equals(callState, IMXCall.CALL_STATE_INVITE_SENT) || - TextUtils.equals(callState, IMXCall.CALL_STATE_RINGING) || - TextUtils.equals(callState, IMXCall.CALL_STATE_CREATE_ANSWER) || - TextUtils.equals(callState, IMXCall.CALL_STATE_CONNECTING) || - TextUtils.equals(callState, IMXCall.CALL_STATE_CONNECTED); + res = TextUtils.equals(callState, IMXCall.CALL_STATE_CREATED) + || TextUtils.equals(callState, IMXCall.CALL_STATE_CREATING_CALL_VIEW) + || TextUtils.equals(callState, IMXCall.CALL_STATE_READY) + || TextUtils.equals(callState, IMXCall.CALL_STATE_WAIT_LOCAL_MEDIA) + || TextUtils.equals(callState, IMXCall.CALL_STATE_WAIT_CREATE_OFFER) + || TextUtils.equals(callState, IMXCall.CALL_STATE_INVITE_SENT) + || TextUtils.equals(callState, IMXCall.CALL_STATE_RINGING) + || TextUtils.equals(callState, IMXCall.CALL_STATE_CREATE_ANSWER) + || TextUtils.equals(callState, IMXCall.CALL_STATE_CONNECTING) + || TextUtils.equals(callState, IMXCall.CALL_STATE_CONNECTED); } return res; @@ -521,10 +520,10 @@ public void run() { // check if there are some unknown devices before warning // of the incoming call. // If there are some unknown devices, the answer event would not be encrypted. - if ((null != room) && - room.isEncrypted() && - mSession.getCrypto().warnOnUnknownDevices() && - room.getNumberOfJoinedMembers() == 2) { + if ((null != room) + && room.isEncrypted() + && mSession.getCrypto().warnOnUnknownDevices() + && room.getNumberOfJoinedMembers() == 2) { // test if the encrypted events are sent only to the verified devices (any room) mSession.getCrypto().getGlobalBlacklistUnverifiedDevices(new SimpleApiCallback() { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java index 87383b094..3b9bc2b60 100755 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXCrypto.java @@ -1520,8 +1520,8 @@ public Map encryptMessage(Map payloadFields, Lis * @param event the event */ private void onToDeviceEvent(final Event event) { - if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_ROOM_KEY) || - TextUtils.equals(event.getType(), Event.EVENT_TYPE_FORWARDED_ROOM_KEY)) { + if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_ROOM_KEY) + || TextUtils.equals(event.getType(), Event.EVENT_TYPE_FORWARDED_ROOM_KEY)) { getDecryptingThreadHandler().post(new Runnable() { @Override public void run() { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXDeviceList.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXDeviceList.java index 4905b2691..e1bef6868 100755 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXDeviceList.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXDeviceList.java @@ -354,15 +354,15 @@ private void onKeysDownloadSucceed(List userIds, Map userIds, boolean forceDownload, final ApiC // downloading keys ->the keys download won't be triggered twice but the callback requires the dedicated keys // not yet retrieved - if (mUserKeyDownloadsInProgress.contains(userId) || - ((TRACKING_STATUS_UP_TO_DATE != status) && (TRACKING_STATUS_UNREACHABLE_SERVER != status)) - ) { + if (mUserKeyDownloadsInProgress.contains(userId) + || ((TRACKING_STATUS_UP_TO_DATE != status) && (TRACKING_STATUS_UNREACHABLE_SERVER != status))) { downloadUsers.add(userId); } else { Map devices = mCryptoStore.getUserDevices(userId); @@ -538,135 +537,136 @@ private void doKeyDownloadForUsers(final List downloadUsers, final ApiCa mxSession.getCryptoRestClient() .downloadKeysForUsers(filteredUsers, mxSession.getDataHandler().getStore().getEventStreamToken(), new ApiCallback() { - @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 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 devices = keysQueryResponse.deviceKeys.get(userId); - - Log.d(LOG_TAG, "## doKeyDownloadForUsers() : Got keys for " + userId + " : " + devices); - - if (null != devices) { - Map mutableDevices = new HashMap<>(devices); - List 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); + 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 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 devices = keysQueryResponse.deviceKeys.get(userId); + + Log.d(LOG_TAG, "## doKeyDownloadForUsers() : Got keys for " + userId + " : " + devices); + + if (null != devices) { + Map mutableDevices = new HashMap<>(devices); + List 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); + + // in some race conditions (like unit tests) + // 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; + } + } - // in some race conditions (like unit tests) - // 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; + // Update the store + // Note that devices which aren't in the response will be removed from the stores + cryptoStore.storeUserDevices(userId, mutableDevices); } - // 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; - } + // the response is the latest request one + mPendingDownloadKeysRequestToken.remove(userId); } - - // 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); } - } - - onKeysDownloadSucceed(filteredUsers, keysQueryResponse.failures); + }); } - }); - } - private void onFailed() { - mxCrypto.getEncryptingThreadHandler().post(new Runnable() { - @Override - public void run() { - List userIdsList = new ArrayList<>(filteredUsers); + private void onFailed() { + mxCrypto.getEncryptingThreadHandler().post(new Runnable() { + @Override + public void run() { + List 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); + } + } - // 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); } - } - - onKeysDownloadFailed(filteredUsers); + }); } - }); - } - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "##doKeyDownloadForUsers() : onNetworkError " + e.getMessage(), e); + @Override + public void onNetworkError(Exception e) { + Log.e(LOG_TAG, "##doKeyDownloadForUsers() : onNetworkError " + e.getMessage(), e); - onFailed(); + onFailed(); - if (null != callback) { - callback.onNetworkError(e); - } - } + if (null != callback) { + callback.onNetworkError(e); + } + } - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "##doKeyDownloadForUsers() : onMatrixError " + e.getMessage()); + @Override + public void onMatrixError(MatrixError e) { + Log.e(LOG_TAG, "##doKeyDownloadForUsers() : onMatrixError " + e.getMessage()); - onFailed(); + onFailed(); - if (null != callback) { - callback.onMatrixError(e); - } - } + if (null != callback) { + callback.onMatrixError(e); + } + } - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "##doKeyDownloadForUsers() : onUnexpectedError " + e.getMessage(), e); + @Override + public void onUnexpectedError(Exception e) { + Log.e(LOG_TAG, "##doKeyDownloadForUsers() : onUnexpectedError " + e.getMessage(), e); - onFailed(); + onFailed(); - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); + if (null != callback) { + callback.onUnexpectedError(e); + } + } + }); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXEncryptedAttachments.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXEncryptedAttachments.java index 0c6f6b9d0..6e300ef7c 100755 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXEncryptedAttachments.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXEncryptedAttachments.java @@ -19,19 +19,16 @@ import android.text.TextUtils; import android.util.Base64; -import org.matrix.androidsdk.util.Log; - import org.matrix.androidsdk.rest.model.crypto.EncryptedFileInfo; import org.matrix.androidsdk.rest.model.crypto.EncryptedFileKey; +import org.matrix.androidsdk.util.Log; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; - import java.io.Serializable; import java.security.MessageDigest; import java.security.SecureRandom; - import java.util.Arrays; import java.util.HashMap; @@ -157,18 +154,17 @@ public static InputStream decryptAttachment(InputStream attachmentStream, Encryp return null; } - if (TextUtils.isEmpty(encryptedFileInfo.iv) || - (null == encryptedFileInfo.key) || - (null == encryptedFileInfo.hashes) || - !encryptedFileInfo.hashes.containsKey("sha256") - ) { + if (TextUtils.isEmpty(encryptedFileInfo.iv) + || (null == encryptedFileInfo.key) + || (null == encryptedFileInfo.hashes) + || !encryptedFileInfo.hashes.containsKey("sha256")) { Log.e(LOG_TAG, "## decryptAttachment() : some fields are not defined"); return null; } - if (!TextUtils.equals(encryptedFileInfo.key.alg, "A256CTR") || - !TextUtils.equals(encryptedFileInfo.key.kty, "oct") || - TextUtils.isEmpty(encryptedFileInfo.key.k)) { + if (!TextUtils.equals(encryptedFileInfo.key.alg, "A256CTR") + || !TextUtils.equals(encryptedFileInfo.key.kty, "oct") + || TextUtils.isEmpty(encryptedFileInfo.key.k)) { Log.e(LOG_TAG, "## decryptAttachment() : invalid key fields"); return null; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXOutgoingRoomKeyRequestManager.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXOutgoingRoomKeyRequestManager.java index 861fd5383..a5bd3cb83 100755 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXOutgoingRoomKeyRequestManager.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXOutgoingRoomKeyRequestManager.java @@ -155,8 +155,8 @@ private void cancelRoomKeyRequest(final Map requestBody, boolean if (req.mState == OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING || req.mState == OutgoingRoomKeyRequest.RequestState.CANCELLATION_PENDING_AND_WILL_RESEND) { // nothing to do here - } else if ((req.mState == OutgoingRoomKeyRequest.RequestState.UNSENT) || - (req.mState == OutgoingRoomKeyRequest.RequestState.FAILED)) { + } else if ((req.mState == OutgoingRoomKeyRequest.RequestState.UNSENT) + || (req.mState == OutgoingRoomKeyRequest.RequestState.FAILED)) { Log.d(LOG_TAG, "## cancelRoomKeyRequest() : deleting unnecessary room key request for " + requestBody); mCryptoStore.deleteOutgoingRoomKeyRequest(req.mRequestId); } else if (req.mState == OutgoingRoomKeyRequest.RequestState.SENT) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/algorithms/megolm/MXMegolmEncryption.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/algorithms/megolm/MXMegolmEncryption.java index 6e0a09fb8..54f3705e1 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/algorithms/megolm/MXMegolmEncryption.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/algorithms/megolm/MXMegolmEncryption.java @@ -249,11 +249,11 @@ private MXOutboundSessionInfo prepareNewSessionInRoom() { private void ensureOutboundSession(MXUsersDevicesMap devicesInRoom, final ApiCallback callback) { MXOutboundSessionInfo session = mOutboundSession; - if ((null == session) || + if ((null == session) // Need to make a brand new session? - session.needsRotation(mSessionRotationPeriodMsgs, mSessionRotationPeriodMs) || + || session.needsRotation(mSessionRotationPeriodMsgs, mSessionRotationPeriodMs) // Determine if we have shared with anyone we shouldn't have - session.sharedWithTooManyDevices(devicesInRoom)) { + || session.sharedWithTooManyDevices(devicesInRoom)) { mOutboundSession = session = prepareNewSessionInRoom(); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 1c8a13f38..532fd3644 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -1321,9 +1321,9 @@ private boolean markAllAsRead(boolean updateReadMarker, final ApiCallback RoomSummary summary = (null != getStore()) ? getStore().getSummary(getRoomId()) : null; if (null != summary) { - if ((0 != summary.getUnreadEventsCount()) || - (0 != summary.getHighlightCount()) || - (0 != summary.getNotificationCount())) { + if ((0 != summary.getUnreadEventsCount()) + || (0 != summary.getHighlightCount()) + || (0 != summary.getNotificationCount())) { Log.e(LOG_TAG, "## markAllAsRead() : the summary events counters should be cleared for " + getRoomId()); Event latestEvent = getStore().getLatestEvent(getRoomId()); @@ -1774,10 +1774,10 @@ public static ImageInfo getImageInfo(Context context, ImageInfo anImageInfo, Uri // extract the Exif info if ((null != sWidth) && (null != sHeight)) { - if ((imageInfo.orientation == ExifInterface.ORIENTATION_TRANSPOSE) || - (imageInfo.orientation == ExifInterface.ORIENTATION_ROTATE_90) || - (imageInfo.orientation == ExifInterface.ORIENTATION_TRANSVERSE) || - (imageInfo.orientation == ExifInterface.ORIENTATION_ROTATE_270)) { + if ((imageInfo.orientation == ExifInterface.ORIENTATION_TRANSPOSE) + || (imageInfo.orientation == ExifInterface.ORIENTATION_ROTATE_90) + || (imageInfo.orientation == ExifInterface.ORIENTATION_TRANSVERSE) + || (imageInfo.orientation == ExifInterface.ORIENTATION_ROTATE_270)) { height = Integer.parseInt(sWidth); width = Integer.parseInt(sHeight); } else { @@ -2280,10 +2280,10 @@ public void onUnexpectedError(Exception e) { */ public void cancelEventSending(final Event event) { if (null != event) { - if ((Event.SentState.UNSENT == event.mSentState) || - (Event.SentState.SENDING == event.mSentState) || - (Event.SentState.WAITING_RETRY == event.mSentState) || - (Event.SentState.ENCRYPTING == event.mSentState)) { + if ((Event.SentState.UNSENT == event.mSentState) + || (Event.SentState.SENDING == event.mSentState) + || (Event.SentState.WAITING_RETRY == event.mSentState) + || (Event.SentState.ENCRYPTING == event.mSentState)) { // the message cannot be sent anymore mDataHandler.updateEventState(event, Event.SentState.UNDELIVERED); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index fe008ee7a..9c435146c 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -966,9 +966,9 @@ public boolean applyState(IMXStore store, Event event, EventTimeline.Direction d } // test if the user has been kicked - if (!TextUtils.equals(event.getSender(), event.stateKey) && - TextUtils.equals(currentMember.membership, RoomMember.MEMBERSHIP_JOIN) && - TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_LEAVE)) { + if (!TextUtils.equals(event.getSender(), event.stateKey) + && TextUtils.equals(currentMember.membership, RoomMember.MEMBERSHIP_JOIN) + && TextUtils.equals(member.membership, RoomMember.MEMBERSHIP_LEAVE)) { member.membership = RoomMember.MEMBERSHIP_KICK; } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java index 0de50da72..e482bc713 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/cryptostore/MXFileCryptoStore.java @@ -242,8 +242,8 @@ public boolean hasData() { loadMetaData(); if (null != mMetaData) { - result = TextUtils.isEmpty(mMetaData.mDeviceId) || - TextUtils.equals(mCredentials.deviceId, mMetaData.mDeviceId); + result = TextUtils.isEmpty(mMetaData.mDeviceId) + || TextUtils.equals(mCredentials.deviceId, mMetaData.mDeviceId); } } @@ -287,9 +287,8 @@ else if (MXFILE_CRYPTO_VERSION != mMetaData.mVersion) { // Check credentials // The device id may not have been provided in credentials. // Check it only if provided, else trust the stored one. - else if (!TextUtils.equals(mMetaData.mUserId, mCredentials.userId) || - ((null != mCredentials.deviceId) && !TextUtils.equals(mCredentials.deviceId, mMetaData.mDeviceId)) - ) { + else if (!TextUtils.equals(mMetaData.mUserId, mCredentials.userId) + || ((null != mCredentials.deviceId) && !TextUtils.equals(mCredentials.deviceId, mMetaData.mDeviceId))) { Log.e(LOG_TAG, "## open() : Credentials do not match"); resetData(); } @@ -1573,10 +1572,10 @@ private static String decodeFilename(String encodedFilename) { * @return true if it is valid */ private boolean isValidIncomingRoomKeyRequest(IncomingRoomKeyRequest incomingRoomKeyRequest) { - return (null != incomingRoomKeyRequest) && - !TextUtils.isEmpty(incomingRoomKeyRequest.mUserId) && - !TextUtils.isEmpty(incomingRoomKeyRequest.mDeviceId) && - !TextUtils.isEmpty(incomingRoomKeyRequest.mRequestId); + return (null != incomingRoomKeyRequest) + && !TextUtils.isEmpty(incomingRoomKeyRequest.mUserId) + && !TextUtils.isEmpty(incomingRoomKeyRequest.mDeviceId) + && !TextUtils.isEmpty(incomingRoomKeyRequest.mRequestId); } @Override @@ -1649,8 +1648,8 @@ public void storeIncomingRoomKeyRequest(IncomingRoomKeyRequest incomingRoomKeyRe loadIncomingRoomKeyRequests(); // invalid or already stored - if (!isValidIncomingRoomKeyRequest(incomingRoomKeyRequest) || - (null != getIncomingRoomKeyRequest(incomingRoomKeyRequest.mUserId, incomingRoomKeyRequest.mDeviceId, incomingRoomKeyRequest.mRequestId))) { + if (!isValidIncomingRoomKeyRequest(incomingRoomKeyRequest) + || (null != getIncomingRoomKeyRequest(incomingRoomKeyRequest.mUserId, incomingRoomKeyRequest.mDeviceId, incomingRoomKeyRequest.mRequestId))) { return; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java index abd1709b1..3e44de780 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java @@ -359,9 +359,9 @@ public void run() { Log.e(LOG_TAG, "Open the store in the background thread."); String errorDescription = null; - boolean succeed = (mMetadata.mVersion == MXFILE_VERSION) && - TextUtils.equals(mMetadata.mUserId, mCredentials.userId) && - TextUtils.equals(mMetadata.mAccessToken, mCredentials.accessToken); + boolean succeed = (mMetadata.mVersion == MXFILE_VERSION) + && TextUtils.equals(mMetadata.mUserId, mCredentials.userId) + && TextUtils.equals(mMetadata.mAccessToken, mCredentials.accessToken); if (!succeed) { errorDescription = "Invalid store content"; @@ -1223,10 +1223,10 @@ private boolean loadRoomMessages(final String roomId) { // finalizes the deserialization for (Event event : events.values()) { // if a message was not sent, mark it as UNDELIVERED - if ((event.mSentState == Event.SentState.UNSENT) || - (event.mSentState == Event.SentState.SENDING) || - (event.mSentState == Event.SentState.WAITING_RETRY) || - (event.mSentState == Event.SentState.ENCRYPTING)) { + if ((event.mSentState == Event.SentState.UNSENT) + || (event.mSentState == Event.SentState.SENDING) + || (event.mSentState == Event.SentState.WAITING_RETRY) + || (event.mSentState == Event.SentState.ENCRYPTING)) { event.mSentState = Event.SentState.UNDELIVERED; shouldSave = true; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java index 2be2eae86..ddcc83d5d 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java @@ -316,8 +316,11 @@ public boolean setDisplayName(String displayName, long ts) { Log.d(LOG_TAG, "## setDisplayName() : from " + mMetadata.mUserDisplayName + " to " + displayName + " ts " + ts); } - isUpdated = (null != mMetadata) && !TextUtils.equals(mMetadata.mUserDisplayName, displayName) && - (mUserDisplayNameTs < ts) && (ts != 0) && (ts <= System.currentTimeMillis()); + isUpdated = (null != mMetadata) + && !TextUtils.equals(mMetadata.mUserDisplayName, displayName) + && (mUserDisplayNameTs < ts) + && (ts != 0) + && (ts <= System.currentTimeMillis()); if (isUpdated) { mMetadata.mUserDisplayName = (null != displayName) ? displayName.trim() : null; @@ -356,8 +359,8 @@ public boolean setAvatarURL(String avatarURL, long ts) { Log.d(LOG_TAG, "## setAvatarURL() : from " + mMetadata.mUserAvatarUrl + " to " + avatarURL + " ts " + ts); } - isUpdated = (null != mMetadata) && !TextUtils.equals(mMetadata.mUserAvatarUrl, avatarURL) && - (mUserAvatarUrlTs < ts) && (ts != 0) && (ts <= System.currentTimeMillis()); + isUpdated = (null != mMetadata) && !TextUtils.equals(mMetadata.mUserAvatarUrl, avatarURL) + && (mUserAvatarUrlTs < ts) && (ts != 0) && (ts <= System.currentTimeMillis()); if (isUpdated) { mMetadata.mUserAvatarUrl = avatarURL; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java index 89c9a93f2..07631e61e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java @@ -788,8 +788,8 @@ public Event getEvent(int row) { * @return true if the read marker can be updated */ private boolean canUpdateReadMarker(MessageRow newMessageRow, MessageRow currentReadMarkerRow) { - return (currentReadMarkerRow != null && - mAdapter.getPosition(newMessageRow) == mAdapter.getPosition(currentReadMarkerRow) + 1 + return (currentReadMarkerRow != null + && mAdapter.getPosition(newMessageRow) == mAdapter.getPosition(currentReadMarkerRow) + 1 && newMessageRow.getEvent().getOriginServerTs() > currentReadMarkerRow.getEvent().originServerTs); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java index 69021eed7..367a0ef68 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java @@ -237,10 +237,10 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa // TODO LazyLoading: handle KICK and BAN membership? /* RoomMember self = mRoom.getMember(mSession.getCredentials().userId); - if (self != null && - (RoomMember.MEMBERSHIP_JOIN.equals(self.membership) || - RoomMember.MEMBERSHIP_KICK.equals(self.membership) || - RoomMember.MEMBERSHIP_BAN.equals(self.membership))) { + if (self != null + && (RoomMember.MEMBERSHIP_JOIN.equals(self.membership) + || RoomMember.MEMBERSHIP_KICK.equals(self.membership) + || RoomMember.MEMBERSHIP_BAN.equals(self.membership))) { joinedRoom = true; } */ diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/CreateRoomParams.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/CreateRoomParams.java index b8739e01f..86720fe36 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/CreateRoomParams.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/CreateRoomParams.java @@ -198,8 +198,10 @@ private int getInvite3PidCount() { * @return true if it is a direct chat */ public boolean isDirect() { - return TextUtils.equals(preset, CreateRoomParams.PRESET_TRUSTED_PRIVATE_CHAT) && (null != isDirect) && isDirect && - (1 == getInviteCount() || (1 == getInvite3PidCount())); + return TextUtils.equals(preset, CreateRoomParams.PRESET_TRUSTED_PRIVATE_CHAT) + && (null != isDirect) + && isDirect + && (1 == getInviteCount() || (1 == getInvite3PidCount())); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java index 7e5b5c171..e17954260 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/Event.java @@ -551,10 +551,10 @@ public boolean hasToken() { * @return true if the event if a call event. */ public boolean isCallEvent() { - return EVENT_TYPE_CALL_INVITE.equals(getType()) || - EVENT_TYPE_CALL_CANDIDATES.equals(getType()) || - EVENT_TYPE_CALL_ANSWER.equals(getType()) || - EVENT_TYPE_CALL_HANGUP.equals(getType()); + return EVENT_TYPE_CALL_INVITE.equals(getType()) + || EVENT_TYPE_CALL_CANDIDATES.equals(getType()) + || EVENT_TYPE_CALL_ANSWER.equals(getType()) + || EVENT_TYPE_CALL_HANGUP.equals(getType()); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/MatrixError.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/MatrixError.java index 1995dd40b..9217b3440 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/MatrixError.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/MatrixError.java @@ -133,19 +133,19 @@ public String getMessage() { * @return true if the error code is a supported one */ public boolean isSupportedErrorCode() { - return MatrixError.FORBIDDEN.equals(errcode) || - MatrixError.UNKNOWN_TOKEN.equals(errcode) || - MatrixError.BAD_JSON.equals(errcode) || - MatrixError.NOT_JSON.equals(errcode) || - MatrixError.NOT_FOUND.equals(errcode) || - MatrixError.LIMIT_EXCEEDED.equals(errcode) || - MatrixError.USER_IN_USE.equals(errcode) || - MatrixError.ROOM_IN_USE.equals(errcode) || - MatrixError.TOO_LARGE.equals(errcode) || - MatrixError.BAD_PAGINATION.equals(errcode) || - MatrixError.OLD_VERSION.equals(errcode) || - MatrixError.UNRECOGNIZED.equals(errcode) || - MatrixError.RESOURCE_LIMIT_EXCEEDED.equals(errcode); + return MatrixError.FORBIDDEN.equals(errcode) + || MatrixError.UNKNOWN_TOKEN.equals(errcode) + || MatrixError.BAD_JSON.equals(errcode) + || MatrixError.NOT_JSON.equals(errcode) + || MatrixError.NOT_FOUND.equals(errcode) + || MatrixError.LIMIT_EXCEEDED.equals(errcode) + || MatrixError.USER_IN_USE.equals(errcode) + || MatrixError.ROOM_IN_USE.equals(errcode) + || MatrixError.TOO_LARGE.equals(errcode) + || MatrixError.BAD_PAGINATION.equals(errcode) + || MatrixError.OLD_VERSION.equals(errcode) + || MatrixError.UNRECOGNIZED.equals(errcode) + || MatrixError.RESOURCE_LIMIT_EXCEEDED.equals(errcode); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java index 983f30063..cbb914e08 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/sync/EventsThread.java @@ -29,8 +29,6 @@ import android.os.PowerManager; import android.os.SystemClock; -import com.google.gson.Gson; - import org.matrix.androidsdk.data.metrics.MetricsListener; import org.matrix.androidsdk.listeners.IMXNetworkEventListener; import org.matrix.androidsdk.network.NetworkConnectivityReceiver; @@ -38,7 +36,6 @@ import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.client.EventsRestClient; import org.matrix.androidsdk.rest.model.MatrixError; -import org.matrix.androidsdk.rest.model.filter.FilterBody; import org.matrix.androidsdk.rest.model.sync.RoomsSyncResponse; import org.matrix.androidsdk.rest.model.sync.SyncResponse; import org.matrix.androidsdk.util.Log; @@ -368,9 +365,9 @@ public void run() { * @return true if the response contains some changed devices. */ private static boolean hasDevicesChanged(SyncResponse syncResponse) { - return (null != syncResponse.deviceLists) && - (null != syncResponse.deviceLists.changed) && - (syncResponse.deviceLists.changed.size() > 0); + return (null != syncResponse.deviceLists) + && (null != syncResponse.deviceLists.changed) + && (syncResponse.deviceLists.changed.size() > 0); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/EventDisplay.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/EventDisplay.java index 316f6b2da..49c425546 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/util/EventDisplay.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/util/EventDisplay.java @@ -376,10 +376,10 @@ protected static String senderDisplayNameForEvent(Event event, EventContent even if ((null != eventContent) && TextUtils.equals(RoomMember.MEMBERSHIP_JOIN, eventContent.membership)) { // detect if it is displayname update // a display name update is detected when the previous state was join and there was a displayname - if (!TextUtils.isEmpty(eventContent.displayname) || - ((null != prevEventContent) - && TextUtils.equals(RoomMember.MEMBERSHIP_JOIN, prevEventContent.membership) - && !TextUtils.isEmpty(prevEventContent.displayname))) { + if (!TextUtils.isEmpty(eventContent.displayname) + || ((null != prevEventContent) + && TextUtils.equals(RoomMember.MEMBERSHIP_JOIN, prevEventContent.membership) + && !TextUtils.isEmpty(prevEventContent.displayname))) { senderDisplayName = eventContent.displayname; } } diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index c3230d4b2..b8a6f9d1e 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -138,3 +138,8 @@ URI_API_PREFIX_PATH_MEDIA_R0 \+ \"\/ URI_API_PREFIX_PATH_R0 \+ \"\/ URI_API_PREFIX_PATH_UNSTABLE \+ \"\/ URI_API_PREFIX_IDENTITY \+ \"\/ + +### Put the operator at the beginning of next line +&&$ +\|\|$ + ==$ From 8849408f4e199e6ad229565eed88c4140e8d3a05 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 19 Sep 2018 11:12:20 +0200 Subject: [PATCH 191/236] Fix issue on test compilation due to API change --- CHANGES.rst | 1 + .../matrix/androidsdk/crypto/CryptoTest.java | 17 +++++++---------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index f5a0dc0c1..76ba1eb9b 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -19,6 +19,7 @@ API Change: - SentState.UNDELIVERABLE has been renamed to SentState.UNDELIVERED - Extract patterns and corresponding methods from MXSession to a dedicated MXPatterns class. - MatrixMessageListFragment is now abstract and take an Adapter type as class parameter + - Parameter guestAccess removed from MxSession.createRoom(). It had no effect. Translations: - diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 8be5d7ee4..a558af4c1 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -2535,9 +2535,8 @@ public void test25_testLeftAndJoinedBob() throws Exception { bobSession.getCrypto().setWarnOnUnknownDevices(false); CountDownLatch lock0 = new CountDownLatch(1); - aliceSession.createRoom(null, null, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PUBLIC, - null, RoomState.GUEST_ACCESS_CAN_JOIN, - null, new TestApiCallback(lock0) { + aliceSession.createRoom(null, null, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PUBLIC, null, null, + new TestApiCallback(lock0) { @Override public void onSuccess(String roomId) { results.put("roomId", roomId); @@ -3010,9 +3009,8 @@ public void onSuccess(Void info) { bobSession.getCrypto().setWarnOnUnknownDevices(false); CountDownLatch lock0 = new CountDownLatch(1); - aliceSession.createRoom(null, null, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PUBLIC, - null, RoomState.GUEST_ACCESS_CAN_JOIN, - null, new TestApiCallback(lock0) { + aliceSession.createRoom(null, null, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PUBLIC, null, null, + new TestApiCallback(lock0) { @Override public void onSuccess(String roomId) { results.put("roomId", roomId); @@ -3141,9 +3139,8 @@ public void onSuccess(Void info) { final String[] aliceRoomId2 = {null}; CountDownLatch lock3 = new CountDownLatch(1); - aliceSession2.createRoom(null, null, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PUBLIC, - null, RoomState.GUEST_ACCESS_CAN_JOIN, - null, new TestApiCallback(lock3) { + aliceSession2.createRoom(null, null, RoomDirectoryVisibility.DIRECTORY_VISIBILITY_PUBLIC, null, null, + new TestApiCallback(lock3) { @Override public void onSuccess(String info) { aliceRoomId2[0] = info; @@ -3394,7 +3391,7 @@ private Pair doE2ETestWithAliceAndBobInARoom(boolea SessionAndRoomId sessionAndRoomId = doE2ETestWithAliceInARoom(); MXSession aliceSession = sessionAndRoomId.first; final String aliceRoomId = sessionAndRoomId.second; - + Room room = aliceSession.getDataHandler().getRoom(aliceRoomId); MXSession bobSession = mTestHelper.createBobAccount(true, false); From e9c812283f37220d52533236d6ecc3de6a9bf592 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 19 Sep 2018 19:07:39 +0200 Subject: [PATCH 192/236] Tests: introduce SessionTestParams --- .../androidsdk/common/CommonTestHelper.java | 64 +++++++++---------- .../androidsdk/common/SessionTestParams.java | 46 +++++++++++++ .../androidsdk/crypto/CryptoRestTest.java | 20 +++--- .../matrix/androidsdk/crypto/CryptoTest.java | 44 +++++++------ .../lazyloading/LazyLoadingTestHelper.java | 24 ++++--- 5 files changed, 121 insertions(+), 77 deletions(-) create mode 100644 matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/SessionTestParams.java diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index 61616053a..6b023a728 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -58,29 +58,29 @@ */ public class CommonTestHelper { - public MXSession createBobAccount(boolean withInitialSync, boolean enableCrypto) throws InterruptedException { - return createAccount(TestConstants.BOB_USER_ID, TestConstants.BOB_PWD, withInitialSync, enableCrypto); + public MXSession createBobAccount(final SessionTestParams testParams) throws InterruptedException { + return createAccount(TestConstants.BOB_USER_ID, TestConstants.BOB_PWD, testParams); } - public MXSession createAliceAccount(boolean withInitialSync, boolean enableCrypto) throws InterruptedException { - return createAccount(TestConstants.ALICE_USER_ID, TestConstants.ALICE_PWD, withInitialSync, enableCrypto); + public MXSession createAliceAccount(final SessionTestParams testParams) throws InterruptedException { + return createAccount(TestConstants.ALICE_USER_ID, TestConstants.ALICE_PWD, testParams); } - public MXSession createSamAccount(boolean withInitialSync, boolean enableCrypto) throws InterruptedException { - return createAccount(TestConstants.SAM_USER_ID, TestConstants.SAM_PWD, withInitialSync, enableCrypto); + public MXSession createSamAccount(final SessionTestParams testParams) throws InterruptedException { + return createAccount(TestConstants.SAM_USER_ID, TestConstants.SAM_PWD, testParams); } - public MXSession logIntoBobAccount(final String bobUserId, final boolean withInitialSync, boolean enableCrypto) throws InterruptedException { - return logIntoAccount(bobUserId, TestConstants.BOB_PWD, withInitialSync, enableCrypto, false); + public MXSession logIntoBobAccount(final String bobUserId, final SessionTestParams testParams) throws InterruptedException { + return logIntoAccount(bobUserId, TestConstants.BOB_PWD, testParams); } - public MXSession logIntoAliceAccount(final String aliceUserId, final boolean withInitialSync, boolean enableCrypto, boolean withLazyLoading) + public MXSession logIntoAliceAccount(final String aliceUserId, final SessionTestParams testParams) throws InterruptedException { - return logIntoAccount(aliceUserId, TestConstants.ALICE_PWD, withInitialSync, enableCrypto, withLazyLoading); + return logIntoAccount(aliceUserId, TestConstants.ALICE_PWD, testParams); } - public MXSession logIntoSamAccount(final String samUserId, final boolean withInitialSync, boolean enableCrypto) throws InterruptedException { - return logIntoAccount(samUserId, TestConstants.SAM_PWD, withInitialSync, enableCrypto, false); + public MXSession logIntoSamAccount(final String samUserId, final SessionTestParams testParams) throws InterruptedException { + return logIntoAccount(samUserId, TestConstants.SAM_PWD, testParams); } /** @@ -183,23 +183,21 @@ public void onEncryptionFailed(RoomMediaMessage roomMediaMessage) { /** * Creates a unique account * - * @param userId the base userId - * @param password the password - * @param withInitialSync true to perform an initial sync - * @param enableCrypto true to set enableCryptoWhenStarting + * @param userId the base userId + * @param password the password + * @param testParams test params about the session * @return the session associated with the newly created account */ private MXSession createAccount(@NonNull final String userId, @NonNull final String password, - final boolean withInitialSync, - final boolean enableCrypto) throws InterruptedException { + @NonNull final SessionTestParams testParams) throws InterruptedException { final Context context = InstrumentationRegistry.getContext(); final MXSession session = createAccountAndSync( context, userId + System.currentTimeMillis() + UUID.randomUUID(), password, - withInitialSync, - enableCrypto + testParams.withInitialSync, + testParams.enableCrypto ); Assert.assertNotNull(session); return session; @@ -208,19 +206,16 @@ private MXSession createAccount(@NonNull final String userId, /** * Logs into an existing account * - * @param userId the userId to log in - * @param password the password to log in - * @param withInitialSync true to perform an initial sync - * @param enableCrypto true to set enableCryptoWhenStarting + * @param userId the userId to log in + * @param password the password to log in + * @param testParams test params about the session * @return the session associated with the existing account */ private MXSession logIntoAccount(@NonNull final String userId, @NonNull final String password, - final boolean withInitialSync, - final boolean enableCrypto, - boolean withLazyLoading) throws InterruptedException { + @NonNull final SessionTestParams testParams) throws InterruptedException { final Context context = InstrumentationRegistry.getContext(); - final MXSession session = logAccountAndSync(context, userId, password, withInitialSync, enableCrypto, withLazyLoading); + final MXSession session = logAccountAndSync(context, userId, password, testParams.withInitialSync, testParams.enableCrypto, testParams.withLazyLoading); Assert.assertNotNull(session); return session; } @@ -325,13 +320,14 @@ public void onSuccess(Credentials credentials) { * @param password the password * @param withInitialSync true to perform an initial sync * @param enableCrypto true to set enableCryptoWhenStarting + * @param withLazyLoading true to enable lazyLoading */ - private MXSession logAccountAndSync(Context context, - String userName, - String password, - boolean withInitialSync, - boolean enableCrypto, - boolean withLazyLoading) throws InterruptedException { + private MXSession logAccountAndSync(final Context context, + final String userName, + final String password, + final boolean withInitialSync, + final boolean enableCrypto, + final boolean withLazyLoading) throws InterruptedException { final HomeServerConnectionConfig hs = createHomeServerConfig(null); LoginRestClient loginRestClient = new LoginRestClient(hs); final Map params = new HashMap<>(); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/SessionTestParams.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/SessionTestParams.java new file mode 100644 index 000000000..fcd90d148 --- /dev/null +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/SessionTestParams.java @@ -0,0 +1,46 @@ +package org.matrix.androidsdk.common; + +public class SessionTestParams { + + final boolean withInitialSync; + final boolean enableCrypto; + final boolean withLazyLoading; + + private SessionTestParams(final Builder builder) { + withInitialSync = builder.withInitialSync; + enableCrypto = builder.enableCrypto; + withLazyLoading = builder.withLazyLoading; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static final class Builder { + private boolean withInitialSync; + private boolean enableCrypto; + private boolean withLazyLoading; + + public Builder() { + } + + public Builder withInitialSync(final boolean withInitialSync) { + this.withInitialSync = withInitialSync; + return this; + } + + public Builder enableCrypto(final boolean enableCrypto) { + this.enableCrypto = enableCrypto; + return this; + } + + public Builder withLazyLoading(final boolean withLazyLoading) { + this.withLazyLoading = withLazyLoading; + return this; + } + + public SessionTestParams build() { + return new SessionTestParams(this); + } + } +} diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java index ac76a120e..ffe4f0efc 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java @@ -28,8 +28,8 @@ import org.junit.runners.MethodSorters; import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.common.CommonTestHelper; +import org.matrix.androidsdk.common.SessionTestParams; import org.matrix.androidsdk.common.TestApiCallback; -import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXKey; import org.matrix.androidsdk.crypto.data.MXUsersDevicesMap; @@ -42,19 +42,19 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class CryptoRestTest { +public class CryptoRestTest { private CommonTestHelper mTestHelper = new CommonTestHelper(); @Test public void test01_testDeviceKeys() throws Exception { - Context context = InstrumentationRegistry.getContext(); - final MXSession bobSession = mTestHelper.createBobAccount(true, false); + final Context context = InstrumentationRegistry.getContext(); + final SessionTestParams testParams = SessionTestParams.newBuilder().withInitialSync(true).build(); + final MXSession bobSession = mTestHelper.createBobAccount(testParams); final Map results = new HashMap<>(); String ed25519key = "wV5E3EUSHpHuoZLljNzojlabjGdXT3Mz7rugG9zgbkI"; @@ -119,8 +119,8 @@ public void onSuccess(KeysQueryResponse keysQueryResponse) { @Test public void test02_testOneTimeKeys() throws Exception { Context context = InstrumentationRegistry.getContext(); - - final MXSession bobSession = mTestHelper.createBobAccount(true, false); + final SessionTestParams testParams = SessionTestParams.newBuilder().withInitialSync(true).build(); + final MXSession bobSession = mTestHelper.createBobAccount(testParams); final Map results = new HashMap<>(); final Map otks = new HashMap<>(); @@ -152,9 +152,9 @@ public void onSuccess(KeysUploadResponse keysUploadResponse) { @Test public void test03_testClaimOneTimeKeysForUsersDevices() throws Exception { Context context = InstrumentationRegistry.getContext(); - - final MXSession bobSession = mTestHelper.createBobAccount(true, false); - final MXSession aliceSession = mTestHelper.createAliceAccount(true, false); + final SessionTestParams testParams = SessionTestParams.newBuilder().withInitialSync(true).build(); + final MXSession bobSession = mTestHelper.createBobAccount(testParams); + final MXSession aliceSession = mTestHelper.createAliceAccount(testParams); final Map results = new HashMap<>(); final Map otks = new HashMap<>(); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index a558af4c1..9d0a5c714 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -39,6 +39,7 @@ import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.common.SessionAndRoomId; +import org.matrix.androidsdk.common.SessionTestParams; import org.matrix.androidsdk.common.TestApiCallback; import org.matrix.androidsdk.common.Triple; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; @@ -76,6 +77,9 @@ public class CryptoTest { private CommonTestHelper mTestHelper = new CommonTestHelper(); + private final SessionTestParams defaultSessionParams = SessionTestParams.newBuilder().withInitialSync(true).build(); + private final SessionTestParams encryptedSessionParams = SessionTestParams.newBuilder().withInitialSync(true).enableCrypto(true).build(); + private static final String LOG_TAG = "CryptoTest"; private static final List messagesFromAlice = Arrays.asList("0 - Hello I'm Alice!", "4 - Go!"); @@ -87,7 +91,7 @@ public void test01_testCryptoNoDeviceId() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession bobSession = mTestHelper.createBobAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); Assert.assertNull(bobSession.getCrypto()); bobSession.getCredentials().deviceId = null; @@ -115,7 +119,7 @@ public void test02_testCryptoPersistenceInStore() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession bobSession = mTestHelper.createBobAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); bobSession.getCredentials().deviceId = "BobDevice"; Assert.assertNull(bobSession.getCrypto()); @@ -225,7 +229,7 @@ public void test03_testKeysUploadAndDownload() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession aliceSession = mTestHelper.createAliceAccount(true, false); + MXSession aliceSession = mTestHelper.createAliceAccount(defaultSessionParams); aliceSession.getCredentials().deviceId = "AliceDevice"; CountDownLatch lock0 = new CountDownLatch(1); @@ -239,7 +243,7 @@ public void onSuccess(Void info) { mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("enableCrypto")); - MXSession bobSession = mTestHelper.createBobAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); CountDownLatch lock2 = new CountDownLatch(1); bobSession.getCredentials().deviceId = "BobDevice"; bobSession.enableCrypto(true, new TestApiCallback(lock2) { @@ -412,7 +416,7 @@ public void test04_testEnsureOlmSessionsForUsers() throws Exception { Context context = InstrumentationRegistry.getContext(); - MXSession aliceSession = mTestHelper.createAliceAccount(true, false); + MXSession aliceSession = mTestHelper.createAliceAccount(defaultSessionParams); final Map results = new HashMap<>(); aliceSession.getCredentials().deviceId = "AliceDevice"; @@ -430,7 +434,7 @@ public void onSuccess(Void info) { mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("enableCryptoAlice")); - MXSession bobSession = mTestHelper.createBobAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); CountDownLatch lock2 = new CountDownLatch(1); bobSession.enableCrypto(true, new TestApiCallback(lock2) { @@ -577,7 +581,7 @@ public void test05_testRoomIsEncrypted() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession bobSession = mTestHelper.createBobAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); CountDownLatch lock0 = new CountDownLatch(1); bobSession.enableCrypto(true, new TestApiCallback(lock0) { @@ -1841,7 +1845,7 @@ public void onToDeviceEvent(Event event) { aliceSession.getDataHandler().addListener(aliceEventListener); // login with a new device id - MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), true, true); + MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), encryptedSessionParams); String bobDeviceId2 = bobSession2.getCredentials().deviceId; Assert.assertNotEquals(bobDeviceId2, bobDeviceId1); @@ -1974,11 +1978,11 @@ public void onSuccess(Void info) { mTestHelper.await(lock3); Assert.assertTrue(results.containsKey("alicelogout")); - MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), true, true); + MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), encryptedSessionParams); Assert.assertNotNull(bobSession2); bobSession2.getCrypto().setWarnOnUnknownDevices(false); - MXSession aliceSession2 = mTestHelper.logIntoAliceAccount(aliceSession.getMyUserId(), true, true, false); + MXSession aliceSession2 = mTestHelper.logIntoAliceAccount(aliceSession.getMyUserId(), encryptedSessionParams); Assert.assertNotNull(aliceSession2); aliceSession2.getCrypto().setWarnOnUnknownDevices(false); @@ -2519,8 +2523,8 @@ public void test25_testLeftAndJoinedBob() throws Exception { final Map results = new HashMap<>(); - MXSession aliceSession = mTestHelper.createAliceAccount(true, false); - MXSession bobSession = mTestHelper.createBobAccount(true, false); + MXSession aliceSession = mTestHelper.createAliceAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); CountDownLatch lock_1 = new CountDownLatch(2); @@ -2612,7 +2616,7 @@ public void onSuccess(Void info) { Credentials bobCredentials = bobSession.getCredentials(); bobSession.clear(context); - MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), true, true); + MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), encryptedSessionParams); Assert.assertNotNull(bobSession2); Assert.assertTrue(bobSession2.isCryptoEnabled()); Assert.assertNotEquals(bobSession2.getCrypto().getMyDevice().deviceId, bobCredentials.deviceId); @@ -2983,8 +2987,8 @@ public void test27_testEnableEncryptionAfterNonEncryptedMessages() throws Except final String messageFromAlice = "Hello I'm Alice!"; final String message2FromAlice = "I'm still Alice!"; - MXSession aliceSession = mTestHelper.createAliceAccount(true, false); - MXSession bobSession = mTestHelper.createBobAccount(true, false); + MXSession aliceSession = mTestHelper.createAliceAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); CountDownLatch lock00b = new CountDownLatch(2); aliceSession.enableCrypto(true, new TestApiCallback(lock00b) { @@ -3049,7 +3053,7 @@ public void onSuccess(Void info) { Credentials bobCredentials = bobSession.getCredentials(); bobSession.clear(context); - MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), true, true); + MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), encryptedSessionParams); Assert.assertNotNull(bobSession2); Assert.assertTrue(bobSession2.isCryptoEnabled()); Assert.assertNotEquals(bobSession2.getCrypto().getMyDevice().deviceId, bobCredentials.deviceId); @@ -3132,7 +3136,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("lock1")); // - Alice adds a new device - final MXSession aliceSession2 = mTestHelper.logIntoAliceAccount(aliceSession.getMyUserId(), true, true, false); + final MXSession aliceSession2 = mTestHelper.logIntoAliceAccount(aliceSession.getMyUserId(), encryptedSessionParams); Assert.assertNotNull(aliceSession2); // - Alice and Bob start sharing a room again @@ -3337,7 +3341,7 @@ public void onToDeviceEvent(Event event) { */ private SessionAndRoomId doE2ETestWithAliceInARoom() throws Exception { final Map results = new HashMap<>(); - MXSession aliceSession = mTestHelper.createAliceAccount(true, false); + MXSession aliceSession = mTestHelper.createAliceAccount(defaultSessionParams); CountDownLatch lock0 = new CountDownLatch(1); aliceSession.enableCrypto(true, new TestApiCallback(lock0) { @@ -3394,7 +3398,7 @@ private Pair doE2ETestWithAliceAndBobInARoom(boolea Room room = aliceSession.getDataHandler().getRoom(aliceRoomId); - MXSession bobSession = mTestHelper.createBobAccount(true, false); + MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); CountDownLatch lock0 = new CountDownLatch(1); bobSession.enableCrypto(cryptedBob, new TestApiCallback(lock0) { @@ -3501,7 +3505,7 @@ private Triple doE2ETestWithAliceAndBobA Room room = aliceSession.getDataHandler().getRoom(aliceRoomId); - MXSession samSession = mTestHelper.createSamAccount(true, false); + MXSession samSession = mTestHelper.createSamAccount(defaultSessionParams); CountDownLatch lock0 = new CountDownLatch(1); samSession.enableCrypto(true, new TestApiCallback(lock0) { diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java index ae1816b07..8889bc575 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java @@ -22,8 +22,8 @@ import org.matrix.androidsdk.MXSession; import org.matrix.androidsdk.common.CommonTestHelper; +import org.matrix.androidsdk.common.SessionTestParams; import org.matrix.androidsdk.common.TestApiCallback; -import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.rest.model.Event; @@ -32,7 +32,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; /** * @@ -60,9 +59,11 @@ public LazyLoadingTestHelper(CommonTestHelper mCommonTestHelper) { * @return initialized data */ public LazyLoadingScenarioData createScenario(boolean withLazyLoading) throws Exception { - MXSession aliceSession = mTestHelper.createAliceAccount(true, false); - MXSession bobSession = mTestHelper.createBobAccount(true, false); - MXSession samSession = mTestHelper.createSamAccount(true, false); + + final SessionTestParams createSessionParams = SessionTestParams.newBuilder().withInitialSync(true).build(); + MXSession aliceSession = mTestHelper.createAliceAccount(createSessionParams); + MXSession bobSession = mTestHelper.createBobAccount(createSessionParams); + MXSession samSession = mTestHelper.createSamAccount(createSessionParams); final String aliceId = aliceSession.getMyUserId(); final String bobId = bobSession.getMyUserId(); @@ -83,11 +84,7 @@ public void onSuccess(String info) { final Room bobRoom = bobSession.getDataHandler().getRoom(roomId); - //update name and join rules - latch = new CountDownLatch(1); - bobRoom.updateName("LazyLoading Test Room", new TestApiCallback(latch)); - mTestHelper.await(latch); - + //update join rules latch = new CountDownLatch(1); bobRoom.updateJoinRules(RoomState.JOIN_RULE_PUBLIC, new TestApiCallback(latch)); mTestHelper.await(latch); @@ -126,9 +123,10 @@ public void onSuccess(String info) { bobSession.clear(context); samSession.clear(context); - aliceSession = mTestHelper.logIntoAliceAccount(aliceId, false, false, withLazyLoading); - bobSession = mTestHelper.logIntoBobAccount(bobId, false, false); - samSession = mTestHelper.logIntoSamAccount(samId, false, false); + final SessionTestParams logSessionParams = SessionTestParams.newBuilder().withLazyLoading(withLazyLoading).build(); + aliceSession = mTestHelper.logIntoAliceAccount(aliceId, logSessionParams); + bobSession = mTestHelper.logIntoBobAccount(bobId, logSessionParams); + samSession = mTestHelper.logIntoSamAccount(samId, logSessionParams); return new LazyLoadingScenarioData(aliceSession, bobSession, samSession, roomId, bobMessageId); } } From 165c94341cbf3d8fba402219e017d040a6cdd9f2 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 19 Sep 2018 19:07:54 +0200 Subject: [PATCH 193/236] Tests: Introduce RoomSummaryTest --- .../lazyloading/RoomSummaryTest.java | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java new file mode 100644 index 000000000..ead6c6322 --- /dev/null +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java @@ -0,0 +1,108 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.lazyloading; + +import android.support.test.InstrumentationRegistry; + +import junit.framework.Assert; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.matrix.androidsdk.RestClient; +import org.matrix.androidsdk.common.CommonTestHelper; +import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.data.RoomSummary; + +public class RoomSummaryTest { + + private CommonTestHelper mTestHelper = new CommonTestHelper(); + private LazyLoadingTestHelper mLazyLoadingTestHelper = new LazyLoadingTestHelper(mTestHelper); + + + @BeforeClass + public static void init() { + RestClient.initUserAgent(InstrumentationRegistry.getContext()); + } + + @Test + public void RoomSummary_CheckMembership_LazyLoadedMembers() throws Exception { + RoomSummary_CheckMembership(true); + } + + @Test + public void RoomSummary_CheckMembership_LoadAllMembers() throws Exception { + RoomSummary_CheckMembership(false); + } + + private void RoomSummary_CheckMembership(boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); + mTestHelper.syncSession(data.aliceSession, false); + final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); + final RoomSummary aliceRoomSummary = aliceRoom.getRoomSummary(); + Assert.assertNotNull(aliceRoomSummary); + Assert.assertTrue(aliceRoomSummary.isJoined()); + + mTestHelper.syncSession(data.samSession, false); + final Room samRoom = data.samSession.getDataHandler().getRoom(data.roomId); + final RoomSummary samRoomSummary = samRoom.getRoomSummary(); + Assert.assertNotNull(samRoomSummary); + Assert.assertTrue(samRoomSummary.isJoined()); + } + + @Test + public void RoomSummary_MemberCount_LazyLoadedMembers() throws Exception { + RoomSummary_MemberCount(true); + } + + @Test + public void RoomSummary_MemberCount_LoadAllMembers() throws Exception { + RoomSummary_MemberCount(false); + } + + private void RoomSummary_MemberCount(boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); + mTestHelper.syncSession(data.aliceSession, false); + final RoomSummary roomSummary = data.aliceSession.getDataHandler().getStore().getSummary(data.roomId); + Assert.assertNotNull(roomSummary); + Assert.assertEquals(3, roomSummary.getNumberOfJoinedMembers()); + Assert.assertEquals(1, roomSummary.getNumberOfInvitedMembers()); + } + + @Test + public void RoomSummary_DisplayNameFromHeroes_LazyLoadedMembers() throws Exception { + RoomSummary_DisplayNameFromHeroes(true); + } + + @Test + public void RoomSummary_DisplayNameFromHeroes_LoadAllMembers() throws Exception { + RoomSummary_DisplayNameFromHeroes(false); + } + + private void RoomSummary_DisplayNameFromHeroes(boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); + mTestHelper.syncSession(data.aliceSession, false); + final Room room = data.aliceSession.getDataHandler().getStore().getRoom(data.roomId); + final RoomState roomState = room.getState(); + + Assert.assertNotNull(roomState.getMember(data.bobSession.getMyUserId())); + Assert.assertNotNull(roomState.getMember(data.aliceSession.getMyUserId())); + Assert.assertNotNull(roomState.getMember(data.samSession.getMyUserId())); + Assert.assertEquals(withLazyLoading, roomState.name != null); + } + + +} From 069143d97080ebfdf4a69fb3c3491b4f855ea178 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 20 Sep 2018 18:46:59 +0200 Subject: [PATCH 194/236] Tests : remove some useless methods --- .../androidsdk/common/CommonTestHelper.java | 25 ++---------- .../androidsdk/common/TestConstants.java | 10 +---- .../androidsdk/crypto/CryptoRestTest.java | 8 ++-- .../matrix/androidsdk/crypto/CryptoTest.java | 40 +++++++++---------- .../lazyloading/LazyLoadingTestHelper.java | 18 +++++---- .../androidsdk/lazyloading/RoomStateTest.java | 3 +- .../lazyloading/RoomSummaryTest.java | 28 +++---------- 7 files changed, 47 insertions(+), 85 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index 6b023a728..dbb5b22dd 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -58,29 +58,12 @@ */ public class CommonTestHelper { - public MXSession createBobAccount(final SessionTestParams testParams) throws InterruptedException { - return createAccount(TestConstants.BOB_USER_ID, TestConstants.BOB_PWD, testParams); + public MXSession createAccount(final SessionTestParams testParams) throws InterruptedException { + return createAccount(TestConstants.USER_ID, TestConstants.PASSWORD, testParams); } - public MXSession createAliceAccount(final SessionTestParams testParams) throws InterruptedException { - return createAccount(TestConstants.ALICE_USER_ID, TestConstants.ALICE_PWD, testParams); - } - - public MXSession createSamAccount(final SessionTestParams testParams) throws InterruptedException { - return createAccount(TestConstants.SAM_USER_ID, TestConstants.SAM_PWD, testParams); - } - - public MXSession logIntoBobAccount(final String bobUserId, final SessionTestParams testParams) throws InterruptedException { - return logIntoAccount(bobUserId, TestConstants.BOB_PWD, testParams); - } - - public MXSession logIntoAliceAccount(final String aliceUserId, final SessionTestParams testParams) - throws InterruptedException { - return logIntoAccount(aliceUserId, TestConstants.ALICE_PWD, testParams); - } - - public MXSession logIntoSamAccount(final String samUserId, final SessionTestParams testParams) throws InterruptedException { - return logIntoAccount(samUserId, TestConstants.SAM_PWD, testParams); + public MXSession logIntoAccount(final String userId, final SessionTestParams testParams) throws InterruptedException { + return logIntoAccount(userId, TestConstants.PASSWORD, testParams); } /** diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java index 87e6d7ad5..faa4b7a08 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java @@ -23,12 +23,6 @@ public class TestConstants { // Time out to use when waiting for server response public static final int AWAIT_TIME_OUT_MILLIS = 30000; - public static final String BOB_USER_ID = "mxBob"; - public static final String BOB_PWD = "bobbob"; - - public static final String ALICE_USER_ID = "mxAlice"; - public static final String ALICE_PWD = "alicealice"; - - public static final String SAM_USER_ID = "mxSam"; - public static final String SAM_PWD = "samsam"; + public static final String USER_ID = "userid"; + public static final String PASSWORD = "password"; } \ No newline at end of file diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java index ffe4f0efc..b131a0bc1 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java @@ -54,7 +54,7 @@ public class CryptoRestTest { public void test01_testDeviceKeys() throws Exception { final Context context = InstrumentationRegistry.getContext(); final SessionTestParams testParams = SessionTestParams.newBuilder().withInitialSync(true).build(); - final MXSession bobSession = mTestHelper.createBobAccount(testParams); + final MXSession bobSession = mTestHelper.createAccount(testParams); final Map results = new HashMap<>(); String ed25519key = "wV5E3EUSHpHuoZLljNzojlabjGdXT3Mz7rugG9zgbkI"; @@ -120,7 +120,7 @@ public void onSuccess(KeysQueryResponse keysQueryResponse) { public void test02_testOneTimeKeys() throws Exception { Context context = InstrumentationRegistry.getContext(); final SessionTestParams testParams = SessionTestParams.newBuilder().withInitialSync(true).build(); - final MXSession bobSession = mTestHelper.createBobAccount(testParams); + final MXSession bobSession = mTestHelper.createAccount(testParams); final Map results = new HashMap<>(); final Map otks = new HashMap<>(); @@ -153,8 +153,8 @@ public void onSuccess(KeysUploadResponse keysUploadResponse) { public void test03_testClaimOneTimeKeysForUsersDevices() throws Exception { Context context = InstrumentationRegistry.getContext(); final SessionTestParams testParams = SessionTestParams.newBuilder().withInitialSync(true).build(); - final MXSession bobSession = mTestHelper.createBobAccount(testParams); - final MXSession aliceSession = mTestHelper.createAliceAccount(testParams); + final MXSession bobSession = mTestHelper.createAccount(testParams); + final MXSession aliceSession = mTestHelper.createAccount(testParams); final Map results = new HashMap<>(); final Map otks = new HashMap<>(); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 9d0a5c714..043ab8c49 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -91,7 +91,7 @@ public void test01_testCryptoNoDeviceId() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); Assert.assertNull(bobSession.getCrypto()); bobSession.getCredentials().deviceId = null; @@ -119,7 +119,7 @@ public void test02_testCryptoPersistenceInStore() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); bobSession.getCredentials().deviceId = "BobDevice"; Assert.assertNull(bobSession.getCrypto()); @@ -229,7 +229,7 @@ public void test03_testKeysUploadAndDownload() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession aliceSession = mTestHelper.createAliceAccount(defaultSessionParams); + MXSession aliceSession = mTestHelper.createAccount(defaultSessionParams); aliceSession.getCredentials().deviceId = "AliceDevice"; CountDownLatch lock0 = new CountDownLatch(1); @@ -243,7 +243,7 @@ public void onSuccess(Void info) { mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("enableCrypto")); - MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); CountDownLatch lock2 = new CountDownLatch(1); bobSession.getCredentials().deviceId = "BobDevice"; bobSession.enableCrypto(true, new TestApiCallback(lock2) { @@ -416,7 +416,7 @@ public void test04_testEnsureOlmSessionsForUsers() throws Exception { Context context = InstrumentationRegistry.getContext(); - MXSession aliceSession = mTestHelper.createAliceAccount(defaultSessionParams); + MXSession aliceSession = mTestHelper.createAccount(defaultSessionParams); final Map results = new HashMap<>(); aliceSession.getCredentials().deviceId = "AliceDevice"; @@ -434,7 +434,7 @@ public void onSuccess(Void info) { mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("enableCryptoAlice")); - MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); CountDownLatch lock2 = new CountDownLatch(1); bobSession.enableCrypto(true, new TestApiCallback(lock2) { @@ -581,7 +581,7 @@ public void test05_testRoomIsEncrypted() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); CountDownLatch lock0 = new CountDownLatch(1); bobSession.enableCrypto(true, new TestApiCallback(lock0) { @@ -1845,7 +1845,7 @@ public void onToDeviceEvent(Event event) { aliceSession.getDataHandler().addListener(aliceEventListener); // login with a new device id - MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), encryptedSessionParams); + MXSession bobSession2 = mTestHelper.logIntoAccount(bobSession.getMyUserId(), encryptedSessionParams); String bobDeviceId2 = bobSession2.getCredentials().deviceId; Assert.assertNotEquals(bobDeviceId2, bobDeviceId1); @@ -1978,11 +1978,11 @@ public void onSuccess(Void info) { mTestHelper.await(lock3); Assert.assertTrue(results.containsKey("alicelogout")); - MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), encryptedSessionParams); + MXSession bobSession2 = mTestHelper.logIntoAccount(bobSession.getMyUserId(), encryptedSessionParams); Assert.assertNotNull(bobSession2); bobSession2.getCrypto().setWarnOnUnknownDevices(false); - MXSession aliceSession2 = mTestHelper.logIntoAliceAccount(aliceSession.getMyUserId(), encryptedSessionParams); + MXSession aliceSession2 = mTestHelper.logIntoAccount(aliceSession.getMyUserId(), encryptedSessionParams); Assert.assertNotNull(aliceSession2); aliceSession2.getCrypto().setWarnOnUnknownDevices(false); @@ -2523,8 +2523,8 @@ public void test25_testLeftAndJoinedBob() throws Exception { final Map results = new HashMap<>(); - MXSession aliceSession = mTestHelper.createAliceAccount(defaultSessionParams); - MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); + MXSession aliceSession = mTestHelper.createAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); CountDownLatch lock_1 = new CountDownLatch(2); @@ -2616,7 +2616,7 @@ public void onSuccess(Void info) { Credentials bobCredentials = bobSession.getCredentials(); bobSession.clear(context); - MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), encryptedSessionParams); + MXSession bobSession2 = mTestHelper.logIntoAccount(bobSession.getMyUserId(), encryptedSessionParams); Assert.assertNotNull(bobSession2); Assert.assertTrue(bobSession2.isCryptoEnabled()); Assert.assertNotEquals(bobSession2.getCrypto().getMyDevice().deviceId, bobCredentials.deviceId); @@ -2987,8 +2987,8 @@ public void test27_testEnableEncryptionAfterNonEncryptedMessages() throws Except final String messageFromAlice = "Hello I'm Alice!"; final String message2FromAlice = "I'm still Alice!"; - MXSession aliceSession = mTestHelper.createAliceAccount(defaultSessionParams); - MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); + MXSession aliceSession = mTestHelper.createAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); CountDownLatch lock00b = new CountDownLatch(2); aliceSession.enableCrypto(true, new TestApiCallback(lock00b) { @@ -3053,7 +3053,7 @@ public void onSuccess(Void info) { Credentials bobCredentials = bobSession.getCredentials(); bobSession.clear(context); - MXSession bobSession2 = mTestHelper.logIntoBobAccount(bobSession.getMyUserId(), encryptedSessionParams); + MXSession bobSession2 = mTestHelper.logIntoAccount(bobSession.getMyUserId(), encryptedSessionParams); Assert.assertNotNull(bobSession2); Assert.assertTrue(bobSession2.isCryptoEnabled()); Assert.assertNotEquals(bobSession2.getCrypto().getMyDevice().deviceId, bobCredentials.deviceId); @@ -3136,7 +3136,7 @@ public void onSuccess(Void info) { Assert.assertTrue(results.containsKey("lock1")); // - Alice adds a new device - final MXSession aliceSession2 = mTestHelper.logIntoAliceAccount(aliceSession.getMyUserId(), encryptedSessionParams); + final MXSession aliceSession2 = mTestHelper.logIntoAccount(aliceSession.getMyUserId(), encryptedSessionParams); Assert.assertNotNull(aliceSession2); // - Alice and Bob start sharing a room again @@ -3341,7 +3341,7 @@ public void onToDeviceEvent(Event event) { */ private SessionAndRoomId doE2ETestWithAliceInARoom() throws Exception { final Map results = new HashMap<>(); - MXSession aliceSession = mTestHelper.createAliceAccount(defaultSessionParams); + MXSession aliceSession = mTestHelper.createAccount(defaultSessionParams); CountDownLatch lock0 = new CountDownLatch(1); aliceSession.enableCrypto(true, new TestApiCallback(lock0) { @@ -3398,7 +3398,7 @@ private Pair doE2ETestWithAliceAndBobInARoom(boolea Room room = aliceSession.getDataHandler().getRoom(aliceRoomId); - MXSession bobSession = mTestHelper.createBobAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); CountDownLatch lock0 = new CountDownLatch(1); bobSession.enableCrypto(cryptedBob, new TestApiCallback(lock0) { @@ -3505,7 +3505,7 @@ private Triple doE2ETestWithAliceAndBobA Room room = aliceSession.getDataHandler().getRoom(aliceRoomId); - MXSession samSession = mTestHelper.createSamAccount(defaultSessionParams); + MXSession samSession = mTestHelper.createAccount(defaultSessionParams); CountDownLatch lock0 = new CountDownLatch(1); samSession.enableCrypto(true, new TestApiCallback(lock0) { diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java index 8889bc575..ac7720a4c 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java @@ -61,9 +61,9 @@ public LazyLoadingTestHelper(CommonTestHelper mCommonTestHelper) { public LazyLoadingScenarioData createScenario(boolean withLazyLoading) throws Exception { final SessionTestParams createSessionParams = SessionTestParams.newBuilder().withInitialSync(true).build(); - MXSession aliceSession = mTestHelper.createAliceAccount(createSessionParams); - MXSession bobSession = mTestHelper.createBobAccount(createSessionParams); - MXSession samSession = mTestHelper.createSamAccount(createSessionParams); + MXSession aliceSession = mTestHelper.createAccount(createSessionParams); + MXSession bobSession = mTestHelper.createAccount(createSessionParams); + MXSession samSession = mTestHelper.createAccount(createSessionParams); final String aliceId = aliceSession.getMyUserId(); final String bobId = bobSession.getMyUserId(); @@ -83,8 +83,11 @@ public void onSuccess(String info) { final String roomId = results.get("roomId"); final Room bobRoom = bobSession.getDataHandler().getRoom(roomId); + //update name and join rules + latch = new CountDownLatch(1); + bobRoom.updateName("LazyLoading Test Room", new TestApiCallback(latch)); + mTestHelper.await(latch); - //update join rules latch = new CountDownLatch(1); bobRoom.updateJoinRules(RoomState.JOIN_RULE_PUBLIC, new TestApiCallback(latch)); mTestHelper.await(latch); @@ -123,10 +126,11 @@ public void onSuccess(String info) { bobSession.clear(context); samSession.clear(context); + final SessionTestParams logSessionParams = SessionTestParams.newBuilder().withLazyLoading(withLazyLoading).build(); - aliceSession = mTestHelper.logIntoAliceAccount(aliceId, logSessionParams); - bobSession = mTestHelper.logIntoBobAccount(bobId, logSessionParams); - samSession = mTestHelper.logIntoSamAccount(samId, logSessionParams); + aliceSession = mTestHelper.logIntoAccount(aliceId, logSessionParams); + bobSession = mTestHelper.logIntoAccount(bobId, logSessionParams); + samSession = mTestHelper.logIntoAccount(samId, logSessionParams); return new LazyLoadingScenarioData(aliceSession, bobSession, samSession, roomId, bobMessageId); } } diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index 3dfc18013..7a6a5c247 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -37,8 +37,7 @@ import java.util.concurrent.CountDownLatch; -@RunWith(AndroidJUnit4.class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@FixMethodOrder(MethodSorters.JVM) public class RoomStateTest { private CommonTestHelper mTestHelper = new CommonTestHelper(); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java index ead6c6322..fd130d1f4 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java @@ -16,17 +16,22 @@ package org.matrix.androidsdk.lazyloading; import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; import junit.framework.Assert; import org.junit.BeforeClass; +import org.junit.FixMethodOrder; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; import org.matrix.androidsdk.RestClient; import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.data.RoomSummary; +@FixMethodOrder(MethodSorters.JVM) public class RoomSummaryTest { private CommonTestHelper mTestHelper = new CommonTestHelper(); @@ -82,27 +87,4 @@ private void RoomSummary_MemberCount(boolean withLazyLoading) throws Exception { Assert.assertEquals(1, roomSummary.getNumberOfInvitedMembers()); } - @Test - public void RoomSummary_DisplayNameFromHeroes_LazyLoadedMembers() throws Exception { - RoomSummary_DisplayNameFromHeroes(true); - } - - @Test - public void RoomSummary_DisplayNameFromHeroes_LoadAllMembers() throws Exception { - RoomSummary_DisplayNameFromHeroes(false); - } - - private void RoomSummary_DisplayNameFromHeroes(boolean withLazyLoading) throws Exception { - final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); - mTestHelper.syncSession(data.aliceSession, false); - final Room room = data.aliceSession.getDataHandler().getStore().getRoom(data.roomId); - final RoomState roomState = room.getState(); - - Assert.assertNotNull(roomState.getMember(data.bobSession.getMyUserId())); - Assert.assertNotNull(roomState.getMember(data.aliceSession.getMyUserId())); - Assert.assertNotNull(roomState.getMember(data.samSession.getMyUserId())); - Assert.assertEquals(withLazyLoading, roomState.name != null); - } - - } From aa00cbb9a07e80a36cd821ddf6138a0279ac3464 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 20 Sep 2018 18:47:38 +0200 Subject: [PATCH 195/236] Tests : add RoomMembers test - lazy loaded --- .../lazyloading/RoomMembersTest.java | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomMembersTest.java diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomMembersTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomMembersTest.java new file mode 100644 index 000000000..9a99dceec --- /dev/null +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomMembersTest.java @@ -0,0 +1,128 @@ +package org.matrix.androidsdk.lazyloading; + +import android.support.test.InstrumentationRegistry; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; +import org.matrix.androidsdk.RestClient; +import org.matrix.androidsdk.common.CommonTestHelper; +import org.matrix.androidsdk.common.TestApiCallback; +import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.rest.model.RoomMember; + +import java.util.List; +import java.util.concurrent.CountDownLatch; + +@FixMethodOrder(MethodSorters.JVM) +public class RoomMembersTest { + + private CommonTestHelper mTestHelper = new CommonTestHelper(); + private LazyLoadingTestHelper mLazyLoadingTestHelper = new LazyLoadingTestHelper(mTestHelper); + + @BeforeClass + public static void init() { + RestClient.initUserAgent(InstrumentationRegistry.getContext()); + } + + @Test + public void RoomMembers_CheckTotalCountAsync_ShouldLoadAllMembers() throws Exception { + RoomMembers_CheckTotalCountAsync(false); + } + + @Test + public void RoomMembers_CheckTotalCountAsync_LazyLoadedMembers() throws Exception { + RoomMembers_CheckTotalCountAsync(true); + } + + private void RoomMembers_CheckTotalCountAsync(final boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); + mTestHelper.syncSession(data.aliceSession, false); + final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); + final CountDownLatch lock = new CountDownLatch(1); + aliceRoom.getMembersAsync(new TestApiCallback>(lock) { + @Override + public void onSuccess(List roomMembers) { + Assert.assertEquals(4, roomMembers.size()); + lock.countDown(); + } + }); + mTestHelper.await(lock); + } + + @Test + public void RoomMembers_CheckActiveCountAsync_ShouldLoadAllMembers() throws Exception { + RoomMembers_CheckActiveCountAsync(false); + } + + @Test + public void RoomMembers_CheckActiveCountAsync_LazyLoadedMembers() throws Exception { + RoomMembers_CheckActiveCountAsync(true); + } + + private void RoomMembers_CheckActiveCountAsync(final boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); + mTestHelper.syncSession(data.aliceSession, false); + final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); + final CountDownLatch lock = new CountDownLatch(1); + aliceRoom.getActiveMembersAsync(new TestApiCallback>(lock) { + @Override + public void onSuccess(List roomMembers) { + Assert.assertEquals(4, roomMembers.size()); + lock.countDown(); + } + }); + mTestHelper.await(lock); + } + + @Test + public void RoomMembers_CheckJoinedCountAsync_ShouldLoadAllMembers() throws Exception { + RoomMembers_CheckJoinedCountAsync(false); + } + + @Test + public void RoomMembers_CheckJoinedCountAsync_LazyLoadedMembers() throws Exception { + RoomMembers_CheckJoinedCountAsync(true); + } + + private void RoomMembers_CheckJoinedCountAsync(final boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); + mTestHelper.syncSession(data.aliceSession, false); + final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); + final CountDownLatch lock = new CountDownLatch(1); + aliceRoom.getJoinedMembersAsync(new TestApiCallback>(lock) { + @Override + public void onSuccess(List roomMembers) { + Assert.assertEquals(3, roomMembers.size()); + lock.countDown(); + } + }); + mTestHelper.await(lock); + } + + @Test + public void RoomMembers_CheckAlreadyLoadedCount_ShouldLoadAllMembers() throws Exception { + RoomMembers_CheckAlreadyLoadedCount(false); + } + + @Test + public void RoomMembers_CheckAlreadyLoadedCount_LazyLoadedMembers() throws Exception { + RoomMembers_CheckAlreadyLoadedCount(true); + } + + private void RoomMembers_CheckAlreadyLoadedCount(final boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); + mTestHelper.syncSession(data.aliceSession, false); + final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); + final List members = aliceRoom.getState().getLoadedMembers(); + if (withLazyLoading) { + Assert.assertEquals(1, members.size()); + } else { + Assert.assertEquals(4, members.size()); + } + } + + +} From 959b54669188129442afe463b5fbd57da1ea7c00 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 21 Sep 2018 11:55:27 +0200 Subject: [PATCH 196/236] Test : clean some test files --- .../androidsdk/common/CommonTestHelper.java | 4 +-- .../androidsdk/common/SessionTestParams.java | 26 +++++++++++++++---- .../matrix/androidsdk/crypto/CryptoTest.java | 2 +- .../lazyloading/RoomMembersTest.java | 15 +++++++++++ .../androidsdk/lazyloading/RoomStateTest.java | 2 -- .../lazyloading/RoomSummaryTest.java | 3 --- 6 files changed, 39 insertions(+), 13 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index dbb5b22dd..18958b91b 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -180,7 +180,7 @@ private MXSession createAccount(@NonNull final String userId, userId + System.currentTimeMillis() + UUID.randomUUID(), password, testParams.withInitialSync, - testParams.enableCrypto + testParams.withCryptoEnabled ); Assert.assertNotNull(session); return session; @@ -198,7 +198,7 @@ private MXSession logIntoAccount(@NonNull final String userId, @NonNull final String password, @NonNull final SessionTestParams testParams) throws InterruptedException { final Context context = InstrumentationRegistry.getContext(); - final MXSession session = logAccountAndSync(context, userId, password, testParams.withInitialSync, testParams.enableCrypto, testParams.withLazyLoading); + final MXSession session = logAccountAndSync(context, userId, password, testParams.withInitialSync, testParams.withCryptoEnabled, testParams.withLazyLoading); Assert.assertNotNull(session); return session; } diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/SessionTestParams.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/SessionTestParams.java index fcd90d148..e76edd482 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/SessionTestParams.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/SessionTestParams.java @@ -1,14 +1,30 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.common; public class SessionTestParams { final boolean withInitialSync; - final boolean enableCrypto; + final boolean withCryptoEnabled; final boolean withLazyLoading; private SessionTestParams(final Builder builder) { withInitialSync = builder.withInitialSync; - enableCrypto = builder.enableCrypto; + withCryptoEnabled = builder.withCryptoEnabled; withLazyLoading = builder.withLazyLoading; } @@ -18,7 +34,7 @@ public static Builder newBuilder() { public static final class Builder { private boolean withInitialSync; - private boolean enableCrypto; + private boolean withCryptoEnabled; private boolean withLazyLoading; public Builder() { @@ -29,8 +45,8 @@ public Builder withInitialSync(final boolean withInitialSync) { return this; } - public Builder enableCrypto(final boolean enableCrypto) { - this.enableCrypto = enableCrypto; + public Builder withCryptoEnabled(final boolean withCryptoEnabled) { + this.withCryptoEnabled = withCryptoEnabled; return this; } diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 043ab8c49..97a5949a2 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -78,7 +78,7 @@ public class CryptoTest { private CommonTestHelper mTestHelper = new CommonTestHelper(); private final SessionTestParams defaultSessionParams = SessionTestParams.newBuilder().withInitialSync(true).build(); - private final SessionTestParams encryptedSessionParams = SessionTestParams.newBuilder().withInitialSync(true).enableCrypto(true).build(); + private final SessionTestParams encryptedSessionParams = SessionTestParams.newBuilder().withInitialSync(true).withCryptoEnabled(true).build(); private static final String LOG_TAG = "CryptoTest"; diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomMembersTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomMembersTest.java index 9a99dceec..663b67f15 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomMembersTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomMembersTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.lazyloading; import android.support.test.InstrumentationRegistry; diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index 7a6a5c247..6b5de0cc1 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -16,14 +16,12 @@ package org.matrix.androidsdk.lazyloading; import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; import android.text.TextUtils; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; -import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; import org.matrix.androidsdk.RestClient; import org.matrix.androidsdk.common.CommonTestHelper; diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java index fd130d1f4..dbc88c7ea 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java @@ -16,19 +16,16 @@ package org.matrix.androidsdk.lazyloading; import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; import junit.framework.Assert; import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; -import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; import org.matrix.androidsdk.RestClient; import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.data.Room; -import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.data.RoomSummary; @FixMethodOrder(MethodSorters.JVM) From b1abf4b3e362e1c41d4a8c7b0e2b8120fbbd875e Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 21 Sep 2018 19:23:37 +0200 Subject: [PATCH 197/236] EventTimeline : break things up to facilitate testing --- .../matrix/androidsdk/data/EventTimeline.java | 321 +++--------------- .../androidsdk/data/IEventTimeline.java | 76 +++++ .../data/TimelineJoinRoomSyncHandler.java | 295 ++++++++++++++++ 3 files changed, 411 insertions(+), 281 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/data/IEventTimeline.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/data/TimelineJoinRoomSyncHandler.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java index 426d57725..a77898869 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java @@ -20,6 +20,7 @@ import android.os.AsyncTask; import android.os.Looper; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; @@ -65,38 +66,9 @@ * with events on calls of [MXEventTimeline paginate] in backwards or forwards direction. * Events are stored in a in-memory store (MXMemoryStore). */ -public class EventTimeline { +public class EventTimeline implements IEventTimeline { private static final String LOG_TAG = EventTimeline.class.getSimpleName(); - /** - * The direction from which an incoming event is considered. - */ - public enum Direction { - /** - * Forwards when the event is added to the end of the timeline. - * These events come from the /sync stream or from forwards pagination. - */ - FORWARDS, - - /** - * Backwards when the event is added to the start of the timeline. - * These events come from a back pagination. - */ - BACKWARDS - } - - public interface EventTimelineListener { - - /** - * Call when an event has been handled in the timeline. - * - * @param event the event. - * @param direction the direction. - * @param roomState the room state - */ - void onEvent(Event event, Direction direction, RoomState roomState); - } - /** * The initial event id used to initialise the timeline. * null in case of live timeline. @@ -154,7 +126,7 @@ public interface EventTimelineListener { /** * true if the back history has been retrieved. */ - private boolean mCanBackPaginate = true; + public boolean mCanBackPaginate = true; /** * true if the last back chunck has been received @@ -223,6 +195,7 @@ public EventTimeline(MXDataHandler dataHandler, String roomId, String eventId) { * * @param isHistorical true when the current timeline is an historical one */ + @Override public void setIsHistorical(boolean isHistorical) { mIsHistorical = isHistorical; } @@ -237,6 +210,7 @@ public String getTimelineId() { /** * @return the dedicated room */ + @Override public Room getRoom() { return mRoom; } @@ -244,6 +218,7 @@ public Room getRoom() { /** * @return the used store */ + @Override public IMXStore getStore() { return mStore; } @@ -258,6 +233,7 @@ public String getInitialEventId() { /** * @return true if this timeline is the live one */ + @Override public boolean isLiveTimeline() { return mIsLiveTimeline; } @@ -316,6 +292,7 @@ public void initHistory() { /** * @return The state of the room at the top most recent event of the timeline. */ + @Override public RoomState getState() { return mState; } @@ -325,17 +302,39 @@ public RoomState getState() { * * @param state the new state. */ + @Override public void setState(RoomState state) { mState = state; } /** - * @return the back state. + * Update the backState. + * + * @param state the new backState. + */ + @Override + public void setBackState(RoomState state) { + mBackState = state; + } + + /** + * @return the backState. */ - private RoomState getBackState() { + @Override + public RoomState getBackState() { return mBackState; } + /** + * Lock over the backPaginate process + * + * @param canBackPaginate the state of the lock (true/false) + */ + @Override + public void setCanBackPaginate(final boolean canBackPaginate) { + mCanBackPaginate = canBackPaginate; + } + /** * Make a deep copy or the dedicated state. * @@ -356,7 +355,8 @@ private void deepCopyState(Direction direction) { * @param direction the direction; ie. forwards for live state, backwards for back state * @return true if the event has been processed. */ - private boolean processStateEvent(Event event, Direction direction) { + @Override + public boolean processStateEvent(Event event, Direction direction) { RoomState affectedState = (direction == Direction.FORWARDS) ? mState : mBackState; boolean isProcessed = affectedState.applyState(getStore(), event, direction); @@ -398,252 +398,9 @@ public void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync) { * @param roomSync the roomSync. * @param isGlobalInitialSync true if the sync has been triggered by a global initial sync */ - public void handleJoinedRoomSync(RoomSync roomSync, boolean isGlobalInitialSync) { - String membership = null; - String myUserId = mDataHandler.getMyUser().user_id; - RoomSummary currentSummary = null; - - RoomMember selfMember = mState.getMember(mDataHandler.getMyUser().user_id); - - if (null != selfMember) { - membership = selfMember.membership; - } - - boolean isRoomInitialSync = (null == membership) || TextUtils.equals(membership, RoomMember.MEMBERSHIP_INVITE); - - // Check whether the room was pending on an invitation. - if (TextUtils.equals(membership, RoomMember.MEMBERSHIP_INVITE)) { - // Reset the storage of this room. An initial sync of the room will be done with the provided 'roomSync'. - Log.d(LOG_TAG, "handleJoinedRoomSync: clean invited room from the store " + mRoomId); - mStore.deleteRoomData(mRoomId); - - // clear the states - RoomState state = new RoomState(); - state.roomId = mRoomId; - state.setDataHandler(mDataHandler); - - mBackState = mState = state; - } - - if ((null != roomSync.state) && (null != roomSync.state.events) && (roomSync.state.events.size() > 0)) { - if (isRoomInitialSync) { - Log.d(LOG_TAG, "## handleJoinedRoomSync() : " + roomSync.state.events.size() + " events for room " + mRoomId + " in store " + getStore()); - } - - // Build/Update first the room state corresponding to the 'start' of the timeline. - // Note: We consider it is not required to clone the existing room state here, because no notification is posted for these events. - if (mDataHandler.isAlive()) { - for (Event event : roomSync.state.events) { - try { - processStateEvent(event, Direction.FORWARDS); - } catch (Exception e) { - Log.e(LOG_TAG, "processStateEvent failed " + e.getMessage(), e); - } - } - - mRoom.setReadyState(true); - } else { - Log.e(LOG_TAG, "## handleJoinedRoomSync() : mDataHandler.isAlive() is false"); - } - - // if it is an initial sync, the live state is initialized here - // so the back state must also be initialized - if (isRoomInitialSync) { - Log.d(LOG_TAG, "## handleJoinedRoomSync() : retrieve X " + mState.getLoadedMembers().size() + " members for room " + mRoomId); - mBackState = mState.deepCopy(); - } - } - - // Handle now timeline.events, the room state is updated during this step too (Note: timeline events are in chronological order) - if (null != roomSync.timeline) { - if (roomSync.timeline.limited) { - if (!isRoomInitialSync) { - // There is a gap between known events and received events in this incremental sync. - currentSummary = mStore.getSummary(mRoomId); - - // define a summary if some messages are left - // the unsent messages are often displayed messages. - Event oldestEvent = mStore.getOldestEvent(mRoomId); - - // Flush the existing messages for this room by keeping state events. - mStore.deleteAllRoomMessages(mRoomId, true); - - if (oldestEvent != null) { - if (RoomSummary.isSupportedEvent(oldestEvent)) { - if (null != currentSummary) { - currentSummary.setLatestReceivedEvent(oldestEvent, mState); - mStore.storeSummary(currentSummary); - } else { - mStore.storeSummary(new RoomSummary(null, oldestEvent, mState, myUserId)); - } - } - } - - // Force a fetch of the loaded members the next time they will be requested - mState.forceMembersRequest(); - } - - // if the prev batch is set to null - // it implies there is no more data on server side. - if (null == roomSync.timeline.prevBatch) { - roomSync.timeline.prevBatch = Event.PAGINATE_BACK_TOKEN_END; - } - - // In case of limited timeline, update token where to start back pagination - mStore.storeBackToken(mRoomId, roomSync.timeline.prevBatch); - // reset the state back token - // because it does not make anymore sense - // by setting at null, the events cache will be cleared when a requesthistory will be called - mBackState.setToken(null); - // reset the back paginate lock - mCanBackPaginate = true; - } - - // any event ? - if ((null != roomSync.timeline.events) && (roomSync.timeline.events.size() > 0)) { - List events = roomSync.timeline.events; - - // save the back token - events.get(0).mToken = roomSync.timeline.prevBatch; - - // Here the events are handled in forward direction (see [handleLiveEvent:]). - // They will be added at the end of the stored events, so we keep the chronological order. - for (Event event : events) { - // the roomId is not defined. - event.roomId = mRoomId; - try { - boolean isLimited = (null != roomSync.timeline) && roomSync.timeline.limited; - - // digest the forward event - handleLiveEvent(event, !isLimited && !isGlobalInitialSync, !isGlobalInitialSync && !isRoomInitialSync); - } catch (Exception e) { - Log.e(LOG_TAG, "timeline event failed " + e.getMessage(), e); - } - } - } - } - - if (isRoomInitialSync) { - // any request history can be triggered by now. - mRoom.setReadyState(true); - } - // Finalize initial sync - else { - if ((null != roomSync.timeline) && roomSync.timeline.limited) { - // The room has been synced with a limited timeline - mDataHandler.onRoomFlush(mRoomId); - } - } - - // the EventTimeLine is used when displaying a room preview - // so, the following items should only be called when it is a live one. - if (mIsLiveTimeline) { - // check if the summary is defined - // after a sync, the room summary might not be defined because the latest message did not generate a room summary/ - if (null != mStore.getRoom(mRoomId)) { - RoomSummary summary = mStore.getSummary(mRoomId); - - // if there is no defined summary - // we have to create a new one - if (null == summary) { - // define a summary if some messages are left - // the unsent messages are often displayed messages. - Event oldestEvent = mStore.getOldestEvent(mRoomId); - - // if there is an oldest event, use it to set a summary - if (oldestEvent != null) { - // always defined a room summary else the room won't be displayed in the recents - mStore.storeSummary(new RoomSummary(null, oldestEvent, mState, myUserId)); - mStore.commit(); - - // if the event is not displayable - // back paginate until to find a valid one - if (!RoomSummary.isSupportedEvent(oldestEvent)) { - Log.e(LOG_TAG, "the room " + mRoomId + " has no valid summary, back paginate once to find a valid one"); - } - } - // use the latest known event - else if (null != currentSummary) { - currentSummary.setLatestReceivedEvent(currentSummary.getLatestReceivedEvent(), mState); - mStore.storeSummary(currentSummary); - mStore.commit(); - } - // try to build a summary from the state events - else if ((null != roomSync.state) && (null != roomSync.state.events) && (roomSync.state.events.size() > 0)) { - List events = new ArrayList<>(roomSync.state.events); - - Collections.reverse(events); - - for (Event event : events) { - event.roomId = mRoomId; - if (RoomSummary.isSupportedEvent(event)) { - if (null == summary) { - summary = new RoomSummary(mStore.getSummary(mRoomId), event, mState, myUserId); - } else { - summary.setLatestReceivedEvent(event, mState); - } - mStore.storeSummary(summary); - - mStore.commit(); - break; - } - } - } - } - } - - if (null != roomSync.unreadNotifications) { - int notifCount = 0; - int highlightCount = 0; - - if (null != roomSync.unreadNotifications.highlightCount) { - highlightCount = roomSync.unreadNotifications.highlightCount; - } - - if (null != roomSync.unreadNotifications.notificationCount) { - notifCount = roomSync.unreadNotifications.notificationCount; - } - - if ((notifCount != mState.getNotificationCount()) || (mState.getHighlightCount() != highlightCount)) { - Log.d(LOG_TAG, "## handleJoinedRoomSync() : update room state notifs count for room id " + getRoom().getRoomId() - + ": highlightCount " + highlightCount + " - notifCount " + notifCount); - - mState.setNotificationCount(notifCount); - mState.setHighlightCount(highlightCount); - mStore.storeLiveStateForRoom(mRoomId); - mDataHandler.onNotificationCountUpdate(mRoomId); - } - - // some users reported that the summary notification counts were sometimes invalid - // so check roomstates and summaries separately - RoomSummary summary = mStore.getSummary(mRoomId); - - if ((null != summary) && ((notifCount != summary.getNotificationCount()) || (summary.getHighlightCount() != highlightCount))) { - Log.d(LOG_TAG, "## handleJoinedRoomSync() : update room summary notifs count for room id " + getRoom().getRoomId() - + ": highlightCount " + highlightCount + " - notifCount " + notifCount); - - summary.setNotificationCount(notifCount); - summary.setHighlightCount(highlightCount); - mStore.flushSummary(summary); - mDataHandler.onNotificationCountUpdate(mRoomId); - } - } - - // TODO LazyLoading, maybe this should be done earlier, because nb of members can be usefull in the instruction above. - if (roomSync.roomSyncSummary != null) { - RoomSummary summary = mStore.getSummary(mRoomId); - - if (summary == null) { - // Should never happen here - Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!! RoomSummary is null !!!!!!!!!!!!!!!!!!!!!"); - } else { - summary.setRoomSyncSummary(roomSync.roomSyncSummary); - - mStore.flushSummary(summary); - } - } - - } + public void handleJoinedRoomSync(@NonNull final RoomSync roomSync, final boolean isGlobalInitialSync) { + final TimelineJoinRoomSyncHandler joinRoomSyncHandler = new TimelineJoinRoomSyncHandler(this, roomSync, isGlobalInitialSync); + joinRoomSyncHandler.handle(); } /** @@ -849,7 +606,8 @@ private void triggerPush(Event event) { * @param checkRedactedStateEvent set to true to check if it triggers a state event redaction * @param withPush set to true to trigger pushes when it is required */ - private void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolean withPush) { + @Override + public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolean withPush) { MyUser myUser = mDataHandler.getMyUser(); // Decrypt event if necessary @@ -1168,6 +926,7 @@ public void run() { * * @return true if a back pagination can be triggered. */ + @Override public boolean canBackPaginate() { // One at a time please return !mIsBackPaginating diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/IEventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/IEventTimeline.java new file mode 100644 index 000000000..6aec8675b --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/IEventTimeline.java @@ -0,0 +1,76 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.data; + +import org.matrix.androidsdk.data.store.IMXStore; +import org.matrix.androidsdk.rest.callback.ApiCallback; +import org.matrix.androidsdk.rest.model.Event; + +interface IEventTimeline { + void setIsHistorical(boolean isHistorical); + + Room getRoom(); + + IMXStore getStore(); + + boolean isLiveTimeline(); + + RoomState getState(); + + void setState(RoomState state); + + void setBackState(RoomState state); + + RoomState getBackState(); + + boolean processStateEvent(Event event, Direction direction); + + void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolean withPush); + + boolean canBackPaginate(); + + void setCanBackPaginate(boolean canBackPaginate); + + /** + * The direction from which an incoming event is considered. + */ + enum Direction { + /** + * Forwards when the event is added to the end of the timeline. + * These events come from the /sync stream or from forwards pagination. + */ + FORWARDS, + + /** + * Backwards when the event is added to the start of the timeline. + * These events come from a back pagination. + */ + BACKWARDS + } + + interface EventTimelineListener { + + /** + * Call when an event has been handled in the timeline. + * + * @param event the event. + * @param direction the direction. + * @param roomState the room state + */ + void onEvent(Event event, Direction direction, RoomState roomState); + } +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/TimelineJoinRoomSyncHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/TimelineJoinRoomSyncHandler.java new file mode 100644 index 000000000..ebecad7bd --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/TimelineJoinRoomSyncHandler.java @@ -0,0 +1,295 @@ +package org.matrix.androidsdk.data; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import org.matrix.androidsdk.MXDataHandler; +import org.matrix.androidsdk.data.store.IMXStore; +import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.rest.model.RoomMember; +import org.matrix.androidsdk.rest.model.sync.RoomSync; +import org.matrix.androidsdk.util.Log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * This class is responsible for handling a Join RoomSync + */ +class TimelineJoinRoomSyncHandler { + + private static final String LOG_TAG = EventTimeline.class.getSimpleName(); + + private final IEventTimeline mEventTimeline; + private final RoomSync mRoomSync; + private final boolean mIsGlobalInitialSync; + + public TimelineJoinRoomSyncHandler(@NonNull final IEventTimeline eventTimeline, + @NonNull final RoomSync roomSync, + final boolean isGlobalInitialSync) { + mEventTimeline = eventTimeline; + mRoomSync = roomSync; + mIsGlobalInitialSync = isGlobalInitialSync; + } + + + public void handle() { + final IMXStore store = mEventTimeline.getStore(); + final Room room = mEventTimeline.getRoom(); + final MXDataHandler dataHandler = room.getDataHandler(); + final String roomId = room.getRoomId(); + final String myUserId = dataHandler.getMyUser().user_id; + final RoomMember selfMember = mEventTimeline.getState().getMember(myUserId); + final RoomSummary currentSummary = store.getSummary(roomId); + + final String membership = selfMember != null ? selfMember.membership : null; + final boolean isRoomInitialSync = (membership == null) || TextUtils.equals(membership, RoomMember.MEMBERSHIP_INVITE); + + // Check whether the room was pending on an invitation. + if (RoomMember.MEMBERSHIP_INVITE.equals(membership)) { + // Reset the storage of this room. An initial sync of the room will be done with the provided 'roomSync'. + cleanInvitedRoom(dataHandler, store, roomId); + } + if ((mRoomSync.state != null) && (mRoomSync.state.events != null) && (mRoomSync.state.events.size() > 0)) { + handleRoomSyncState(room, store, isRoomInitialSync); + } + // Handle now timeline.events, the room state is updated during this step too (Note: timeline events are in chronological order) + if (mRoomSync.timeline != null) { + handleRoomSyncTimeline(store, myUserId, roomId, currentSummary, isRoomInitialSync); + } + if (isRoomInitialSync) { + // any request history can be triggered by now. + room.setReadyState(true); + } else if (mRoomSync.timeline != null && mRoomSync.timeline.limited) { + // Finalize initial sync + // The room has been synced with a limited timeline + dataHandler.onRoomFlush(roomId); + } + // the EventTimeLine is used when displaying a room preview + // so, the following items should only be called when it is a live one. + if (mEventTimeline.isLiveTimeline()) { + handleLiveTimeline(dataHandler, store, roomId, myUserId, currentSummary); + } + } + + private void handleRoomSyncState(@NonNull final Room room, @NonNull final IMXStore store, boolean isRoomInitialSync) { + if (isRoomInitialSync) { + Log.d(LOG_TAG, "##" + mRoomSync.state.events.size() + " events " + + "for room " + room.getRoomId() + + "in store " + store + ); + } + + // Build/Update first the room state corresponding to the 'start' of the timeline. + // Note: We consider it is not required to clone the existing room state here, because no notification is posted for these events. + if (room.getDataHandler().isAlive()) { + for (Event event : mRoomSync.state.events) { + try { + mEventTimeline.processStateEvent(event, EventTimeline.Direction.FORWARDS); + } catch (Exception e) { + Log.e(LOG_TAG, "processStateEvent failed " + e.getMessage(), e); + } + } + + room.setReadyState(true); + } else { + Log.e(LOG_TAG, "## mDataHandler.isAlive() is false"); + } + // if it is an initial sync, the live state is initialized here + // so the back state must also be initialized + if (isRoomInitialSync) { + final RoomState state = mEventTimeline.getState(); + Log.d(LOG_TAG, "## handleJoinedRoomSync() : retrieve X " + state.getLoadedMembers().size() + " members for room " + room.getRoomId()); + mEventTimeline.setBackState(state.deepCopy()); + } + } + + private void cleanInvitedRoom(@NonNull final MXDataHandler dataHandler, + @NonNull final IMXStore store, + @NonNull final String roomId) { + Log.d(LOG_TAG, "clean invited room from the store " + roomId); + store.deleteRoomData(roomId); + // clear the states + final RoomState state = new RoomState(); + state.roomId = roomId; + state.setDataHandler(dataHandler); + mEventTimeline.setBackState(state); + mEventTimeline.setState(state); + } + + private void handleRoomSyncTimeline(@NonNull final IMXStore store, + @NonNull final String myUserId, + @NonNull final String roomId, + @Nullable final RoomSummary currentSummary, + final boolean isRoomInitialSync) { + if (mRoomSync.timeline.limited) { + if (!isRoomInitialSync) { + final RoomState state = mEventTimeline.getState(); + // There is a gap between known events and received events in this incremental sync. + // define a summary if some messages are left + // the unsent messages are often displayed messages. + final Event oldestEvent = store.getOldestEvent(roomId); + // Flush the existing messages for this room by keeping state events. + store.deleteAllRoomMessages(roomId, true); + if (oldestEvent != null) { + if (RoomSummary.isSupportedEvent(oldestEvent)) { + if (currentSummary != null) { + currentSummary.setLatestReceivedEvent(oldestEvent, state); + store.storeSummary(currentSummary); + } else { + store.storeSummary(new RoomSummary(null, oldestEvent, state, myUserId)); + } + } + } + // Force a fetch of the loaded members the next time they will be requested + state.forceMembersRequest(); + } + + // if the prev batch is set to null + // it implies there is no more data on server side. + if (mRoomSync.timeline.prevBatch == null) { + mRoomSync.timeline.prevBatch = Event.PAGINATE_BACK_TOKEN_END; + } + + // In case of limited timeline, update token where to start back pagination + store.storeBackToken(roomId, mRoomSync.timeline.prevBatch); + // reset the state back token + // because it does not make anymore sense + // by setting at null, the events cache will be cleared when a requesthistory will be called + mEventTimeline.getBackState().setToken(null); + // reset the back paginate lock + mEventTimeline.setCanBackPaginate(true); + } + + // any event ? + if ((null != mRoomSync.timeline.events) && (mRoomSync.timeline.events.size() > 0)) { + List events = mRoomSync.timeline.events; + + // save the back token + events.get(0).mToken = mRoomSync.timeline.prevBatch; + + // Here the events are handled in forward direction (see [handleLiveEvent:]). + // They will be added at the end of the stored events, so we keep the chronological order. + for (Event event : events) { + // the roomId is not defined. + event.roomId = roomId; + try { + boolean isLimited = (null != mRoomSync.timeline) && mRoomSync.timeline.limited; + + // digest the forward event + mEventTimeline.handleLiveEvent(event, !isLimited && !mIsGlobalInitialSync, !mIsGlobalInitialSync && !isRoomInitialSync); + } catch (Exception e) { + Log.e(LOG_TAG, "timeline event failed " + e.getMessage(), e); + } + } + } + } + + private void handleLiveTimeline(@NonNull final MXDataHandler dataHandler, + @NonNull final IMXStore store, + @NonNull final String roomId, + @NonNull final String myUserId, + @Nullable final RoomSummary currentSummary) { + final RoomState state = mEventTimeline.getState(); + // check if the summary is defined + // after a sync, the room summary might not be defined because the latest message did not generate a room summary/ + if (null != store.getRoom(roomId)) { + RoomSummary summary = store.getSummary(roomId); + // if there is no defined summary + // we have to create a new one + if (summary == null) { + // define a summary if some messages are left + // the unsent messages are often displayed messages. + Event oldestEvent = store.getOldestEvent(roomId); + + // if there is an oldest event, use it to set a summary + if (oldestEvent != null) { + // always defined a room summary else the room won't be displayed in the recents + store.storeSummary(new RoomSummary(null, oldestEvent, state, myUserId)); + store.commit(); + + // if the event is not displayable + // back paginate until to find a valid one + if (!RoomSummary.isSupportedEvent(oldestEvent)) { + Log.e(LOG_TAG, "the room " + roomId + " has no valid summary, back paginate once to find a valid one"); + } + } + // use the latest known event + else if (currentSummary != null) { + currentSummary.setLatestReceivedEvent(currentSummary.getLatestReceivedEvent(), state); + store.storeSummary(currentSummary); + store.commit(); + } + // try to build a summary from the state events + else if ((mRoomSync.state != null) && (mRoomSync.state.events != null) && (mRoomSync.state.events.size() > 0)) { + final List events = new ArrayList<>(mRoomSync.state.events); + Collections.reverse(events); + + for (Event event : events) { + event.roomId = roomId; + if (RoomSummary.isSupportedEvent(event)) { + summary = new RoomSummary(store.getSummary(roomId), event, state, myUserId); + store.storeSummary(summary); + store.commit(); + break; + } + } + } + } + } + + if (null != mRoomSync.unreadNotifications) { + int notifCount = 0; + int highlightCount = 0; + + if (null != mRoomSync.unreadNotifications.highlightCount) { + highlightCount = mRoomSync.unreadNotifications.highlightCount; + } + + if (null != mRoomSync.unreadNotifications.notificationCount) { + notifCount = mRoomSync.unreadNotifications.notificationCount; + } + + if ((notifCount != state.getNotificationCount()) || (state.getHighlightCount() != highlightCount)) { + Log.d(LOG_TAG, "## handleJoinedRoomSync() : update room state notifs count for room id " + roomId + + ": highlightCount " + highlightCount + " - notifCount " + notifCount); + + state.setNotificationCount(notifCount); + state.setHighlightCount(highlightCount); + store.storeLiveStateForRoom(roomId); + dataHandler.onNotificationCountUpdate(roomId); + } + + // some users reported that the summary notification counts were sometimes invalid + // so check roomstates and summaries separately + RoomSummary summary = store.getSummary(roomId); + + if ((null != summary) && ((notifCount != summary.getNotificationCount()) || (summary.getHighlightCount() != highlightCount))) { + Log.d(LOG_TAG, "## handleJoinedRoomSync() : update room summary notifs count for room id " + roomId + + ": highlightCount " + highlightCount + " - notifCount " + notifCount); + + summary.setNotificationCount(notifCount); + summary.setHighlightCount(highlightCount); + store.flushSummary(summary); + dataHandler.onNotificationCountUpdate(roomId); + } + } + + // TODO LazyLoading, maybe this should be done earlier, because nb of members can be usefull in the instruction above. + if (mRoomSync.roomSyncSummary != null) { + RoomSummary summary = store.getSummary(roomId); + + if (summary == null) { + // Should never happen here + Log.e(LOG_TAG, "!!!!!!!!!!!!!!!!!!!!! RoomSummary is null !!!!!!!!!!!!!!!!!!!!!"); + } else { + summary.setRoomSyncSummary(mRoomSync.roomSyncSummary); + + store.flushSummary(summary); + } + } + } + +} From dab5efe480e360dd21f773d64430acb875ee9dd1 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 24 Sep 2018 18:28:11 +0200 Subject: [PATCH 198/236] TimelineEvent : rework handling liveEvent (breaking dependencies #step2) --- .../matrix/androidsdk/crypto/CryptoTest.java | 2 +- .../androidsdk/lazyloading/RoomStateTest.java | 2 +- .../org/matrix/androidsdk/MXDataHandler.java | 2 +- .../matrix/androidsdk/data/DataRetriever.java | 1 + .../java/org/matrix/androidsdk/data/Room.java | 2 +- .../androidsdk/data/RoomPreviewData.java | 1 + .../org/matrix/androidsdk/data/RoomState.java | 1 + .../androidsdk/data/store/IMXStore.java | 2 +- .../androidsdk/data/store/MXFileStore.java | 2 +- .../androidsdk/data/store/MXMemoryStore.java | 2 +- .../data/{ => timeline}/EventTimeline.java | 461 ++---------------- .../data/{ => timeline}/IEventTimeline.java | 14 +- .../timeline/StateEventRedactionChecker.java | 169 +++++++ .../data/timeline/TimelineEventSaver.java | 66 +++ .../TimelineJoinRoomSyncHandler.java | 15 +- .../timeline/TimelineLiveEventHandler.java | 275 +++++++++++ .../data/timeline/TimelinePushWorker.java | 89 ++++ .../fragments/MatrixMessageListFragment.java | 2 +- .../fragments/MatrixMessagesFragment.java | 2 +- .../rest/client/RoomsRestClient.java | 2 +- 20 files changed, 663 insertions(+), 449 deletions(-) rename matrix-sdk/src/main/java/org/matrix/androidsdk/data/{ => timeline}/EventTimeline.java (67%) rename matrix-sdk/src/main/java/org/matrix/androidsdk/data/{ => timeline}/IEventTimeline.java (85%) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java rename matrix-sdk/src/main/java/org/matrix/androidsdk/data/{ => timeline}/TimelineJoinRoomSyncHandler.java (96%) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 97a5949a2..5e5bf4092 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -45,7 +45,7 @@ import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXOlmSessionResult; import org.matrix.androidsdk.crypto.data.MXUsersDevicesMap; -import org.matrix.androidsdk.data.EventTimeline; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.data.store.IMXStore; diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index 6b5de0cc1..6e62ef6c4 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -25,7 +25,7 @@ import org.junit.runners.MethodSorters; import org.matrix.androidsdk.RestClient; import org.matrix.androidsdk.common.CommonTestHelper; -import org.matrix.androidsdk.data.EventTimeline; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.rest.callback.SimpleApiCallback; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index e624bf2da..756b6e57d 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -33,7 +33,7 @@ import org.matrix.androidsdk.crypto.MXDecryptionException; import org.matrix.androidsdk.crypto.MXEventDecryptionResult; import org.matrix.androidsdk.data.DataRetriever; -import org.matrix.androidsdk.data.EventTimeline; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.MyUser; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java index 5dee5ce55..3c0bdb158 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java @@ -20,6 +20,7 @@ import android.text.TextUtils; import org.matrix.androidsdk.data.store.IMXStore; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.client.RoomsRestClient; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 532fd3644..4b20a4766 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -44,6 +44,7 @@ import org.matrix.androidsdk.crypto.MXCryptoError; import org.matrix.androidsdk.crypto.data.MXEncryptEventContentResult; import org.matrix.androidsdk.data.store.IMXStore; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.db.MXMediasCache; import org.matrix.androidsdk.listeners.IMXEventListener; import org.matrix.androidsdk.listeners.MXEventListener; @@ -152,7 +153,6 @@ public void init(IMXStore store, String roomId, MXDataHandler dataHandler) { mLiveTimeline.setRoomId(roomId); mDataHandler = dataHandler; mStore = store; - if (null != mDataHandler) { mMyUserId = mDataHandler.getUserId(); mLiveTimeline.setDataHandler(mStore, dataHandler); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomPreviewData.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomPreviewData.java index 7a909ffa3..23377af38 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomPreviewData.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomPreviewData.java @@ -22,6 +22,7 @@ import android.text.TextUtils; import org.matrix.androidsdk.MXSession; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.MatrixError; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 9c435146c..840ac4c60 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -26,6 +26,7 @@ import org.matrix.androidsdk.MXDataHandler; import org.matrix.androidsdk.call.MXCallsManager; import org.matrix.androidsdk.data.store.IMXStore; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.model.Event; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java index ae32c0cca..8c5b90da2 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/IMXStore.java @@ -21,7 +21,7 @@ import android.content.Context; import android.support.annotation.Nullable; -import org.matrix.androidsdk.data.EventTimeline; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomAccountData; import org.matrix.androidsdk.data.RoomSummary; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java index 3e44de780..765a2b570 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java @@ -24,7 +24,7 @@ import android.text.TextUtils; import org.matrix.androidsdk.HomeServerConnectionConfig; -import org.matrix.androidsdk.data.EventTimeline; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomAccountData; import org.matrix.androidsdk.data.RoomState; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java index ddcc83d5d..460efe9f5 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java @@ -24,7 +24,7 @@ import android.support.annotation.Nullable; import android.text.TextUtils; -import org.matrix.androidsdk.data.EventTimeline; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomAccountData; import org.matrix.androidsdk.data.RoomSummary; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java similarity index 67% rename from matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java rename to matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java index a77898869..ce9a8c06b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java @@ -16,7 +16,7 @@ * limitations under the License. */ -package org.matrix.androidsdk.data; +package org.matrix.androidsdk.data.timeline; import android.os.AsyncTask; import android.os.Looper; @@ -24,28 +24,21 @@ import android.support.annotation.Nullable; import android.text.TextUtils; -import com.google.gson.JsonObject; - import org.matrix.androidsdk.MXDataHandler; -import org.matrix.androidsdk.call.MXCall; +import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.data.RoomSummary; import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.data.store.MXMemoryStore; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.model.Event; -import org.matrix.androidsdk.rest.model.EventContent; import org.matrix.androidsdk.rest.model.EventContext; import org.matrix.androidsdk.rest.model.MatrixError; -import org.matrix.androidsdk.rest.model.ReceiptData; -import org.matrix.androidsdk.rest.model.RoomMember; import org.matrix.androidsdk.rest.model.TokensChunkEvents; -import org.matrix.androidsdk.rest.model.bingrules.BingRule; import org.matrix.androidsdk.rest.model.sync.InvitedRoomSync; import org.matrix.androidsdk.rest.model.sync.RoomSync; -import org.matrix.androidsdk.util.BingRulesManager; -import org.matrix.androidsdk.util.EventDisplay; import org.matrix.androidsdk.util.FilterUtil; -import org.matrix.androidsdk.util.JsonUtils; import org.matrix.androidsdk.util.Log; import java.util.ArrayList; @@ -148,6 +141,13 @@ public class EventTimeline implements IEventTimeline { */ private final String mTimelineId = System.currentTimeMillis() + ""; + // Allows to store event and roomSummary + private final TimelineEventSaver mTimelineEventSaver = new TimelineEventSaver(this); + + private final StateEventRedactionChecker mStateEventRedactionChecker = new StateEventRedactionChecker(this); + + private TimelinePushWorker mTimelinePushWorker; + /** * Constructor from room. * @@ -188,6 +188,7 @@ public EventTimeline(MXDataHandler dataHandler, String roomId, String eventId) { mState.setDataHandler(dataHandler); mBackState.setDataHandler(dataHandler); + mTimelinePushWorker = new TimelinePushWorker(mDataHandler); } /** @@ -200,9 +201,18 @@ public void setIsHistorical(boolean isHistorical) { mIsHistorical = isHistorical; } + /** + * Returns true if the current timeline is an historical one + */ + @Override + public boolean isHistorical() { + return mIsHistorical; + } + /* * @return the unique identifier */ + @Override public String getTimelineId() { return mTimelineId; } @@ -269,12 +279,14 @@ public void setDataHandler(IMXStore store, MXDataHandler dataHandler) { mDataHandler = dataHandler; mState.setDataHandler(dataHandler); mBackState.setDataHandler(dataHandler); + mTimelinePushWorker = new TimelinePushWorker(mDataHandler); } /** * Reset the back state so that future history requests start over from live. * Must be called when opening a room if interested in history. */ + @Override public void initHistory() { mBackState = mState.deepCopy(); mCanBackPaginate = true; @@ -340,7 +352,7 @@ public void setCanBackPaginate(final boolean canBackPaginate) { * * @param direction the room state direction to deep copy. */ - private void deepCopyState(Direction direction) { + public void deepCopyState(Direction direction) { if (direction == Direction.FORWARDS) { mState = mState.deepCopy(); } else { @@ -420,184 +432,9 @@ public void storeOutgoingEvent(Event event) { * @param event the event to store */ private void storeEvent(Event event) { - String myUserId = mDataHandler.getCredentials().userId; - - // create dummy read receipt for any incoming event - // to avoid not synchronized read receipt and event - if ((null != event.getSender()) && (null != event.eventId)) { - mRoom.handleReceiptData(new ReceiptData(event.getSender(), event.eventId, event.originServerTs)); - } - - mStore.storeLiveRoomEvent(event); - - if (RoomSummary.isSupportedEvent(event)) { - RoomSummary summary = mStore.getSummary(event.roomId); - - if (null == summary) { - summary = new RoomSummary(summary, event, mState, myUserId); - } else { - summary.setLatestReceivedEvent(event, mState); - } - - mStore.storeSummary(summary); - } - } - - /** - * Store a live room event. - * - * @param event The event to be stored. - * @param checkRedactedStateEvent true to check if this event redacts a state event - */ - private void storeLiveRoomEvent(Event event, boolean checkRedactedStateEvent) { - boolean store = false; - String myUserId = mDataHandler.getCredentials().userId; - - if (Event.EVENT_TYPE_REDACTION.equals(event.getType())) { - if (event.getRedactedEventId() != null) { - Event eventToPrune = mStore.getEvent(event.getRedactedEventId(), event.roomId); - - // when an event is redacted, some fields must be kept. - if (null != eventToPrune) { - store = true; - - // remove expected keys - eventToPrune.prune(event); - - // store the prune event - storeEvent(eventToPrune); - - // store the redaction event too (for the read markers management) - storeEvent(event); - - // the redaction check must not be done during an initial sync - // or the redacted event is received with roomSync.timeline.limited - if (checkRedactedStateEvent && eventToPrune.stateKey != null) { - checkStateEventRedaction(event); - } - - // search the latest displayable event - // to replace the summary text - List events = new ArrayList<>(mStore.getRoomMessages(event.roomId)); - for (int index = events.size() - 1; index >= 0; index--) { - Event anEvent = events.get(index); - if (RoomSummary.isSupportedEvent(anEvent)) { - // Decrypt event if necessary - if (TextUtils.equals(anEvent.getType(), Event.EVENT_TYPE_MESSAGE_ENCRYPTED)) { - if (null != mDataHandler.getCrypto()) { - mDataHandler.decryptEvent(anEvent, getTimelineId()); - } - } - - EventDisplay eventDisplay = new EventDisplay(mStore.getContext(), anEvent, mState); - - // ensure that message can be displayed - if (!TextUtils.isEmpty(eventDisplay.getTextualDisplay())) { - event = anEvent; - break; - } - } - - } - } else { - // the redaction check must not be done during an initial sync - // or the redacted event is received with roomSync.timeline.limited - if (checkRedactedStateEvent) { - checkStateEventRedaction(event); - } - } - } - } else { - // the candidate events are not stored. - store = !event.isCallEvent() || !Event.EVENT_TYPE_CALL_CANDIDATES.equals(event.getType()); - - // thread issue - // if the user leaves a room, - if (Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(event.getType()) && myUserId.equals(event.stateKey)) { - String membership = event.getContentAsJsonObject().getAsJsonPrimitive("membership").getAsString(); - - if (RoomMember.MEMBERSHIP_LEAVE.equals(membership) || RoomMember.MEMBERSHIP_BAN.equals(membership)) { - store = mIsHistorical; - // delete the room and warn the listener of the leave event only at the end of the events chunk processing - } - } - } - - if (store) { - storeEvent(event); - } - - // warn the listener that a new room has been created - if (Event.EVENT_TYPE_STATE_ROOM_CREATE.equals(event.getType())) { - mDataHandler.onNewRoom(event.roomId); - } - - // warn the listeners that a room has been joined - if (Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(event.getType()) && myUserId.equals(event.stateKey)) { - String membership = event.getContentAsJsonObject().getAsJsonPrimitive("membership").getAsString(); - - if (RoomMember.MEMBERSHIP_JOIN.equals(membership)) { - mDataHandler.onJoinRoom(event.roomId); - } else if (RoomMember.MEMBERSHIP_INVITE.equals(membership)) { - mDataHandler.onNewRoom(event.roomId); - } - } + mTimelineEventSaver.storeEvent(event); } - /** - * Trigger a push if there is a dedicated push rules which implies it. - * - * @param event the event - */ - private void triggerPush(Event event) { - BingRule bingRule; - boolean outOfTimeEvent = false; - long maxlifetime = 0; - long eventLifeTime = 0; - - JsonObject eventContent = event.getContentAsJsonObject(); - - if (eventContent.has("lifetime")) { - maxlifetime = eventContent.get("lifetime").getAsLong(); - eventLifeTime = System.currentTimeMillis() - event.getOriginServerTs(); - - outOfTimeEvent = eventLifeTime > maxlifetime; - } - - BingRulesManager bingRulesManager = mDataHandler.getBingRulesManager(); - - // If the bing rules apply, bing - if (!outOfTimeEvent - && (bingRulesManager != null) - && (null != (bingRule = bingRulesManager.fulfilledBingRule(event)))) { - - if (bingRule.shouldNotify()) { - // bing the call events only if they make sense - if (Event.EVENT_TYPE_CALL_INVITE.equals(event.getType())) { - long lifeTime = event.getAge(); - - if (Long.MAX_VALUE == lifeTime) { - lifeTime = System.currentTimeMillis() - event.getOriginServerTs(); - } - - if (lifeTime > MXCall.CALL_TIMEOUT_MS) { - Log.d(LOG_TAG, "handleLiveEvent : IGNORED onBingEvent rule id " + bingRule.ruleId + " event id " + event.eventId - + " in " + event.roomId); - return; - } - } - - Log.d(LOG_TAG, "handleLiveEvent : onBingEvent rule id " + bingRule.ruleId + " event id " + event.eventId + " in " + event.roomId); - mDataHandler.onBingEvent(event, mState, bingRule); - } else { - Log.d(LOG_TAG, "handleLiveEvent :rule id " + bingRule.ruleId + " event id " + event.eventId - + " in " + event.roomId + " has a mute notify rule"); - } - } else if (outOfTimeEvent) { - Log.e(LOG_TAG, "handleLiveEvent : outOfTimeEvent for " + event.eventId + " in " + event.roomId); - Log.e(LOG_TAG, "handleLiveEvent : outOfTimeEvent maxlifetime " + maxlifetime + " eventLifeTime " + eventLifeTime); - } - } /** * Handle events coming down from the event stream. @@ -608,122 +445,8 @@ private void triggerPush(Event event) { */ @Override public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolean withPush) { - MyUser myUser = mDataHandler.getMyUser(); - - // Decrypt event if necessary - mDataHandler.decryptEvent(event, getTimelineId()); - - // dispatch the call events to the calls manager - if (event.isCallEvent()) { - mDataHandler.getCallsManager().handleCallEvent(mStore, event); - - storeLiveRoomEvent(event, false); - - // the candidates events are not tracked - // because the users don't need to see the peer exchanges. - if (!TextUtils.equals(event.getType(), Event.EVENT_TYPE_CALL_CANDIDATES)) { - // warn the listeners - // general listeners - mDataHandler.onLiveEvent(event, mState); - - // timeline listeners - onEvent(event, Direction.FORWARDS, mState); - } - - // trigger pushes when it is required - if (withPush) { - triggerPush(event); - } - - } else { - Event storedEvent = mStore.getEvent(event.eventId, event.roomId); - - // avoid processing event twice - if (null != storedEvent) { - // an event has been echoed - if (storedEvent.getAge() == Event.DUMMY_EVENT_AGE) { - mStore.deleteEvent(storedEvent); - mStore.storeLiveRoomEvent(event); - mStore.commit(); - Log.d(LOG_TAG, "handleLiveEvent : the event " + event.eventId + " in " + event.roomId + " has been echoed"); - } else { - Log.d(LOG_TAG, "handleLiveEvent : the event " + event.eventId + " in " + event.roomId + " already exist."); - return; - } - } - - // Room event - if (event.roomId != null) { - // check if the room has been joined - // the initial sync + the first requestHistory call is done here - // instead of being done in the application - if (Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(event.getType()) && TextUtils.equals(event.getSender(), mDataHandler.getUserId())) { - EventContent eventContent = JsonUtils.toEventContent(event.getContentAsJsonObject()); - EventContent prevEventContent = event.getPrevContent(); - - String prevMembership = null; - - if (null != prevEventContent) { - prevMembership = prevEventContent.membership; - } - - // if the membership keeps the same value "join". - // it should mean that the user profile has been updated. - if (!event.isRedacted() && TextUtils.equals(prevMembership, eventContent.membership) - && TextUtils.equals(RoomMember.MEMBERSHIP_JOIN, eventContent.membership)) { - // check if the user updates his profile from another device. - - boolean hasAccountInfoUpdated = false; - - if (!TextUtils.equals(eventContent.displayname, myUser.displayname)) { - hasAccountInfoUpdated = true; - myUser.displayname = eventContent.displayname; - mStore.setDisplayName(myUser.displayname, event.getOriginServerTs()); - } - - if (!TextUtils.equals(eventContent.avatar_url, myUser.getAvatarUrl())) { - hasAccountInfoUpdated = true; - myUser.setAvatarUrl(eventContent.avatar_url); - mStore.setAvatarURL(myUser.avatar_url, event.getOriginServerTs()); - } - - if (hasAccountInfoUpdated) { - mDataHandler.onAccountInfoUpdate(myUser); - } - } - } - - RoomState previousState = mState; - - if (event.stateKey != null) { - // copy the live state before applying any update - deepCopyState(Direction.FORWARDS); - - // check if the event has been processed - if (!processStateEvent(event, Direction.FORWARDS)) { - // not processed -> do not warn the application - // assume that the event is a duplicated one. - return; - } - } - - storeLiveRoomEvent(event, checkRedactedStateEvent); - - // warn the listeners - // general listeners - mDataHandler.onLiveEvent(event, previousState); - - // timeline listeners - onEvent(event, Direction.FORWARDS, previousState); - - // trigger pushes when it is required - if (withPush) { - triggerPush(event); - } - } else { - Log.e(LOG_TAG, "Unknown live event type: " + event.getType()); - } - } + final TimelineLiveEventHandler liveEventHandler = new TimelineLiveEventHandler(this, mTimelineEventSaver, mStateEventRedactionChecker, mTimelinePushWorker); + liveEventHandler.handleLiveEvent(event, checkRedactedStateEvent, withPush); } @@ -1309,133 +1032,6 @@ public void run() { }); } - //============================================================================================================== - // State events redactions - //============================================================================================================== - - /** - * Redaction of a state event might require to reload the timeline - * because the room states has to be updated. - * - * @param redactionEvent the redaction event - */ - private void checkStateEventRedaction(final Event redactionEvent) { - - final String eventId = redactionEvent.getRedactedEventId(); - Log.d(LOG_TAG, "checkStateEventRedaction of event " + eventId); - - // check if the state events is locally known - mState.getStateEvents(getStore(), null, new SimpleApiCallback>() { - @Override - public void onSuccess(List stateEvents) { - - // Check whether the current room state depends on this redacted event. - boolean isFound = false; - for (int index = 0; index < stateEvents.size(); index++) { - Event stateEvent = stateEvents.get(index); - - if (TextUtils.equals(stateEvent.eventId, eventId)) { - - Log.d(LOG_TAG, "checkStateEventRedaction: the current room state has been modified by the event redaction"); - - // remove expected keys - stateEvent.prune(redactionEvent); - - stateEvents.set(index, stateEvent); - - // digest the updated state - processStateEvent(stateEvent, Direction.FORWARDS); - - isFound = true; - break; - } - } - - if (!isFound) { - // Else try to find the redacted event among members which - // are stored apart from other state events - - // Reason: The membership events are not anymore stored in the application store - // until we have found a way to improve the way they are stored. - // It used to have many out of memory errors because they are too many stored small memory objects. - // see https://github.com/matrix-org/matrix-android-sdk/issues/196 - - // Note: if lazy loading is on, getMemberByEventId() can return null, but it is ok, because we just want to update our cache - RoomMember member = mState.getMemberByEventId(eventId); - if (member != null) { - Log.d(LOG_TAG, "checkStateEventRedaction: the current room members list has been modified by the event redaction"); - - // the android SDK does not store stock member events but a representation of them, RoomMember. - // Prune this representation - member.prune(); - - isFound = true; - } - } - - if (isFound) { - mStore.storeLiveStateForRoom(mRoomId); - - // warn that there was a flush - initHistory(); - mDataHandler.onRoomFlush(mRoomId); - } else { - Log.d(LOG_TAG, "checkStateEventRedaction: the redacted event is unknown. Fetch it from the homeserver"); - checkStateEventRedactionWithHomeserver(eventId); - } - } - }); - } - - /** - * Check with the HS whether the redacted event impacts the room data we have locally. - * If yes, local data must be pruned. - * - * @param eventId the redacted event id - */ - private void checkStateEventRedactionWithHomeserver(String eventId) { - Log.d(LOG_TAG, "checkStateEventRedactionWithHomeserver on event Id " + eventId); - - // We need to figure out if this redacted event is a room state in the past. - // If yes, we must prune the `prev_content` of the state event that replaced it. - // Indeed, redacted information shouldn't spontaneously appear when you backpaginate... - // TODO: This is no more implemented (see https://github.com/vector-im/riot-ios/issues/443). - // The previous implementation based on a room initial sync was too heavy server side - // and has been removed. - - if (!TextUtils.isEmpty(eventId)) { - Log.d(LOG_TAG, "checkStateEventRedactionWithHomeserver : retrieving the event"); - - mDataHandler.getDataRetriever().getRoomsRestClient().getEvent(mRoomId, eventId, new ApiCallback() { - @Override - public void onSuccess(Event event) { - if ((null != event) && (null != event.stateKey)) { - Log.d(LOG_TAG, "checkStateEventRedactionWithHomeserver : the redacted event is a state event in the past." + - " TODO: prune prev_content of the new state event"); - - } else { - Log.d(LOG_TAG, "checkStateEventRedactionWithHomeserver : the redacted event is a not state event -> job is done"); - } - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "checkStateEventRedactionWithHomeserver : failed to retrieved the redacted event: onNetworkError " + e.getMessage(), e); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "checkStateEventRedactionWithHomeserver : failed to retrieved the redacted event: onNetworkError " + e.getMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "checkStateEventRedactionWithHomeserver : failed to retrieved the redacted event: onNetworkError " + e.getMessage(), e); - } - }); - } - } - //============================================================================================================== // onEvent listener management. //============================================================================================================== @@ -1477,7 +1073,8 @@ public void removeEventTimelineListener(EventTimelineListener listener) { * @param direction the direction. * @param roomState the roomState. */ - private void onEvent(final Event event, final Direction direction, final RoomState roomState) { + @Override + public void onEvent(final Event event, final Direction direction, final RoomState roomState) { // ensure that the listeners are called in the UI thread if (Looper.getMainLooper().getThread() != Thread.currentThread()) { final android.os.Handler handler = new android.os.Handler(Looper.getMainLooper()); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/IEventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java similarity index 85% rename from matrix-sdk/src/main/java/org/matrix/androidsdk/data/IEventTimeline.java rename to matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java index 6aec8675b..0a9d8baa0 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/IEventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java @@ -14,8 +14,10 @@ * limitations under the License. */ -package org.matrix.androidsdk.data; +package org.matrix.androidsdk.data.timeline; +import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.model.Event; @@ -23,12 +25,18 @@ interface IEventTimeline { void setIsHistorical(boolean isHistorical); + boolean isHistorical(); + + void initHistory(); + Room getRoom(); IMXStore getStore(); boolean isLiveTimeline(); + String getTimelineId(); + RoomState getState(); void setState(RoomState state); @@ -37,6 +45,8 @@ interface IEventTimeline { RoomState getBackState(); + void deepCopyState(Direction direction); + boolean processStateEvent(Event event, Direction direction); void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolean withPush); @@ -45,6 +55,8 @@ interface IEventTimeline { void setCanBackPaginate(boolean canBackPaginate); + void onEvent(final Event event, final Direction direction, final RoomState roomState); + /** * The direction from which an incoming event is considered. */ diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java new file mode 100644 index 000000000..60c935690 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java @@ -0,0 +1,169 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.data.timeline; + +import android.text.TextUtils; + +import org.matrix.androidsdk.MXDataHandler; +import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.data.store.IMXStore; +import org.matrix.androidsdk.rest.callback.ApiCallback; +import org.matrix.androidsdk.rest.callback.SimpleApiCallback; +import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.rest.model.MatrixError; +import org.matrix.androidsdk.rest.model.RoomMember; +import org.matrix.androidsdk.util.Log; + +import java.util.List; + +import javax.annotation.Nonnull; + + +class StateEventRedactionChecker { + + private static final String LOG_TAG = StateEventRedactionChecker.class.getSimpleName(); + private final IEventTimeline mEventTimeline; + + StateEventRedactionChecker(IEventTimeline eventTimeline) { + mEventTimeline = eventTimeline; + } + + /** + * Redaction of a state event might require to reload the timeline + * because the room states has to be updated. + * + * @param redactionEvent the redaction event + */ + public void checkStateEventRedaction(final Event redactionEvent) { + final IMXStore store = mEventTimeline.getStore(); + final Room room = mEventTimeline.getRoom(); + final MXDataHandler dataHandler = room.getDataHandler(); + final String roomId = room.getRoomId(); + final String eventId = redactionEvent.getRedacts(); + final RoomState state = mEventTimeline.getState(); + Log.d(LOG_TAG, "checkStateEventRedaction of event " + eventId); + // check if the state events is locally known + state.getStateEvents(store, null, new SimpleApiCallback>() { + @Override + public void onSuccess(List stateEvents) { + + // Check whether the current room state depends on this redacted event. + boolean isFound = false; + for (int index = 0; index < stateEvents.size(); index++) { + Event stateEvent = stateEvents.get(index); + + if (TextUtils.equals(stateEvent.eventId, eventId)) { + + Log.d(LOG_TAG, "checkStateEventRedaction: the current room state has been modified by the event redaction"); + + // remove expected keys + stateEvent.prune(redactionEvent); + stateEvents.set(index, stateEvent); + // digest the updated state + mEventTimeline.processStateEvent(stateEvent, IEventTimeline.Direction.FORWARDS); + isFound = true; + break; + } + } + + if (!isFound) { + // Else try to find the redacted event among members which + // are stored apart from other state events + + // Reason: The membership events are not anymore stored in the application store + // until we have found a way to improve the way they are stored. + // It used to have many out of memory errors because they are too many stored small memory objects. + // see https://github.com/matrix-org/matrix-android-sdk/issues/196 + + // Note: if lazy loading is on, getMemberByEventId() can return null, but it is ok, because we just want to update our cache + RoomMember member = state.getMemberByEventId(eventId); + if (member != null) { + Log.d(LOG_TAG, "checkStateEventRedaction: the current room members list has been modified by the event redaction"); + + // the android SDK does not store stock member events but a representation of them, RoomMember. + // Prune this representation + member.prune(); + + isFound = true; + } + } + + if (isFound) { + store.storeLiveStateForRoom(roomId); + // warn that there was a flush + mEventTimeline.initHistory(); + dataHandler.onRoomFlush(roomId); + } else { + Log.d(LOG_TAG, "checkStateEventRedaction: the redacted event is unknown. Fetch it from the homeserver"); + checkStateEventRedactionWithHomeserver(dataHandler, roomId, eventId); + } + } + }); + } + + /** + * Check with the HS whether the redacted event impacts the room data we have locally. + * If yes, local data must be pruned. + * + * @param eventId the redacted event id + */ + private void checkStateEventRedactionWithHomeserver(@Nonnull final MXDataHandler dataHandler, + @Nonnull final String roomId, + @Nonnull final String eventId) { + Log.d(LOG_TAG, "checkStateEventRedactionWithHomeserver on event Id " + eventId); + + // We need to figure out if this redacted event is a room state in the past. + // If yes, we must prune the `prev_content` of the state event that replaced it. + // Indeed, redacted information shouldn't spontaneously appear when you backpaginate... + // TODO: This is no more implemented (see https://github.com/vector-im/riot-ios/issues/443). + // The previous implementation based on a room initial sync was too heavy server side + // and has been removed. + if (!TextUtils.isEmpty(eventId)) { + Log.d(LOG_TAG, "checkStateEventRedactionWithHomeserver : retrieving the event"); + dataHandler.getDataRetriever().getRoomsRestClient().getEvent(roomId, eventId, new ApiCallback() { + @Override + public void onSuccess(Event event) { + if ((null != event) && (null != event.stateKey)) { + Log.d(LOG_TAG, "checkStateEventRedactionWithHomeserver : the redacted event is a state event in the past." + + " TODO: prune prev_content of the new state event"); + + } else { + Log.d(LOG_TAG, "checkStateEventRedactionWithHomeserver : the redacted event is a not state event -> job is done"); + } + } + + @Override + public void onNetworkError(Exception e) { + Log.e(LOG_TAG, "checkStateEventRedactionWithHomeserver : failed to retrieved the redacted event: onNetworkError " + e.getMessage(), e); + } + + @Override + public void onMatrixError(MatrixError e) { + Log.e(LOG_TAG, "checkStateEventRedactionWithHomeserver : failed to retrieved the redacted event: onNetworkError " + e.getMessage()); + } + + @Override + public void onUnexpectedError(Exception e) { + Log.e(LOG_TAG, "checkStateEventRedactionWithHomeserver : failed to retrieved the redacted event: onNetworkError " + e.getMessage(), e); + } + }); + } + } + + +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java new file mode 100644 index 000000000..414bf8f52 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java @@ -0,0 +1,66 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.data.timeline; + +import org.matrix.androidsdk.MXDataHandler; +import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.data.RoomSummary; +import org.matrix.androidsdk.data.store.IMXStore; +import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.rest.model.ReceiptData; + +class TimelineEventSaver { + + private final IEventTimeline mEventTimeline; + + TimelineEventSaver(IEventTimeline mEventTimeline) { + this.mEventTimeline = mEventTimeline; + } + + /** + * * Store a live room event. + * + * @param event the event to be stored. + */ + + public void storeEvent(Event event) { + final IMXStore store = mEventTimeline.getStore(); + final Room room = mEventTimeline.getRoom(); + final MXDataHandler dataHandler = room.getDataHandler(); + final String myUserId = dataHandler.getCredentials().userId; + + // create dummy read receipt for any incoming event + // to avoid not synchronized read receipt and event + if ((null != event.getSender()) && (null != event.eventId)) { + room.handleReceiptData(new ReceiptData(event.getSender(), event.eventId, event.originServerTs)); + } + store.storeLiveRoomEvent(event); + if (RoomSummary.isSupportedEvent(event)) { + final RoomState roomState = mEventTimeline.getState(); + RoomSummary summary = store.getSummary(event.roomId); + if (null == summary) { + summary = new RoomSummary(summary, event, roomState, myUserId); + } else { + summary.setLatestReceivedEvent(event, roomState); + } + + store.storeSummary(summary); + } + } + +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/TimelineJoinRoomSyncHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java similarity index 96% rename from matrix-sdk/src/main/java/org/matrix/androidsdk/data/TimelineJoinRoomSyncHandler.java rename to matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java index ebecad7bd..5727610a7 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/TimelineJoinRoomSyncHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java @@ -1,10 +1,13 @@ -package org.matrix.androidsdk.data; +package org.matrix.androidsdk.data.timeline; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; import org.matrix.androidsdk.MXDataHandler; +import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.data.RoomSummary; import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.RoomMember; @@ -20,15 +23,15 @@ */ class TimelineJoinRoomSyncHandler { - private static final String LOG_TAG = EventTimeline.class.getSimpleName(); + private static final String LOG_TAG = TimelineJoinRoomSyncHandler.class.getSimpleName(); private final IEventTimeline mEventTimeline; private final RoomSync mRoomSync; private final boolean mIsGlobalInitialSync; - public TimelineJoinRoomSyncHandler(@NonNull final IEventTimeline eventTimeline, - @NonNull final RoomSync roomSync, - final boolean isGlobalInitialSync) { + TimelineJoinRoomSyncHandler(@NonNull final IEventTimeline eventTimeline, + @NonNull final RoomSync roomSync, + final boolean isGlobalInitialSync) { mEventTimeline = eventTimeline; mRoomSync = roomSync; mIsGlobalInitialSync = isGlobalInitialSync; @@ -202,7 +205,7 @@ private void handleLiveTimeline(@NonNull final MXDataHandler dataHandler, if (summary == null) { // define a summary if some messages are left // the unsent messages are often displayed messages. - Event oldestEvent = store.getOldestEvent(roomId); + final Event oldestEvent = store.getOldestEvent(roomId); // if there is an oldest event, use it to set a summary if (oldestEvent != null) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java new file mode 100644 index 000000000..f65481be2 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java @@ -0,0 +1,275 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.data.timeline; + +import android.text.TextUtils; + +import org.matrix.androidsdk.MXDataHandler; +import org.matrix.androidsdk.data.MyUser; +import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.data.RoomSummary; +import org.matrix.androidsdk.data.store.IMXStore; +import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.rest.model.EventContent; +import org.matrix.androidsdk.rest.model.RoomMember; +import org.matrix.androidsdk.util.EventDisplay; +import org.matrix.androidsdk.util.JsonUtils; +import org.matrix.androidsdk.util.Log; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nonnull; + +class TimelineLiveEventHandler { + + private static final String LOG_TAG = TimelineLiveEventHandler.class.getSimpleName(); + + private final IEventTimeline mEventTimeline; + private final TimelineEventSaver mTimelineEventSaver; + private final StateEventRedactionChecker mStateEventRedactionChecker; + private final TimelinePushWorker mTimelinePushWorker; + + TimelineLiveEventHandler(@Nonnull final IEventTimeline eventTimeline, + @Nonnull final TimelineEventSaver timelineEventSaver, + @Nonnull final StateEventRedactionChecker stateEventRedactionChecker, + @Nonnull final TimelinePushWorker timelinePushWorker) { + mEventTimeline = eventTimeline; + mTimelineEventSaver = timelineEventSaver; + mStateEventRedactionChecker = stateEventRedactionChecker; + mTimelinePushWorker = timelinePushWorker; + } + + /** + * Handle events coming down from the event stream. + * + * @param event the live event + * @param checkRedactedStateEvent set to true to check if it triggers a state event redaction + * @param withPush set to true to trigger pushes when it is required + */ + public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolean withPush) { + final IMXStore store = mEventTimeline.getStore(); + final Room room = mEventTimeline.getRoom(); + final MXDataHandler dataHandler = room.getDataHandler(); + final String timelineId = mEventTimeline.getTimelineId(); + final MyUser myUser = dataHandler.getMyUser(); + + // Decrypt event if necessary + dataHandler.decryptEvent(event, timelineId); + + // dispatch the call events to the calls manager + if (event.isCallEvent()) { + final RoomState roomState = mEventTimeline.getState(); + dataHandler.getCallsManager().handleCallEvent(store, event); + storeLiveRoomEvent(dataHandler, store, false, event); + // the candidates events are not tracked + // because the users don't need to see the peer exchanges. + if (!TextUtils.equals(event.getType(), Event.EVENT_TYPE_CALL_CANDIDATES)) { + // warn the listeners + // general listeners + dataHandler.onLiveEvent(event, roomState); + // timeline listeners + mEventTimeline.onEvent(event, IEventTimeline.Direction.FORWARDS, roomState); + } + + // trigger pushes when it is required + if (withPush) { + mTimelinePushWorker.triggerPush(roomState, event); + } + + } else { + final Event storedEvent = store.getEvent(event.eventId, event.roomId); + + // avoid processing event twice + if (null != storedEvent) { + // an event has been echoed + if (storedEvent.getAge() == Event.DUMMY_EVENT_AGE) { + store.deleteEvent(storedEvent); + store.storeLiveRoomEvent(event); + store.commit(); + Log.d(LOG_TAG, "handleLiveEvent : the event " + event.eventId + " in " + event.roomId + " has been echoed"); + } else { + Log.d(LOG_TAG, "handleLiveEvent : the event " + event.eventId + " in " + event.roomId + " already exist."); + return; + } + } + + // Room event + if (event.roomId != null) { + // check if the room has been joined + // the initial sync + the first requestHistory call is done here + // instead of being done in the application + if (Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(event.getType()) && TextUtils.equals(event.getSender(), dataHandler.getUserId())) { + EventContent eventContent = JsonUtils.toEventContent(event.getContentAsJsonObject()); + EventContent prevEventContent = event.getPrevContent(); + + String prevMembership = null; + + if (prevEventContent != null) { + prevMembership = prevEventContent.membership; + } + + // if the membership keeps the same value "join". + // it should mean that the user profile has been updated. + if (!event.isRedacted() && TextUtils.equals(prevMembership, eventContent.membership) + && TextUtils.equals(RoomMember.MEMBERSHIP_JOIN, eventContent.membership)) { + // check if the user updates his profile from another device. + + boolean hasAccountInfoUpdated = false; + + if (!TextUtils.equals(eventContent.displayname, myUser.displayname)) { + hasAccountInfoUpdated = true; + myUser.displayname = eventContent.displayname; + store.setDisplayName(myUser.displayname, event.getOriginServerTs()); + } + + if (!TextUtils.equals(eventContent.avatar_url, myUser.getAvatarUrl())) { + hasAccountInfoUpdated = true; + myUser.setAvatarUrl(eventContent.avatar_url); + store.setAvatarURL(myUser.avatar_url, event.getOriginServerTs()); + } + + if (hasAccountInfoUpdated) { + dataHandler.onAccountInfoUpdate(myUser); + } + } + } + + final RoomState previousState = mEventTimeline.getState(); + if (event.stateKey != null) { + // copy the live state before applying any update + mEventTimeline.deepCopyState(IEventTimeline.Direction.FORWARDS); + // check if the event has been processed + if (!mEventTimeline.processStateEvent(event, IEventTimeline.Direction.FORWARDS)) { + // not processed -> do not warn the application + // assume that the event is a duplicated one. + return; + } + } + storeLiveRoomEvent(dataHandler, store, checkRedactedStateEvent, event); + + // warn the listeners + // general listeners + dataHandler.onLiveEvent(event, previousState); + + // timeline listeners + mEventTimeline.onEvent(event, IEventTimeline.Direction.FORWARDS, previousState); + + // trigger pushes when it is required + if (withPush) { + mTimelinePushWorker.triggerPush(mEventTimeline.getState(), event); + } + } else { + Log.e(LOG_TAG, "Unknown live event type: " + event.getType()); + } + } + } + + /** + * Store a live room event. + * + * @param event The event to be stored. + * @param checkRedactedStateEvent true to check if this event redacts a state event + */ + private void storeLiveRoomEvent(final MXDataHandler dataHandler, + final IMXStore store, + final boolean checkRedactedStateEvent, + Event event) { + + + boolean shouldBeSaved = false; + String myUserId = dataHandler.getCredentials().userId; + + if (Event.EVENT_TYPE_REDACTION.equals(event.getType())) { + if (event.getRedacts() != null) { + Event eventToPrune = store.getEvent(event.getRedacts(), event.roomId); + + // when an event is redacted, some fields must be kept. + if (eventToPrune != null) { + shouldBeSaved = true; + // remove expected keys + eventToPrune.prune(event); + // store the prune event + mTimelineEventSaver.storeEvent(eventToPrune); + // store the redaction event too (for the read markers management) + mTimelineEventSaver.storeEvent(event); + // the redaction check must not be done during an initial sync + // or the redacted event is received with roomSync.timeline.limited + if (checkRedactedStateEvent && eventToPrune.stateKey != null) { + mStateEventRedactionChecker.checkStateEventRedaction(event); + } + // search the latest displayable event + // to replace the summary text + final List events = new ArrayList<>(store.getRoomMessages(event.roomId)); + for (int index = events.size() - 1; index >= 0; index--) { + final Event indexedEvent = events.get(index); + if (RoomSummary.isSupportedEvent(indexedEvent)) { + // Decrypt event if necessary + if (TextUtils.equals(indexedEvent.getType(), Event.EVENT_TYPE_MESSAGE_ENCRYPTED)) { + if (null != dataHandler.getCrypto()) { + dataHandler.decryptEvent(indexedEvent, mEventTimeline.getTimelineId()); + } + } + final RoomState state = mEventTimeline.getState(); + final EventDisplay eventDisplay = new EventDisplay(store.getContext(), indexedEvent, state); + // ensure that message can be displayed + if (!TextUtils.isEmpty(eventDisplay.getTextualDisplay())) { + event = indexedEvent; + break; + } + } + + } + } else if (checkRedactedStateEvent) { + // the redaction check must not be done during an initial sync + // or the redacted event is received with roomSync.timeline.limited + mStateEventRedactionChecker.checkStateEventRedaction(event); + } + } + } else { + // the candidate events are not stored. + shouldBeSaved = !event.isCallEvent() || !Event.EVENT_TYPE_CALL_CANDIDATES.equals(event.getType()); + // thread issue + // if the user leaves a room, + if (Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(event.getType()) && myUserId.equals(event.stateKey)) { + final String membership = event.getContentAsJsonObject().getAsJsonPrimitive("membership").getAsString(); + if (RoomMember.MEMBERSHIP_LEAVE.equals(membership) || RoomMember.MEMBERSHIP_BAN.equals(membership)) { + shouldBeSaved = mEventTimeline.isHistorical(); + // delete the room and warn the listener of the leave event only at the end of the events chunk processing + } + } + } + if (shouldBeSaved) { + mTimelineEventSaver.storeEvent(event); + } + // warn the listener that a new room has been created + if (Event.EVENT_TYPE_STATE_ROOM_CREATE.equals(event.getType())) { + dataHandler.onNewRoom(event.roomId); + } + // warn the listeners that a room has been joined + if (Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(event.getType()) && myUserId.equals(event.stateKey)) { + final String membership = event.getContentAsJsonObject().getAsJsonPrimitive("membership").getAsString(); + if (RoomMember.MEMBERSHIP_JOIN.equals(membership)) { + dataHandler.onJoinRoom(event.roomId); + } else if (RoomMember.MEMBERSHIP_INVITE.equals(membership)) { + dataHandler.onNewRoom(event.roomId); + } + } + } + +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java new file mode 100644 index 000000000..35132d7b6 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java @@ -0,0 +1,89 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.data.timeline; + +import com.google.gson.JsonObject; + +import org.matrix.androidsdk.MXDataHandler; +import org.matrix.androidsdk.call.MXCall; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.rest.model.bingrules.BingRule; +import org.matrix.androidsdk.util.BingRulesManager; +import org.matrix.androidsdk.util.Log; + +import javax.annotation.Nonnull; + +public class TimelinePushWorker { + + private static final String LOG_TAG = TimelinePushWorker.class.getSimpleName(); + + @Nonnull + private final MXDataHandler mDataHandler; + + public TimelinePushWorker(@Nonnull final MXDataHandler dataHandler) { + mDataHandler = dataHandler; + } + + /** + * Trigger a push if there is a dedicated push rules which implies it. + * + * @param event the event + */ + public void triggerPush(@Nonnull final RoomState state, + @Nonnull Event event) { + BingRule bingRule; + boolean outOfTimeEvent = false; + long maxLifetime = 0; + long eventLifetime = 0; + final JsonObject eventContent = event.getContentAsJsonObject(); + if (eventContent != null && eventContent.has("lifetime")) { + maxLifetime = eventContent.get("lifetime").getAsLong(); + eventLifetime = System.currentTimeMillis() - event.getOriginServerTs(); + outOfTimeEvent = eventLifetime > maxLifetime; + } + final BingRulesManager bingRulesManager = mDataHandler.getBingRulesManager(); + // If the bing rules apply, bing + if (!outOfTimeEvent + && (bingRulesManager != null) + && (null != (bingRule = bingRulesManager.fulfilledBingRule(event)))) { + + if (bingRule.shouldNotify()) { + // bing the call events only if they make sense + if (Event.EVENT_TYPE_CALL_INVITE.equals(event.getType())) { + long lifeTime = event.getAge(); + if (Long.MAX_VALUE == lifeTime) { + lifeTime = System.currentTimeMillis() - event.getOriginServerTs(); + } + if (lifeTime > MXCall.CALL_TIMEOUT_MS) { + Log.d(LOG_TAG, "IGNORED onBingEvent rule id " + bingRule.ruleId + " event id " + event.eventId + + " in " + event.roomId); + return; + } + } + Log.d(LOG_TAG, "onBingEvent rule id " + bingRule.ruleId + " event id " + event.eventId + " in " + event.roomId); + mDataHandler.onBingEvent(event, state, bingRule); + } else { + Log.d(LOG_TAG, "rule id " + bingRule.ruleId + " event id " + event.eventId + + " in " + event.roomId + " has a mute notify rule"); + } + } else if (outOfTimeEvent) { + Log.e(LOG_TAG, "outOfTimeEvent for " + event.eventId + " in " + event.roomId); + Log.e(LOG_TAG, "outOfTimeEvent maxlifetime " + maxLifetime + " eventLifeTime " + eventLifetime); + } + } +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java index 07631e61e..9a8a81060 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java @@ -43,7 +43,7 @@ import org.matrix.androidsdk.adapters.AbstractMessagesAdapter; import org.matrix.androidsdk.adapters.MessageRow; import org.matrix.androidsdk.crypto.MXCryptoError; -import org.matrix.androidsdk.data.EventTimeline; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomMediaMessage; import org.matrix.androidsdk.data.RoomPreviewData; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java index 367a0ef68..12d29cd4c 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java @@ -29,7 +29,7 @@ import android.widget.Toast; import org.matrix.androidsdk.MXSession; -import org.matrix.androidsdk.data.EventTimeline; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomPreviewData; import org.matrix.androidsdk.data.RoomState; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java index f07cc2444..43930bc1f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/RoomsRestClient.java @@ -26,8 +26,8 @@ import org.matrix.androidsdk.HomeServerConnectionConfig; import org.matrix.androidsdk.RestClient; -import org.matrix.androidsdk.data.EventTimeline; import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.rest.api.RoomsApi; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.callback.RestAdapterCallback; From 3cf9c49ae6ae33168acbcc0a1a2c04a83785eadd Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 25 Sep 2018 10:35:13 +0200 Subject: [PATCH 199/236] TimelineEvent : rework handling invited room --- .../data/timeline/EventTimeline.java | 19 +----- .../TimelineInvitedRoomSyncHandler.java | 65 +++++++++++++++++++ 2 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java index ce9a8c06b..fa633998e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java @@ -385,23 +385,8 @@ public boolean processStateEvent(Event event, Direction direction) { * @param invitedRoomSync the invitation room events. */ public void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync) { - // Handle the state events as live events (the room state will be updated, and the listeners (if any) will be notified). - if ((null != invitedRoomSync) && (null != invitedRoomSync.inviteState) && (null != invitedRoomSync.inviteState.events)) { - - for (Event event : invitedRoomSync.inviteState.events) { - // Add a fake event id if none in order to be able to store the event - if (null == event.eventId) { - event.eventId = mRoomId + "-" + System.currentTimeMillis() + "-" + event.hashCode(); - } - - // The roomId is not defined. - event.roomId = mRoomId; - handleLiveEvent(event, false, true); - } - - // The room related to the pending invite can be considered as ready from now - mRoom.setReadyState(true); - } + final TimelineInvitedRoomSyncHandler invitedRoomSyncHandler = new TimelineInvitedRoomSyncHandler(this, invitedRoomSync); + invitedRoomSyncHandler.handle(); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java new file mode 100644 index 000000000..f8227ae81 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java @@ -0,0 +1,65 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.data.timeline; + +import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.rest.model.sync.InvitedRoomSync; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * This class is responsible for handling the invitation room events from the SyncResponse + */ +class TimelineInvitedRoomSyncHandler { + + private final IEventTimeline mEventTimeline; + private final InvitedRoomSync mInvitedRoomSync; + + TimelineInvitedRoomSyncHandler(@Nonnull final IEventTimeline eventTimeline, + @Nullable final InvitedRoomSync invitedRoomSync) { + mEventTimeline = eventTimeline; + mInvitedRoomSync = invitedRoomSync; + } + + /** + * Handle the invitation room events + */ + public void handle() { + // Handle the state events as live events (the room state will be updated, and the listeners (if any) will be notified). + if ((mInvitedRoomSync != null) && (mInvitedRoomSync.inviteState != null) && (mInvitedRoomSync.inviteState.events != null)) { + final Room room = mEventTimeline.getRoom(); + final String roomId = room.getRoomId(); + + for (Event event : mInvitedRoomSync.inviteState.events) { + // Add a fake event id if none in order to be able to store the event + if (null == event.eventId) { + event.eventId = roomId + "-" + System.currentTimeMillis() + "-" + event.hashCode(); + } + + // The roomId is not defined. + event.roomId = roomId; + mEventTimeline.handleLiveEvent(event, false, true); + } + // The room related to the pending invite can be considered as ready from now + room.setReadyState(true); + } + } + + +} From cba2dc6d748858da5459e8339fec54f39ac7ab81 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 25 Sep 2018 16:07:53 +0200 Subject: [PATCH 200/236] TimelineEvent : introduce TimelineStateHolder to manage state --- .../java/org/matrix/androidsdk/data/Room.java | 2 +- .../data/timeline/EventTimeline.java | 110 +++++--------- .../data/timeline/IEventTimeline.java | 13 -- .../timeline/StateEventRedactionChecker.java | 9 +- .../data/timeline/TimelineEventSaver.java | 11 +- .../timeline/TimelineJoinRoomSyncHandler.java | 29 ++-- .../timeline/TimelineLiveEventHandler.java | 18 ++- .../data/timeline/TimelinePushWorker.java | 4 +- .../data/timeline/TimelineStateHolder.java | 139 ++++++++++++++++++ 9 files changed, 219 insertions(+), 116 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 4b20a4766..5795e9256 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -150,13 +150,13 @@ public Room() { * @param dataHandler the data handler */ public void init(IMXStore store, String roomId, MXDataHandler dataHandler) { - mLiveTimeline.setRoomId(roomId); mDataHandler = dataHandler; mStore = store; if (null != mDataHandler) { mMyUserId = mDataHandler.getUserId(); mLiveTimeline.setDataHandler(mStore, dataHandler); } + mLiveTimeline.setRoomId(roomId); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java index fa633998e..5b904d872 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java @@ -73,16 +73,6 @@ public class EventTimeline implements IEventTimeline { */ private boolean mIsLiveTimeline; - /** - * The state of the room at the top most recent event of the timeline. - */ - private RoomState mState = new RoomState(); - - /** - * The historical state of the room when paginating back. - */ - private RoomState mBackState = new RoomState(); - /** * The associated room. */ @@ -141,12 +131,10 @@ public class EventTimeline implements IEventTimeline { */ private final String mTimelineId = System.currentTimeMillis() + ""; - // Allows to store event and roomSummary - private final TimelineEventSaver mTimelineEventSaver = new TimelineEventSaver(this); - - private final StateEventRedactionChecker mStateEventRedactionChecker = new StateEventRedactionChecker(this); - + private TimelineEventSaver mTimelineEventSaver; + private StateEventRedactionChecker mStateEventRedactionChecker; private TimelinePushWorker mTimelinePushWorker; + private TimelineStateHolder mStateHolder; /** * Constructor from room. @@ -179,16 +167,15 @@ public EventTimeline(MXDataHandler dataHandler, String roomId) { public EventTimeline(MXDataHandler dataHandler, String roomId, String eventId) { mInitialEventId = eventId; mDataHandler = dataHandler; - mStore = new MXMemoryStore(dataHandler.getCredentials(), null); mRoom = mDataHandler.getRoom(mStore, roomId, true); mRoom.setLiveTimeline(this); mRoom.setReadyState(true); - setRoomId(roomId); - - mState.setDataHandler(dataHandler); - mBackState.setDataHandler(dataHandler); mTimelinePushWorker = new TimelinePushWorker(mDataHandler); + mStateHolder = new TimelineStateHolder(mDataHandler, mStore); + mStateEventRedactionChecker = new StateEventRedactionChecker(this, mStateHolder); + mTimelineEventSaver = new TimelineEventSaver(this, mStateHolder); + setRoomId(roomId); } /** @@ -264,8 +251,7 @@ public boolean hasReachedHomeServerForwardsPaginationEnd() { */ public void setRoomId(String roomId) { mRoomId = roomId; - mState.roomId = roomId; - mBackState.roomId = roomId; + mStateHolder.setRoomId(roomId); } /** @@ -277,9 +263,10 @@ public void setRoomId(String roomId) { public void setDataHandler(IMXStore store, MXDataHandler dataHandler) { mStore = store; mDataHandler = dataHandler; - mState.setDataHandler(dataHandler); - mBackState.setDataHandler(dataHandler); mTimelinePushWorker = new TimelinePushWorker(mDataHandler); + mStateHolder = new TimelineStateHolder(mDataHandler, mStore); + mStateEventRedactionChecker = new StateEventRedactionChecker(this, mStateHolder); + mTimelineEventSaver = new TimelineEventSaver(this, mStateHolder); } /** @@ -288,7 +275,8 @@ public void setDataHandler(IMXStore store, MXDataHandler dataHandler) { */ @Override public void initHistory() { - mBackState = mState.deepCopy(); + final RoomState backState = getState().deepCopy(); + setBackState(backState); mCanBackPaginate = true; mIsBackPaginating = false; @@ -304,9 +292,8 @@ public void initHistory() { /** * @return The state of the room at the top most recent event of the timeline. */ - @Override public RoomState getState() { - return mState; + return mStateHolder.getState(); } /** @@ -314,9 +301,8 @@ public RoomState getState() { * * @param state the new state. */ - @Override public void setState(RoomState state) { - mState = state; + mStateHolder.setState(state); } /** @@ -324,17 +310,15 @@ public void setState(RoomState state) { * * @param state the new backState. */ - @Override - public void setBackState(RoomState state) { - mBackState = state; + private void setBackState(RoomState state) { + mStateHolder.setBackState(state); } /** * @return the backState. */ - @Override - public RoomState getBackState() { - return mBackState; + private RoomState getBackState() { + return mStateHolder.getBackState(); } /** @@ -353,11 +337,7 @@ public void setCanBackPaginate(final boolean canBackPaginate) { * @param direction the room state direction to deep copy. */ public void deepCopyState(Direction direction) { - if (direction == Direction.FORWARDS) { - mState = mState.deepCopy(); - } else { - mBackState = mBackState.deepCopy(); - } + mStateHolder.deepCopyState(direction); } /** @@ -367,16 +347,8 @@ public void deepCopyState(Direction direction) { * @param direction the direction; ie. forwards for live state, backwards for back state * @return true if the event has been processed. */ - @Override - public boolean processStateEvent(Event event, Direction direction) { - RoomState affectedState = (direction == Direction.FORWARDS) ? mState : mBackState; - boolean isProcessed = affectedState.applyState(getStore(), event, direction); - - if ((isProcessed) && (direction == Direction.FORWARDS)) { - mStore.storeLiveStateForRoom(mRoomId); - } - - return isProcessed; + private boolean processStateEvent(Event event, Direction direction) { + return mStateHolder.processStateEvent(event, direction); } /** @@ -396,10 +368,23 @@ public void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync) { * @param isGlobalInitialSync true if the sync has been triggered by a global initial sync */ public void handleJoinedRoomSync(@NonNull final RoomSync roomSync, final boolean isGlobalInitialSync) { - final TimelineJoinRoomSyncHandler joinRoomSyncHandler = new TimelineJoinRoomSyncHandler(this, roomSync, isGlobalInitialSync); + final TimelineJoinRoomSyncHandler joinRoomSyncHandler = new TimelineJoinRoomSyncHandler(this, roomSync, mStateHolder, isGlobalInitialSync); joinRoomSyncHandler.handle(); } + /** + * Handle events coming down from the event stream. + * + * @param event the live event + * @param checkRedactedStateEvent set to true to check if it triggers a state event redaction + * @param withPush set to true to trigger pushes when it is required + */ + @Override + public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolean withPush) { + final TimelineLiveEventHandler liveEventHandler = new TimelineLiveEventHandler(this, mTimelineEventSaver, mStateEventRedactionChecker, mTimelinePushWorker, mStateHolder); + liveEventHandler.handleLiveEvent(event, checkRedactedStateEvent, withPush); + } + /** * Store an outgoing event. * @@ -420,21 +405,6 @@ private void storeEvent(Event event) { mTimelineEventSaver.storeEvent(event); } - - /** - * Handle events coming down from the event stream. - * - * @param event the live event - * @param checkRedactedStateEvent set to true to check if it triggers a state event redaction - * @param withPush set to true to trigger pushes when it is required - */ - @Override - public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolean withPush) { - final TimelineLiveEventHandler liveEventHandler = new TimelineLiveEventHandler(this, mTimelineEventSaver, mStateEventRedactionChecker, mTimelinePushWorker); - liveEventHandler.handleLiveEvent(event, checkRedactedStateEvent, withPush); - } - - //================================================================================ // History request //================================================================================ @@ -493,7 +463,7 @@ private void manageBackEvents(int maxEventCount, final ApiCallback call RoomSummary summary = mStore.getSummary(mRoomId); if ((null != latestSupportedEvent) && ((null == summary) || !RoomSummary.isSupportedEvent(summary.getLatestReceivedEvent()))) { - mStore.storeSummary(new RoomSummary(null, latestSupportedEvent, mState, mDataHandler.getUserId())); + mStore.storeSummary(new RoomSummary(null, latestSupportedEvent, getState(), mDataHandler.getUserId())); } Log.d(LOG_TAG, "manageEvents : commit"); @@ -639,7 +609,7 @@ public boolean canBackPaginate() { // One at a time please return !mIsBackPaginating // history_visibility flag management - && mState.canBackPaginate(mRoom.isJoined(), mRoom.isInvited()) + && getState().canBackPaginate(mRoom.isJoined(), mRoom.isInvited()) // If we have already reached the end of history && mCanBackPaginate // If the room is not finished being set up @@ -967,7 +937,7 @@ protected void onPostExecute(Void args) { } // init the tokens - mBackState.setToken(eventContext.start); + getBackState().setToken(eventContext.start); mForwardsPaginationToken = eventContext.end; // send the back events to complete pagination @@ -1056,7 +1026,7 @@ public void removeEventTimelineListener(EventTimelineListener listener) { * * @param event the event. * @param direction the direction. - * @param roomState the roomState. + * @param roomState the roogetState(). */ @Override public void onEvent(final Event event, final Direction direction, final RoomState roomState) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java index 0a9d8baa0..04f6d80c8 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java @@ -19,7 +19,6 @@ import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.data.store.IMXStore; -import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.model.Event; interface IEventTimeline { @@ -37,18 +36,6 @@ interface IEventTimeline { String getTimelineId(); - RoomState getState(); - - void setState(RoomState state); - - void setBackState(RoomState state); - - RoomState getBackState(); - - void deepCopyState(Direction direction); - - boolean processStateEvent(Event event, Direction direction); - void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolean withPush); boolean canBackPaginate(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java index 60c935690..2d93accb2 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java @@ -16,6 +16,7 @@ package org.matrix.androidsdk.data.timeline; +import android.support.annotation.NonNull; import android.text.TextUtils; import org.matrix.androidsdk.MXDataHandler; @@ -38,9 +39,11 @@ class StateEventRedactionChecker { private static final String LOG_TAG = StateEventRedactionChecker.class.getSimpleName(); private final IEventTimeline mEventTimeline; + private final TimelineStateHolder mTimelineStateHolder; - StateEventRedactionChecker(IEventTimeline eventTimeline) { + StateEventRedactionChecker(@NonNull final IEventTimeline eventTimeline, @NonNull final TimelineStateHolder timelineStateHolder) { mEventTimeline = eventTimeline; + mTimelineStateHolder = timelineStateHolder; } /** @@ -55,7 +58,7 @@ public void checkStateEventRedaction(final Event redactionEvent) { final MXDataHandler dataHandler = room.getDataHandler(); final String roomId = room.getRoomId(); final String eventId = redactionEvent.getRedacts(); - final RoomState state = mEventTimeline.getState(); + final RoomState state = mTimelineStateHolder.getState(); Log.d(LOG_TAG, "checkStateEventRedaction of event " + eventId); // check if the state events is locally known state.getStateEvents(store, null, new SimpleApiCallback>() { @@ -75,7 +78,7 @@ public void onSuccess(List stateEvents) { stateEvent.prune(redactionEvent); stateEvents.set(index, stateEvent); // digest the updated state - mEventTimeline.processStateEvent(stateEvent, IEventTimeline.Direction.FORWARDS); + mTimelineStateHolder.processStateEvent(stateEvent, IEventTimeline.Direction.FORWARDS); isFound = true; break; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java index 414bf8f52..22caa0107 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java @@ -16,6 +16,8 @@ package org.matrix.androidsdk.data.timeline; +import android.support.annotation.NonNull; + import org.matrix.androidsdk.MXDataHandler; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; @@ -27,9 +29,11 @@ class TimelineEventSaver { private final IEventTimeline mEventTimeline; + private final TimelineStateHolder mTimelineStateHolder; - TimelineEventSaver(IEventTimeline mEventTimeline) { - this.mEventTimeline = mEventTimeline; + TimelineEventSaver(@NonNull final IEventTimeline eventTimeline, @NonNull final TimelineStateHolder timelineStateHolder) { + mEventTimeline = eventTimeline; + mTimelineStateHolder = timelineStateHolder; } /** @@ -51,14 +55,13 @@ public void storeEvent(Event event) { } store.storeLiveRoomEvent(event); if (RoomSummary.isSupportedEvent(event)) { - final RoomState roomState = mEventTimeline.getState(); + final RoomState roomState = mTimelineStateHolder.getState(); RoomSummary summary = store.getSummary(event.roomId); if (null == summary) { summary = new RoomSummary(summary, event, roomState, myUserId); } else { summary.setLatestReceivedEvent(event, roomState); } - store.storeSummary(summary); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java index 5727610a7..8584be2d3 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java @@ -27,13 +27,16 @@ class TimelineJoinRoomSyncHandler { private final IEventTimeline mEventTimeline; private final RoomSync mRoomSync; + private final TimelineStateHolder mTimelineStateHolder; private final boolean mIsGlobalInitialSync; TimelineJoinRoomSyncHandler(@NonNull final IEventTimeline eventTimeline, @NonNull final RoomSync roomSync, + @NonNull final TimelineStateHolder timelineStateHolder, final boolean isGlobalInitialSync) { mEventTimeline = eventTimeline; mRoomSync = roomSync; + mTimelineStateHolder = timelineStateHolder; mIsGlobalInitialSync = isGlobalInitialSync; } @@ -44,7 +47,7 @@ public void handle() { final MXDataHandler dataHandler = room.getDataHandler(); final String roomId = room.getRoomId(); final String myUserId = dataHandler.getMyUser().user_id; - final RoomMember selfMember = mEventTimeline.getState().getMember(myUserId); + final RoomMember selfMember = mTimelineStateHolder.getState().getMember(myUserId); final RoomSummary currentSummary = store.getSummary(roomId); final String membership = selfMember != null ? selfMember.membership : null; @@ -53,7 +56,7 @@ public void handle() { // Check whether the room was pending on an invitation. if (RoomMember.MEMBERSHIP_INVITE.equals(membership)) { // Reset the storage of this room. An initial sync of the room will be done with the provided 'roomSync'. - cleanInvitedRoom(dataHandler, store, roomId); + cleanInvitedRoom(store, roomId); } if ((mRoomSync.state != null) && (mRoomSync.state.events != null) && (mRoomSync.state.events.size() > 0)) { handleRoomSyncState(room, store, isRoomInitialSync); @@ -90,7 +93,7 @@ private void handleRoomSyncState(@NonNull final Room room, @NonNull final IMXSto if (room.getDataHandler().isAlive()) { for (Event event : mRoomSync.state.events) { try { - mEventTimeline.processStateEvent(event, EventTimeline.Direction.FORWARDS); + mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.FORWARDS); } catch (Exception e) { Log.e(LOG_TAG, "processStateEvent failed " + e.getMessage(), e); } @@ -103,23 +106,17 @@ private void handleRoomSyncState(@NonNull final Room room, @NonNull final IMXSto // if it is an initial sync, the live state is initialized here // so the back state must also be initialized if (isRoomInitialSync) { - final RoomState state = mEventTimeline.getState(); + final RoomState state = mTimelineStateHolder.getState(); Log.d(LOG_TAG, "## handleJoinedRoomSync() : retrieve X " + state.getLoadedMembers().size() + " members for room " + room.getRoomId()); - mEventTimeline.setBackState(state.deepCopy()); + mTimelineStateHolder.setBackState(state.deepCopy()); } } - private void cleanInvitedRoom(@NonNull final MXDataHandler dataHandler, - @NonNull final IMXStore store, + private void cleanInvitedRoom(@NonNull final IMXStore store, @NonNull final String roomId) { Log.d(LOG_TAG, "clean invited room from the store " + roomId); store.deleteRoomData(roomId); - // clear the states - final RoomState state = new RoomState(); - state.roomId = roomId; - state.setDataHandler(dataHandler); - mEventTimeline.setBackState(state); - mEventTimeline.setState(state); + mTimelineStateHolder.clear(); } private void handleRoomSyncTimeline(@NonNull final IMXStore store, @@ -129,7 +126,7 @@ private void handleRoomSyncTimeline(@NonNull final IMXStore store, final boolean isRoomInitialSync) { if (mRoomSync.timeline.limited) { if (!isRoomInitialSync) { - final RoomState state = mEventTimeline.getState(); + final RoomState state = mTimelineStateHolder.getState(); // There is a gap between known events and received events in this incremental sync. // define a summary if some messages are left // the unsent messages are often displayed messages. @@ -161,7 +158,7 @@ private void handleRoomSyncTimeline(@NonNull final IMXStore store, // reset the state back token // because it does not make anymore sense // by setting at null, the events cache will be cleared when a requesthistory will be called - mEventTimeline.getBackState().setToken(null); + mTimelineStateHolder.getBackState().setToken(null); // reset the back paginate lock mEventTimeline.setCanBackPaginate(true); } @@ -195,7 +192,7 @@ private void handleLiveTimeline(@NonNull final MXDataHandler dataHandler, @NonNull final String roomId, @NonNull final String myUserId, @Nullable final RoomSummary currentSummary) { - final RoomState state = mEventTimeline.getState(); + final RoomState state = mTimelineStateHolder.getState(); // check if the summary is defined // after a sync, the room summary might not be defined because the latest message did not generate a room summary/ if (null != store.getRoom(roomId)) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java index f65481be2..0d76ab8c4 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java @@ -16,6 +16,7 @@ package org.matrix.androidsdk.data.timeline; +import android.support.annotation.NonNull; import android.text.TextUtils; import org.matrix.androidsdk.MXDataHandler; @@ -44,15 +45,18 @@ class TimelineLiveEventHandler { private final TimelineEventSaver mTimelineEventSaver; private final StateEventRedactionChecker mStateEventRedactionChecker; private final TimelinePushWorker mTimelinePushWorker; + private final TimelineStateHolder mTimelineStateHolder; TimelineLiveEventHandler(@Nonnull final IEventTimeline eventTimeline, @Nonnull final TimelineEventSaver timelineEventSaver, @Nonnull final StateEventRedactionChecker stateEventRedactionChecker, - @Nonnull final TimelinePushWorker timelinePushWorker) { + @Nonnull final TimelinePushWorker timelinePushWorker, + @NonNull final TimelineStateHolder timelineStateHolder) { mEventTimeline = eventTimeline; mTimelineEventSaver = timelineEventSaver; mStateEventRedactionChecker = stateEventRedactionChecker; mTimelinePushWorker = timelinePushWorker; + mTimelineStateHolder = timelineStateHolder; } /** @@ -74,7 +78,7 @@ public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolea // dispatch the call events to the calls manager if (event.isCallEvent()) { - final RoomState roomState = mEventTimeline.getState(); + final RoomState roomState = mTimelineStateHolder.getState(); dataHandler.getCallsManager().handleCallEvent(store, event); storeLiveRoomEvent(dataHandler, store, false, event); // the candidates events are not tracked @@ -150,12 +154,12 @@ public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolea } } - final RoomState previousState = mEventTimeline.getState(); + final RoomState previousState = mTimelineStateHolder.getState(); if (event.stateKey != null) { // copy the live state before applying any update - mEventTimeline.deepCopyState(IEventTimeline.Direction.FORWARDS); + mTimelineStateHolder.deepCopyState(IEventTimeline.Direction.FORWARDS); // check if the event has been processed - if (!mEventTimeline.processStateEvent(event, IEventTimeline.Direction.FORWARDS)) { + if (!mTimelineStateHolder.processStateEvent(event, IEventTimeline.Direction.FORWARDS)) { // not processed -> do not warn the application // assume that the event is a duplicated one. return; @@ -172,7 +176,7 @@ public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolea // trigger pushes when it is required if (withPush) { - mTimelinePushWorker.triggerPush(mEventTimeline.getState(), event); + mTimelinePushWorker.triggerPush(mTimelineStateHolder.getState(), event); } } else { Log.e(LOG_TAG, "Unknown live event type: " + event.getType()); @@ -225,7 +229,7 @@ private void storeLiveRoomEvent(final MXDataHandler dataHandler, dataHandler.decryptEvent(indexedEvent, mEventTimeline.getTimelineId()); } } - final RoomState state = mEventTimeline.getState(); + final RoomState state = mTimelineStateHolder.getState(); final EventDisplay eventDisplay = new EventDisplay(store.getContext(), indexedEvent, state); // ensure that message can be displayed if (!TextUtils.isEmpty(eventDisplay.getTextualDisplay())) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java index 35132d7b6..d449e8dc7 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java @@ -28,14 +28,14 @@ import javax.annotation.Nonnull; -public class TimelinePushWorker { +class TimelinePushWorker { private static final String LOG_TAG = TimelinePushWorker.class.getSimpleName(); @Nonnull private final MXDataHandler mDataHandler; - public TimelinePushWorker(@Nonnull final MXDataHandler dataHandler) { + TimelinePushWorker(@Nonnull final MXDataHandler dataHandler) { mDataHandler = dataHandler; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java new file mode 100644 index 000000000..9314c21f9 --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java @@ -0,0 +1,139 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.data.timeline; + +import android.support.annotation.NonNull; + +import org.matrix.androidsdk.MXDataHandler; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.data.store.IMXStore; +import org.matrix.androidsdk.rest.model.Event; + +/** + * This class is responsible for holding the state and backState of a room timeline + */ +class TimelineStateHolder { + + private final MXDataHandler mDataHandler; + private final IMXStore mStore; + private String mRoomId; + + /** + * The state of the room at the top most recent event of the timeline. + */ + private RoomState mState; + + /** + * The historical state of the room when paginating back. + */ + private RoomState mBackState; + + TimelineStateHolder(@NonNull final MXDataHandler dataHandler, @NonNull final IMXStore store) { + mDataHandler = dataHandler; + mStore = store; + initStates(); + } + + public void clear() { + initStates(); + mBackState.roomId = mRoomId; + mState.roomId = mRoomId; + } + + /** + * @return The state of the room at the top most recent event of the timeline. + */ + @NonNull + public RoomState getState() { + return mState; + } + + /** + * Update the state. + * + * @param state the new state. + */ + public void setState(@NonNull final RoomState state) { + mState = state; + } + + /** + * @return the backState. + */ + @NonNull + public RoomState getBackState() { + return mBackState; + } + + /** + * Update the backState. + * + * @param state the new backState. + */ + public void setBackState(@NonNull final RoomState state) { + mBackState = state; + } + + /** + * Make a deep copy or the dedicated state. + * + * @param direction the room state direction to deep copy. + */ + public void deepCopyState(final IEventTimeline.Direction direction) { + if (direction == IEventTimeline.Direction.FORWARDS) { + mState = mState.deepCopy(); + } else { + mBackState = mBackState.deepCopy(); + } + } + + /** + * Process a state event to keep the internal live and back states up to date. + * + * @param event the state event + * @param direction the direction; ie. forwards for live state, backwards for back state + * @return true if the event has been processed. + */ + public boolean processStateEvent(@NonNull final Event event, final IEventTimeline.Direction direction) { + final RoomState affectedState = (direction == IEventTimeline.Direction.FORWARDS) ? mState : mBackState; + boolean isProcessed = affectedState.applyState(mStore, event, direction); + if (isProcessed && direction == IEventTimeline.Direction.FORWARDS) { + mStore.storeLiveStateForRoom(mRoomId); + } + return isProcessed; + } + + /** + * Set the room Id + * + * @param roomId the new room id. + */ + public void setRoomId(@NonNull final String roomId) { + mRoomId = roomId; + mState.roomId = roomId; + mBackState.roomId = roomId; + } + + private void initStates() { + mBackState = new RoomState(); + mBackState.setDataHandler(mDataHandler); + mState = new RoomState(); + mState.setDataHandler(mDataHandler); + } + + +} From 67a3133f00ece16ecaa7960c4eabee0b2cacb91f Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 25 Sep 2018 19:14:58 +0200 Subject: [PATCH 201/236] TimelineEvent : add a factory --- .../matrix/androidsdk/crypto/CryptoTest.java | 33 +++++----- .../androidsdk/lazyloading/RoomStateTest.java | 13 ++-- .../org/matrix/androidsdk/MXDataHandler.java | 4 +- .../java/org/matrix/androidsdk/data/Room.java | 35 ++++------ .../androidsdk/data/store/MXFileStore.java | 2 +- .../data/timeline/EventTimeline.java | 64 ++++--------------- .../data/timeline/EventTimelineFactory.java | 52 +++++++++++++++ .../data/timeline/TimelinePushWorker.java | 11 ++-- .../fragments/MatrixMessageListFragment.java | 9 +-- 9 files changed, 114 insertions(+), 109 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 5e5bf4092..a8bb619e1 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -51,6 +51,7 @@ import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.data.store.MXFileStore; import org.matrix.androidsdk.data.store.MXStoreListener; +import org.matrix.androidsdk.data.timeline.EventTimelineFactory; import org.matrix.androidsdk.listeners.MXEventListener; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.callback.SimpleApiCallback; @@ -1131,9 +1132,9 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } }; - roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); + roomFromBobPOV.getTimeline().addEventTimelineListener(eventTimelineListener); - roomFromBobPOV.getLiveTimeLine().backPaginate(new TestApiCallback(lock2) { + roomFromBobPOV.getTimeline().backPaginate(new TestApiCallback(lock2) { @Override public void onSuccess(Integer info) { results.put("backPaginate", "backPaginate"); @@ -1173,7 +1174,7 @@ public void test12_testAliceAndBobInAEncryptedRoomBackPaginationFromHomeServer() String eventId = bobSession.getDataHandler().getStore().getLatestEvent(aliceRoomId).eventId; - EventTimeline timeline = new EventTimeline(bobSession.getDataHandler(), aliceRoomId, eventId); + EventTimeline timeline = EventTimelineFactory.pastTimeline(bobSession.getDataHandler(), aliceRoomId, eventId); final CountDownLatch lock2 = new CountDownLatch(6); final List receivedEvents = new ArrayList<>(); @@ -1530,7 +1531,7 @@ public void onLiveEvent(Event event, RoomState roomState) { event.setClearData(null); - bobSession.getDataHandler().decryptEvent(event, roomFromBobPOV.getLiveTimeLine().getTimelineId()); + bobSession.getDataHandler().decryptEvent(event, roomFromBobPOV.getTimeline().getTimelineId()); results.put("decrypted", event); lock1.countDown(); @@ -1616,7 +1617,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } }; - roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); + roomFromBobPOV.getTimeline().addEventTimelineListener(eventTimelineListener); roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback() { @Override @@ -1697,7 +1698,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } }; - roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); + roomFromBobPOV.getTimeline().addEventTimelineListener(eventTimelineListener); roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback() { @Override @@ -1800,7 +1801,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } }; - roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); + roomFromBobPOV.getTimeline().addEventTimelineListener(eventTimelineListener); String aliceMessage1 = "Hello I'm Alice!"; @@ -1874,7 +1875,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } }; - roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener4); + roomFromBobPOV2.getTimeline().addEventTimelineListener(eventTimelineListener4); String aliceMessage2 = "Hello I'm still Alice!"; roomFromAlicePOV.sendEvent(buildTextEvent(aliceMessage2, aliceSession, aliceRoomId), new SimpleApiCallback() { @@ -1937,7 +1938,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } }; - roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); + roomFromBobPOV.getTimeline().addEventTimelineListener(eventTimelineListener); String aliceMessage1 = "Hello I'm Alice!"; @@ -2007,7 +2008,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } } }; - roomFromBob2POV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); + roomFromBob2POV.getTimeline().addEventTimelineListener(eventTimelineListener2); String messageFromAlice2 = "Hello I'm still Alice!"; roomFromAlice2POV.sendEvent(buildTextEvent(messageFromAlice2, aliceSession2, aliceRoomId), new SimpleApiCallback() { @@ -2055,7 +2056,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } }; - roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); + roomFromBobPOV.getTimeline().addEventTimelineListener(eventTimelineListener); String aliceMessage1 = "Hello I'm Alice!"; @@ -2099,7 +2100,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } }; - roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); + roomFromBobPOV.getTimeline().addEventTimelineListener(eventTimelineListener2); String aliceMessage2 = "Hello I'm still Alice!"; @@ -2144,7 +2145,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } }; - roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener3); + roomFromBobPOV.getTimeline().addEventTimelineListener(eventTimelineListener3); String aliceMessage3 = "Hello I'm still Alice and you can read this!"; @@ -2587,7 +2588,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } }; - roomFromBobPOV.getLiveTimeLine().addEventTimelineListener(eventTimelineListener); + roomFromBobPOV.getTimeline().addEventTimelineListener(eventTimelineListener); roomFromAlicePOV.sendEvent(buildTextEvent(messageFromAlice, aliceSession, aliceRoomId), new SimpleApiCallback() { @Override public void onSuccess(Void info) { @@ -2646,7 +2647,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } }; - roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); + roomFromBobPOV2.getTimeline().addEventTimelineListener(eventTimelineListener2); roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, aliceSession, aliceRoomId), new SimpleApiCallback() { @Override public void onSuccess(Void info) { @@ -3085,7 +3086,7 @@ public void onEvent(Event event, EventTimeline.Direction direction, RoomState ro } }; - roomFromBobPOV2.getLiveTimeLine().addEventTimelineListener(eventTimelineListener2); + roomFromBobPOV2.getTimeline().addEventTimelineListener(eventTimelineListener2); roomFromAlicePOV.sendEvent(buildTextEvent(message2FromAlice, aliceSession, aliceRoomId), new SimpleApiCallback() { @Override public void onSuccess(Void info) { diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index 6e62ef6c4..0d6e32911 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -25,9 +25,10 @@ import org.junit.runners.MethodSorters; import org.matrix.androidsdk.RestClient; import org.matrix.androidsdk.common.CommonTestHelper; -import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.data.timeline.EventTimeline; +import org.matrix.androidsdk.data.timeline.EventTimelineFactory; import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.util.JsonUtils; @@ -87,7 +88,7 @@ private void RoomState_IncomingMessage(final boolean withLazyLoading) throws Exc mTestHelper.syncSession(data.samSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); final CountDownLatch lock = new CountDownLatch(1); - aliceRoom.getLiveTimeLine().addEventTimelineListener(new EventTimeline.EventTimelineListener() { + aliceRoom.getTimeline().addEventTimelineListener(new EventTimeline.EventTimelineListener() { @Override public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { lock.countDown(); @@ -123,7 +124,7 @@ private void RoomState_BackPaginate(final boolean withLazyLoading) throws Except mTestHelper.syncSession(data.aliceSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); final CountDownLatch lock = new CountDownLatch(1); - final EventTimeline liveTimeline = aliceRoom.getLiveTimeLine(); + final EventTimeline liveTimeline = aliceRoom.getTimeline(); liveTimeline.addEventTimelineListener(new EventTimeline.EventTimelineListener() { int messageCount = 0; @@ -181,7 +182,7 @@ private void RoomState_Permalink(final boolean withLazyLoading) throws Exception mTestHelper.syncSession(data.aliceSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); final Event lastEvent = aliceRoom.getDataHandler().getStore().getLatestEvent(data.roomId); - final EventTimeline eventTimeline = new EventTimeline(data.aliceSession.getDataHandler(), lastEvent.roomId, lastEvent.eventId); + final EventTimeline eventTimeline = EventTimelineFactory.pastTimeline(data.aliceSession.getDataHandler(), lastEvent.roomId, lastEvent.eventId); final CountDownLatch lock = new CountDownLatch(1); eventTimeline.resetPaginationAroundInitialEvent(10, new SimpleApiCallback() { @Override @@ -221,7 +222,7 @@ private void RoomState_PermalinkWithBackPagination(final boolean withLazyLoading final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); mTestHelper.syncSession(data.aliceSession, false); final CountDownLatch lock = new CountDownLatch(1); - final EventTimeline eventTimeline = new EventTimeline(data.aliceSession.getDataHandler(), data.roomId, data.bobMessageId); + final EventTimeline eventTimeline = EventTimelineFactory.pastTimeline(data.aliceSession.getDataHandler(), data.roomId, data.bobMessageId); eventTimeline.addEventTimelineListener(new EventTimeline.EventTimelineListener() { int messageCount = 0; @@ -286,7 +287,7 @@ private void RoomState_PermalinkWithForwardPagination(final boolean withLazyLoad final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); mTestHelper.syncSession(data.aliceSession, false); final CountDownLatch lock = new CountDownLatch(1); - final EventTimeline eventTimeline = new EventTimeline(data.aliceSession.getDataHandler(), data.roomId, data.bobMessageId); + final EventTimeline eventTimeline = EventTimelineFactory.pastTimeline(data.aliceSession.getDataHandler(), data.roomId, data.bobMessageId); eventTimeline.addEventTimelineListener(new EventTimeline.EventTimelineListener() { int messageCount = 0; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 756b6e57d..72c40e7bb 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -863,7 +863,7 @@ public void checkRoom(Room room) { if (null == room.getDataHandler()) { Log.e(LOG_TAG, "checkRoom : the room was not initialized"); room.init(mStore, room.getRoomId(), this); - } else if ((null != room.getLiveTimeLine()) && (null == room.getLiveTimeLine().mDataHandler)) { + } else if ((null != room.getTimeline()) && (null == room.getTimeline().mDataHandler)) { Log.e(LOG_TAG, "checkRoom : the timeline was not initialized"); room.init(mStore, room.getRoomId(), this); } @@ -1332,7 +1332,7 @@ public void deleteRoom(String roomId) { } // copy the state - leftRoom.getLiveTimeLine().setState(r.getLiveTimeLine().getState()); + leftRoom.getTimeline().setState(r.getTimeline().getState()); } // remove the previous definition diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 5795e9256..12df1f826 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -45,6 +45,7 @@ import org.matrix.androidsdk.crypto.data.MXEncryptEventContentResult; import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.data.timeline.EventTimeline; +import org.matrix.androidsdk.data.timeline.EventTimelineFactory; import org.matrix.androidsdk.db.MXMediasCache; import org.matrix.androidsdk.listeners.IMXEventListener; import org.matrix.androidsdk.listeners.MXEventListener; @@ -121,7 +122,7 @@ public class Room { private boolean mRefreshUnreadAfterSync = false; // the time line - private EventTimeline mLiveTimeline; + private EventTimeline mTimeline; // initial sync callback. private ApiCallback mOnInitialSyncCallback; @@ -135,13 +136,6 @@ public class Room { // true when the current room is a left one private boolean mIsLeft; - /** - * Default room creator - */ - public Room() { - mLiveTimeline = new EventTimeline(this, true); - } - /** * Init the room fields. * @@ -152,11 +146,10 @@ public Room() { public void init(IMXStore store, String roomId, MXDataHandler dataHandler) { mDataHandler = dataHandler; mStore = store; - if (null != mDataHandler) { + if (mDataHandler != null) { mMyUserId = mDataHandler.getUserId(); - mLiveTimeline.setDataHandler(mStore, dataHandler); } - mLiveTimeline.setRoomId(roomId); + mTimeline = EventTimelineFactory.liveTimeline(mStore, mDataHandler, this, roomId); } /** @@ -232,7 +225,7 @@ public boolean isOngoingConferenceCall() { */ public void setIsLeft(boolean isLeft) { mIsLeft = isLeft; - mLiveTimeline.setIsHistorical(isLeft); + mTimeline.setIsHistorical(isLeft); } /** @@ -312,7 +305,7 @@ public void handleJoinedRoomSync(RoomSync roomSync, boolean isGlobalInitialSync) mIsSyncing = true; synchronized (this) { - mLiveTimeline.handleJoinedRoomSync(roomSync, isGlobalInitialSync); + mTimeline.handleJoinedRoomSync(roomSync, isGlobalInitialSync); RoomSummary roomSummary = getRoomSummary(); if (roomSummary != null) { roomSummary.setIsJoined(); @@ -371,7 +364,7 @@ public void run() { * @param invitedRoomSync the invitation room events. */ public void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync) { - mLiveTimeline.handleInvitedRoomSync(invitedRoomSync); + mTimeline.handleInvitedRoomSync(invitedRoomSync); RoomSummary roomSummary = getRoomSummary(); @@ -386,7 +379,7 @@ public void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync) { * @param event the event. */ public void storeOutgoingEvent(Event event) { - mLiveTimeline.storeOutgoingEvent(event); + mTimeline.storeOutgoingEvent(event); } /** @@ -422,7 +415,7 @@ public void cancelRemoteHistoryRequest() { //================================================================================ public String getRoomId() { - return mLiveTimeline.getState().roomId; + return mTimeline.getState().roomId; } public void setAccountData(RoomAccountData accountData) { @@ -434,7 +427,7 @@ public RoomAccountData getAccountData() { } public RoomState getState() { - return mLiveTimeline.getState(); + return mTimeline.getState(); } public boolean isLeaving() { @@ -449,12 +442,12 @@ public void getDisplayableMembersAsync(@NonNull final ApiCallback Date: Wed, 26 Sep 2018 16:37:09 +0200 Subject: [PATCH 202/236] EventTimeline : fix creation within room --- .../org/matrix/androidsdk/MXDataHandler.java | 34 +---------------- .../java/org/matrix/androidsdk/data/Room.java | 19 +++------- .../androidsdk/data/store/MXFileStore.java | 5 +-- .../androidsdk/data/store/MXMemoryStore.java | 24 +++++++++++- .../data/timeline/EventTimelineFactory.java | 37 +++++++++++++++---- .../fragments/MatrixMessageListFragment.java | 5 --- .../fragments/MatrixMessagesFragment.java | 7 +--- 7 files changed, 62 insertions(+), 69 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 72c40e7bb..83a559871 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -33,7 +33,6 @@ import org.matrix.androidsdk.crypto.MXDecryptionException; import org.matrix.androidsdk.crypto.MXEventDecryptionResult; import org.matrix.androidsdk.data.DataRetriever; -import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.MyUser; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; @@ -41,6 +40,7 @@ import org.matrix.androidsdk.data.metrics.MetricsListener; import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.data.store.MXMemoryStore; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.db.MXMediasCache; import org.matrix.androidsdk.groups.GroupsManager; import org.matrix.androidsdk.listeners.IMXEventListener; @@ -193,7 +193,6 @@ public MXDataHandler(IMXStore store, Credentials credentials) { mSyncHandlerThread = new HandlerThread("MXDataHandler" + mCredentials.userId, Thread.MIN_PRIORITY); mSyncHandlerThread.start(); mSyncHandler = new MXOsHandler(mSyncHandlerThread.getLooper()); - mLeftRoomsStore = new MXMemoryStore(credentials, store.getContext()); } @@ -673,13 +672,6 @@ void checkPermanentStorageData() { // some fields are not retrieved : // They are used to retrieve some data // so add the missing links. - - Collection rooms = mStore.getRooms(); - - for (Room room : rooms) { - room.init(mStore, room.getRoomId(), this); - } - Collection summaries = mStore.getSummaries(); for (RoomSummary summary : summaries) { if (null != summary.getLatestRoomState()) { @@ -835,14 +827,12 @@ public Room getRoom(IMXStore store, String roomId, boolean create) { room = store.getRoom(roomId); if ((room == null) && create) { Log.d(LOG_TAG, "## getRoom() : create the room " + roomId); - room = new Room(); - room.init(store, roomId, this); + room = new Room(this, roomId); store.storeRoom(room); } else if ((null != room) && (null == room.getDataHandler())) { // GA reports that some rooms have no data handler // so ensure that it is not properly set Log.e(LOG_TAG, "getRoom " + roomId + " was not initialized"); - room.init(store, roomId, this); store.storeRoom(room); } } @@ -850,26 +840,6 @@ public Room getRoom(IMXStore store, String roomId, boolean create) { return room; } - /** - * Checks if the room is properly initialized. - * GA reported us that some room fields are not initialized. - * But, i really don't know how it is possible. - * - * @param room the room check - */ - public void checkRoom(Room room) { - // sanity check - if (null != room) { - if (null == room.getDataHandler()) { - Log.e(LOG_TAG, "checkRoom : the room was not initialized"); - room.init(mStore, room.getRoomId(), this); - } else if ((null != room.getTimeline()) && (null == room.getTimeline().mDataHandler)) { - Log.e(LOG_TAG, "checkRoom : the timeline was not initialized"); - room.init(mStore, room.getRoomId(), this); - } - } - } - /** * Provides the room summaries list. * diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 12df1f826..51db5e07a 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -136,24 +136,15 @@ public class Room { // true when the current room is a left one private boolean mIsLeft; - /** - * Init the room fields. - * - * @param store the store. - * @param roomId the room id - * @param dataHandler the data handler - */ - public void init(IMXStore store, String roomId, MXDataHandler dataHandler) { + public Room(@NonNull final MXDataHandler dataHandler, @NonNull final String roomId) { mDataHandler = dataHandler; - mStore = store; - if (mDataHandler != null) { - mMyUserId = mDataHandler.getUserId(); - } - mTimeline = EventTimelineFactory.liveTimeline(mStore, mDataHandler, this, roomId); + mStore = mDataHandler.getStore(roomId); + mMyUserId = mDataHandler.getUserId(); + mTimeline = EventTimelineFactory.liveTimeline(mDataHandler, this, roomId); } /** - * @return the used datahandler + * @return the used data handler */ public MXDataHandler getDataHandler() { return mDataHandler; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java index fe40185fc..5da98d915 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java @@ -24,11 +24,11 @@ import android.text.TextUtils; import org.matrix.androidsdk.HomeServerConnectionConfig; -import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomAccountData; import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.data.RoomSummary; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.ReceiptData; @@ -1239,8 +1239,7 @@ private boolean loadRoomMessages(final String roomId) { // succeeds to extract the message list if (null != events) { // create the room object - Room room = new Room(); - room.init(this, roomId, null); + final Room room = new Room(getDataHandler(), roomId); // do not wait that the live state update room.setReadyState(true); storeRoom(room); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java index 460efe9f5..48fb9626c 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXMemoryStore.java @@ -24,12 +24,13 @@ import android.support.annotation.Nullable; import android.text.TextUtils; -import org.matrix.androidsdk.data.timeline.EventTimeline; +import org.matrix.androidsdk.MXDataHandler; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomAccountData; import org.matrix.androidsdk.data.RoomSummary; import org.matrix.androidsdk.data.comparator.Comparators; import org.matrix.androidsdk.data.metrics.MetricsListener; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.rest.callback.ApiCallback; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.ReceiptData; @@ -106,6 +107,9 @@ public class MXMemoryStore implements IMXStore { protected long mUserDisplayNameTs; protected long mUserAvatarUrlTs; + // DataHandler -- added waiting to be refactored + private MXDataHandler mDataHandler; + /** * Initialization method. */ @@ -1641,4 +1645,22 @@ public String getAntivirusServerPublicKey() { public void setMetricsListener(MetricsListener metricsListener) { mMetricsListener = metricsListener; } + + /** + * Get the associated dataHandler + * + * @return the associated dataHandler + */ + protected MXDataHandler getDataHandler() { + return mDataHandler; + } + + /** + * Update the associated dataHandler + * + * @param dataHandler the dataHandler + */ + public void setDataHandler(final MXDataHandler dataHandler) { + mDataHandler = dataHandler; + } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java index e38423657..0e3fa140f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java @@ -1,3 +1,19 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.data.timeline; import android.support.annotation.NonNull; @@ -5,22 +21,25 @@ import org.matrix.androidsdk.MXDataHandler; import org.matrix.androidsdk.data.Room; -import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.data.store.MXMemoryStore; public class EventTimelineFactory { /** - * Constructor from room. + * Method to create a live timeline associated with the room. * - * @param room the linked room. + * @param dataHandler the dataHandler + * @param room the linked room. + * @param roomId the roomId */ - public static EventTimeline liveTimeline(final IMXStore store, final MXDataHandler dataHandler, final Room room, final String roomId) { - return new EventTimeline(store, dataHandler, room, roomId, null, true); + public static EventTimeline liveTimeline(@NonNull final MXDataHandler dataHandler, + @NonNull final Room room, + @NonNull final String roomId) { + return new EventTimeline(dataHandler.getStore(roomId), dataHandler, room, roomId, null, true); } /** - * Constructor from room and event Id + * Method to create a past timeline. * * @param dataHandler the data handler * @param roomId the room id. @@ -32,10 +51,12 @@ public static EventTimeline pastTimeline( } /** - * Constructor from room and event Id + * Method to create a past timeline around an eventId. + * It will create a memory store and a room * * @param dataHandler the data handler - * @param eventId the event id. + * @param roomId the room id. + * @param eventId the event id */ public static EventTimeline pastTimeline(@NonNull MXDataHandler dataHandler, @NonNull String roomId, diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java index 7d0a92046..81eb0fec1 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java @@ -528,11 +528,6 @@ else if (PREVIEW_MODE_READ_ONLY.equals(previewMode)) { } } } - - // GA reported some weird room content - // so ensure that the room fields are properly initialized - mSession.getDataHandler().checkRoom(mRoom); - mMessageListView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java index 12d29cd4c..239bed0f2 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java @@ -29,10 +29,10 @@ import android.widget.Toast; import org.matrix.androidsdk.MXSession; -import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomPreviewData; import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.listeners.IMXEventListener; import org.matrix.androidsdk.listeners.MXEventListener; import org.matrix.androidsdk.rest.callback.ApiCallback; @@ -214,11 +214,6 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa // check if this room has been joined, if not, join it then get messages. mRoom = mSession.getDataHandler().getRoom(roomId); } - - // GA reported some weird room content - // so ensure that the room fields are properly initialized - mSession.getDataHandler().checkRoom(mRoom); - // display the message history around a dedicated message if ((null != mEventTimeline) && !mEventTimeline.isLiveTimeline() && (null != mEventTimeline.getInitialEventId())) { initializeTimeline(); From d0e2b5bb6be5718f3599813082a5dca94b32e5c1 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 26 Sep 2018 16:51:00 +0200 Subject: [PATCH 203/236] EventTimeline : dispatch events within a dedicated class --- .../data/timeline/EventTimeline.java | 79 ++++--------- .../data/timeline/IEventTimeline.java | 2 - .../data/timeline/TimelineEventListeners.java | 105 ++++++++++++++++++ .../timeline/TimelineLiveEventHandler.java | 9 +- 4 files changed, 132 insertions(+), 63 deletions(-) create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java index a019022bd..4940a913b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java @@ -130,10 +130,11 @@ public class EventTimeline implements IEventTimeline { */ private final String mTimelineId = System.currentTimeMillis() + ""; - private TimelineEventSaver mTimelineEventSaver; - private StateEventRedactionChecker mStateEventRedactionChecker; - private TimelinePushWorker mTimelinePushWorker; - private TimelineStateHolder mStateHolder; + private final TimelineEventSaver mTimelineEventSaver; + private final StateEventRedactionChecker mStateEventRedactionChecker; + private final TimelinePushWorker mTimelinePushWorker; + private final TimelineStateHolder mStateHolder; + private final TimelineEventListeners mEventListeners; /** * Constructor from room and event Id @@ -158,6 +159,7 @@ public class EventTimeline implements IEventTimeline { mStateEventRedactionChecker = new StateEventRedactionChecker(this, mStateHolder); mTimelineEventSaver = new TimelineEventSaver(this, mStateHolder); mStateHolder.setRoomId(mRoomId); + mEventListeners = new TimelineEventListeners(); } /** @@ -326,7 +328,10 @@ public void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync) { * @param isGlobalInitialSync true if the sync has been triggered by a global initial sync */ public void handleJoinedRoomSync(@NonNull final RoomSync roomSync, final boolean isGlobalInitialSync) { - final TimelineJoinRoomSyncHandler joinRoomSyncHandler = new TimelineJoinRoomSyncHandler(this, roomSync, mStateHolder, isGlobalInitialSync); + final TimelineJoinRoomSyncHandler joinRoomSyncHandler = new TimelineJoinRoomSyncHandler(this, + roomSync, + mStateHolder, + isGlobalInitialSync); joinRoomSyncHandler.handle(); } @@ -339,7 +344,12 @@ public void handleJoinedRoomSync(@NonNull final RoomSync roomSync, final boolean */ @Override public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolean withPush) { - final TimelineLiveEventHandler liveEventHandler = new TimelineLiveEventHandler(this, mTimelineEventSaver, mStateEventRedactionChecker, mTimelinePushWorker, mStateHolder); + final TimelineLiveEventHandler liveEventHandler = new TimelineLiveEventHandler(this, + mTimelineEventSaver, + mStateEventRedactionChecker, + mTimelinePushWorker, + mStateHolder, + mEventListeners); liveEventHandler.handleLiveEvent(event, checkRedactedStateEvent, withPush); } @@ -413,7 +423,7 @@ private void manageBackEvents(int maxEventCount, final ApiCallback call } mSnapshotEvents.remove(0); - onEvent(snapshotedEvent.mEvent, Direction.BACKWARDS, snapshotedEvent.mState); + mEventListeners.onEvent(snapshotedEvent.mEvent, Direction.BACKWARDS, snapshotedEvent.mState); } // https://github.com/vector-im/vector-android/pull/354 @@ -530,7 +540,7 @@ protected void onPostExecute(Void args) { manageBackEvents(MAX_EVENT_COUNT_PER_PAGINATION, callback); } else { for (Event event : events) { - onEvent(event, Direction.FORWARDS, getState()); + mEventListeners.onEvent(event, Direction.FORWARDS, getState()); } if (null != callback) { @@ -891,7 +901,7 @@ protected void onPostExecute(Void args) { // send them one by one for (SnapshotEvent snapshotEvent : nextSnapshotEvents) { mSnapshotEvents.remove(snapshotEvent); - onEvent(snapshotEvent.mEvent, Direction.FORWARDS, snapshotEvent.mState); + mEventListeners.onEvent(snapshotEvent.mEvent, Direction.FORWARDS, snapshotEvent.mState); } // init the tokens @@ -949,21 +959,13 @@ public void run() { // onEvent listener management. //============================================================================================================== - private final List mEventTimelineListeners = new ArrayList<>(); - /** * Add an events listener. * * @param listener the listener to add. */ public void addEventTimelineListener(EventTimelineListener listener) { - if (null != listener) { - synchronized (this) { - if (-1 == mEventTimelineListeners.indexOf(listener)) { - mEventTimelineListeners.add(listener); - } - } - } + mEventListeners.add(listener); } /** @@ -972,45 +974,6 @@ public void addEventTimelineListener(EventTimelineListener listener) { * @param listener the listener to remove. */ public void removeEventTimelineListener(EventTimelineListener listener) { - if (null != listener) { - synchronized (this) { - mEventTimelineListeners.remove(listener); - } - } - } - - /** - * Dispatch the onEvent callback. - * - * @param event the event. - * @param direction the direction. - * @param roomState the roogetState(). - */ - @Override - public void onEvent(final Event event, final Direction direction, final RoomState roomState) { - // ensure that the listeners are called in the UI thread - if (Looper.getMainLooper().getThread() != Thread.currentThread()) { - final android.os.Handler handler = new android.os.Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run() { - onEvent(event, direction, roomState); - } - }); - } else { - List listeners; - - synchronized (this) { - listeners = new ArrayList<>(mEventTimelineListeners); - } - - for (EventTimelineListener listener : listeners) { - try { - listener.onEvent(event, direction, roomState); - } catch (Exception e) { - Log.e(LOG_TAG, "EventTimeline.onEvent " + listener + " crashes " + e.getMessage(), e); - } - } - } + mEventListeners.remove(listener); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java index 04f6d80c8..c1c6ba062 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java @@ -42,8 +42,6 @@ interface IEventTimeline { void setCanBackPaginate(boolean canBackPaginate); - void onEvent(final Event event, final Direction direction, final RoomState roomState); - /** * The direction from which an incoming event is considered. */ diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java new file mode 100644 index 000000000..31c0787ba --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java @@ -0,0 +1,105 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.data.timeline; + +import android.os.Handler; +import android.os.Looper; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * Handle the timeline event listeners + * Is responsible for dispatching events + */ +public class TimelineEventListeners { + + private static final String LOG_TAG = TimelineEventListeners.class.getSimpleName(); + + // The inner listeners + private final List mEventTimelineListeners = new ArrayList<>(); + + /** + * Add an events listener. + * + * @param listener the listener to add. + */ + public void add(@Nullable final IEventTimeline.EventTimelineListener listener) { + if (listener != null) { + synchronized (this) { + if (mEventTimelineListeners.indexOf(listener) == -1) { + mEventTimelineListeners.add(listener); + } + } + } + } + + /** + * Remove an events listener. + * + * @param listener the listener to remove. + */ + public void remove(@Nullable final IEventTimeline.EventTimelineListener listener) { + if (null != listener) { + synchronized (this) { + mEventTimelineListeners.remove(listener); + } + } + } + + /** + * Dispatch the onEvent callback. + * + * @param event the event. + * @param direction the direction. + * @param roomState the roomState. + */ + public void onEvent(@NonNull final Event event, + @NonNull final IEventTimeline.Direction direction, + @NonNull final RoomState roomState) { + // ensure that the listeners are called in the UI thread + if (Looper.getMainLooper().getThread() == Thread.currentThread()) { + final List listeners; + synchronized (this) { + listeners = new ArrayList<>(mEventTimelineListeners); + } + for (IEventTimeline.EventTimelineListener listener : listeners) { + try { + listener.onEvent(event, direction, roomState); + } catch (Exception e) { + Log.e(LOG_TAG, "EventTimeline.onEvent " + listener + " crashes " + e.getMessage(), e); + } + } + } else { + final Handler handler = new Handler(Looper.getMainLooper()); + handler.post(new Runnable() { + @Override + public void run() { + onEvent(event, direction, roomState); + } + }); + } + } + + +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java index 0d76ab8c4..0b2f0f613 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java @@ -46,17 +46,20 @@ class TimelineLiveEventHandler { private final StateEventRedactionChecker mStateEventRedactionChecker; private final TimelinePushWorker mTimelinePushWorker; private final TimelineStateHolder mTimelineStateHolder; + private final TimelineEventListeners mEventListeners; TimelineLiveEventHandler(@Nonnull final IEventTimeline eventTimeline, @Nonnull final TimelineEventSaver timelineEventSaver, @Nonnull final StateEventRedactionChecker stateEventRedactionChecker, @Nonnull final TimelinePushWorker timelinePushWorker, - @NonNull final TimelineStateHolder timelineStateHolder) { + @NonNull final TimelineStateHolder timelineStateHolder, + @NonNull final TimelineEventListeners eventListeners) { mEventTimeline = eventTimeline; mTimelineEventSaver = timelineEventSaver; mStateEventRedactionChecker = stateEventRedactionChecker; mTimelinePushWorker = timelinePushWorker; mTimelineStateHolder = timelineStateHolder; + mEventListeners = eventListeners; } /** @@ -88,7 +91,7 @@ public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolea // general listeners dataHandler.onLiveEvent(event, roomState); // timeline listeners - mEventTimeline.onEvent(event, IEventTimeline.Direction.FORWARDS, roomState); + mEventListeners.onEvent(event, IEventTimeline.Direction.FORWARDS, roomState); } // trigger pushes when it is required @@ -172,7 +175,7 @@ public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolea dataHandler.onLiveEvent(event, previousState); // timeline listeners - mEventTimeline.onEvent(event, IEventTimeline.Direction.FORWARDS, previousState); + mEventListeners.onEvent(event, IEventTimeline.Direction.FORWARDS, previousState); // trigger pushes when it is required if (withPush) { From f25a4f5245b20b48d5dc9b4db13db12885668e9f Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 26 Sep 2018 16:59:12 +0200 Subject: [PATCH 204/236] EventTimeline : dispatch live events --- .../data/timeline/EventTimeline.java | 29 ++++++------------- .../data/timeline/IEventTimeline.java | 2 -- .../TimelineInvitedRoomSyncHandler.java | 7 ++++- .../timeline/TimelineJoinRoomSyncHandler.java | 5 +++- 4 files changed, 19 insertions(+), 24 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java index 4940a913b..d3587c456 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java @@ -135,6 +135,7 @@ public class EventTimeline implements IEventTimeline { private final TimelinePushWorker mTimelinePushWorker; private final TimelineStateHolder mStateHolder; private final TimelineEventListeners mEventListeners; + private final TimelineLiveEventHandler mLiveEventHandler; /** * Constructor from room and event Id @@ -160,6 +161,12 @@ public class EventTimeline implements IEventTimeline { mTimelineEventSaver = new TimelineEventSaver(this, mStateHolder); mStateHolder.setRoomId(mRoomId); mEventListeners = new TimelineEventListeners(); + mLiveEventHandler = new TimelineLiveEventHandler(this, + mTimelineEventSaver, + mStateEventRedactionChecker, + mTimelinePushWorker, + mStateHolder, + mEventListeners); } /** @@ -317,7 +324,7 @@ private boolean processStateEvent(Event event, Direction direction) { * @param invitedRoomSync the invitation room events. */ public void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync) { - final TimelineInvitedRoomSyncHandler invitedRoomSyncHandler = new TimelineInvitedRoomSyncHandler(this, invitedRoomSync); + final TimelineInvitedRoomSyncHandler invitedRoomSyncHandler = new TimelineInvitedRoomSyncHandler(this, mLiveEventHandler, invitedRoomSync); invitedRoomSyncHandler.handle(); } @@ -331,28 +338,10 @@ public void handleJoinedRoomSync(@NonNull final RoomSync roomSync, final boolean final TimelineJoinRoomSyncHandler joinRoomSyncHandler = new TimelineJoinRoomSyncHandler(this, roomSync, mStateHolder, - isGlobalInitialSync); + mLiveEventHandler, isGlobalInitialSync); joinRoomSyncHandler.handle(); } - /** - * Handle events coming down from the event stream. - * - * @param event the live event - * @param checkRedactedStateEvent set to true to check if it triggers a state event redaction - * @param withPush set to true to trigger pushes when it is required - */ - @Override - public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolean withPush) { - final TimelineLiveEventHandler liveEventHandler = new TimelineLiveEventHandler(this, - mTimelineEventSaver, - mStateEventRedactionChecker, - mTimelinePushWorker, - mStateHolder, - mEventListeners); - liveEventHandler.handleLiveEvent(event, checkRedactedStateEvent, withPush); - } - /** * Store an outgoing event. * diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java index c1c6ba062..8c27c40cb 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java @@ -36,8 +36,6 @@ interface IEventTimeline { String getTimelineId(); - void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolean withPush); - boolean canBackPaginate(); void setCanBackPaginate(boolean canBackPaginate); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java index f8227ae81..1b1b93ef7 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java @@ -16,6 +16,8 @@ package org.matrix.androidsdk.data.timeline; +import android.support.annotation.NonNull; + import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.sync.InvitedRoomSync; @@ -29,11 +31,14 @@ class TimelineInvitedRoomSyncHandler { private final IEventTimeline mEventTimeline; + private final TimelineLiveEventHandler mLiveEventHandler; private final InvitedRoomSync mInvitedRoomSync; TimelineInvitedRoomSyncHandler(@Nonnull final IEventTimeline eventTimeline, + @NonNull final TimelineLiveEventHandler liveEventHandler, @Nullable final InvitedRoomSync invitedRoomSync) { mEventTimeline = eventTimeline; + mLiveEventHandler = liveEventHandler; mInvitedRoomSync = invitedRoomSync; } @@ -54,7 +59,7 @@ public void handle() { // The roomId is not defined. event.roomId = roomId; - mEventTimeline.handleLiveEvent(event, false, true); + mLiveEventHandler.handleLiveEvent(event, false, true); } // The room related to the pending invite can be considered as ready from now room.setReadyState(true); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java index 8584be2d3..f333dbc01 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java @@ -28,15 +28,18 @@ class TimelineJoinRoomSyncHandler { private final IEventTimeline mEventTimeline; private final RoomSync mRoomSync; private final TimelineStateHolder mTimelineStateHolder; + private final TimelineLiveEventHandler mTimelineLiveEventHandler; private final boolean mIsGlobalInitialSync; TimelineJoinRoomSyncHandler(@NonNull final IEventTimeline eventTimeline, @NonNull final RoomSync roomSync, @NonNull final TimelineStateHolder timelineStateHolder, + @NonNull final TimelineLiveEventHandler timelineLiveEventHandler, final boolean isGlobalInitialSync) { mEventTimeline = eventTimeline; mRoomSync = roomSync; mTimelineStateHolder = timelineStateHolder; + mTimelineLiveEventHandler = timelineLiveEventHandler; mIsGlobalInitialSync = isGlobalInitialSync; } @@ -179,7 +182,7 @@ private void handleRoomSyncTimeline(@NonNull final IMXStore store, boolean isLimited = (null != mRoomSync.timeline) && mRoomSync.timeline.limited; // digest the forward event - mEventTimeline.handleLiveEvent(event, !isLimited && !mIsGlobalInitialSync, !mIsGlobalInitialSync && !isRoomInitialSync); + mTimelineLiveEventHandler.handleLiveEvent(event, !isLimited && !mIsGlobalInitialSync, !mIsGlobalInitialSync && !isRoomInitialSync); } catch (Exception e) { Log.e(LOG_TAG, "timeline event failed " + e.getMessage(), e); } From 9c1a9fdcef7ea87a213f1c37cbb9c01b1e39fe27 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 26 Sep 2018 17:44:58 +0200 Subject: [PATCH 205/236] TimelineEvent : clean up dependencies --- .../data/timeline/EventTimeline.java | 27 ++++++++++--------- .../data/timeline/TimelineStateHolder.java | 7 ++--- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java index d3587c456..f5d3b90cd 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java @@ -97,7 +97,7 @@ public class EventTimeline implements IEventTimeline { /** * The data handler : used to retrieve data from the store or to trigger REST requests. */ - public MXDataHandler mDataHandler; + private MXDataHandler mDataHandler; /** * Pending request statuses @@ -131,17 +131,19 @@ public class EventTimeline implements IEventTimeline { private final String mTimelineId = System.currentTimeMillis() + ""; private final TimelineEventSaver mTimelineEventSaver; - private final StateEventRedactionChecker mStateEventRedactionChecker; - private final TimelinePushWorker mTimelinePushWorker; private final TimelineStateHolder mStateHolder; private final TimelineEventListeners mEventListeners; private final TimelineLiveEventHandler mLiveEventHandler; /** - * Constructor from room and event Id + * Constructor with package visibility. Creation should be done through EventTimelineFactory * - * @param dataHandler the data handler - * @param eventId the event id. + * @param store the store associated (in case of past timeline, the store is memory only) + * @param dataHandler the dataHandler + * @param room the room + * @param roomId the room id + * @param eventId the eventId + * @param isLive true if the timeline is a live one */ EventTimeline(@NonNull final IMXStore store, @NonNull final MXDataHandler dataHandler, @@ -155,16 +157,15 @@ public class EventTimeline implements IEventTimeline { mRoom = room; mRoomId = roomId; mStore = store; - mTimelinePushWorker = new TimelinePushWorker(mDataHandler); - mStateHolder = new TimelineStateHolder(mDataHandler, mStore); - mStateEventRedactionChecker = new StateEventRedactionChecker(this, mStateHolder); - mTimelineEventSaver = new TimelineEventSaver(this, mStateHolder); - mStateHolder.setRoomId(mRoomId); mEventListeners = new TimelineEventListeners(); + mStateHolder = new TimelineStateHolder(mDataHandler, mStore, roomId); + final StateEventRedactionChecker stateEventRedactionChecker = new StateEventRedactionChecker(this, mStateHolder); + mTimelineEventSaver = new TimelineEventSaver(this, mStateHolder); + final TimelinePushWorker timelinePushWorker = new TimelinePushWorker(mDataHandler); mLiveEventHandler = new TimelineLiveEventHandler(this, mTimelineEventSaver, - mStateEventRedactionChecker, - mTimelinePushWorker, + stateEventRedactionChecker, + timelinePushWorker, mStateHolder, mEventListeners); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java index 9314c21f9..505768e84 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java @@ -42,16 +42,15 @@ class TimelineStateHolder { */ private RoomState mBackState; - TimelineStateHolder(@NonNull final MXDataHandler dataHandler, @NonNull final IMXStore store) { + TimelineStateHolder(@NonNull final MXDataHandler dataHandler, @NonNull final IMXStore store, final String roomId) { mDataHandler = dataHandler; mStore = store; + mRoomId = roomId; initStates(); } public void clear() { initStates(); - mBackState.roomId = mRoomId; - mState.roomId = mRoomId; } /** @@ -131,8 +130,10 @@ public void setRoomId(@NonNull final String roomId) { private void initStates() { mBackState = new RoomState(); mBackState.setDataHandler(mDataHandler); + mBackState.roomId = mRoomId; mState = new RoomState(); mState.setDataHandler(mDataHandler); + mState.roomId = mRoomId; } From 7747aae0c24354e95cc58181b9b8161da6674c9b Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 26 Sep 2018 17:45:24 +0200 Subject: [PATCH 206/236] TimelineEvent : fix room creation (use good store) --- .../src/main/java/org/matrix/androidsdk/MXDataHandler.java | 2 +- matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java | 4 ++-- .../java/org/matrix/androidsdk/data/store/MXFileStore.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java index 83a559871..77d829a62 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/MXDataHandler.java @@ -827,7 +827,7 @@ public Room getRoom(IMXStore store, String roomId, boolean create) { room = store.getRoom(roomId); if ((room == null) && create) { Log.d(LOG_TAG, "## getRoom() : create the room " + roomId); - room = new Room(this, roomId); + room = new Room(this, store, roomId); store.storeRoom(room); } else if ((null != room) && (null == room.getDataHandler())) { // GA reports that some rooms have no data handler diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index 51db5e07a..f2b2ed9a2 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -136,9 +136,9 @@ public class Room { // true when the current room is a left one private boolean mIsLeft; - public Room(@NonNull final MXDataHandler dataHandler, @NonNull final String roomId) { + public Room(@NonNull final MXDataHandler dataHandler, @NonNull final IMXStore store, @NonNull final String roomId) { mDataHandler = dataHandler; - mStore = mDataHandler.getStore(roomId); + mStore = store; mMyUserId = mDataHandler.getUserId(); mTimeline = EventTimelineFactory.liveTimeline(mDataHandler, this, roomId); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java index 5da98d915..ef31e3ab2 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/store/MXFileStore.java @@ -1239,7 +1239,7 @@ private boolean loadRoomMessages(final String roomId) { // succeeds to extract the message list if (null != events) { // create the room object - final Room room = new Room(getDataHandler(), roomId); + final Room room = new Room(getDataHandler(), this, roomId); // do not wait that the live state update room.setReadyState(true); storeRoom(room); From 48375abc0462b331c63c2960f8701f459a781e06 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 26 Sep 2018 18:07:25 +0200 Subject: [PATCH 207/236] EventTimeline : expose only one interface --- .../data/timeline/EventTimeline.java | 842 +-------------- .../data/timeline/EventTimelineFactory.java | 4 +- .../data/timeline/IEventTimeline.java | 71 -- .../data/timeline/MXEventTimeline.java | 984 ++++++++++++++++++ .../timeline/StateEventRedactionChecker.java | 6 +- .../data/timeline/TimelineEventListeners.java | 12 +- .../data/timeline/TimelineEventSaver.java | 22 +- .../TimelineInvitedRoomSyncHandler.java | 12 +- .../timeline/TimelineJoinRoomSyncHandler.java | 4 +- .../timeline/TimelineLiveEventHandler.java | 12 +- .../data/timeline/TimelineStateHolder.java | 10 +- 11 files changed, 1079 insertions(+), 900 deletions(-) delete mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java create mode 100644 matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java index f5d3b90cd..509e69df5 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java @@ -1,6 +1,4 @@ /* - * Copyright 2016 OpenMarket Ltd - * Copyright 2017 Vector Creations Ltd * Copyright 2018 New Vector Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,31 +16,15 @@ package org.matrix.androidsdk.data.timeline; -import android.os.AsyncTask; -import android.os.Looper; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.TextUtils; -import org.matrix.androidsdk.MXDataHandler; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; -import org.matrix.androidsdk.data.RoomSummary; import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.rest.callback.ApiCallback; -import org.matrix.androidsdk.rest.callback.SimpleApiCallback; import org.matrix.androidsdk.rest.model.Event; -import org.matrix.androidsdk.rest.model.EventContext; -import org.matrix.androidsdk.rest.model.MatrixError; -import org.matrix.androidsdk.rest.model.TokensChunkEvents; import org.matrix.androidsdk.rest.model.sync.InvitedRoomSync; import org.matrix.androidsdk.rest.model.sync.RoomSync; -import org.matrix.androidsdk.util.FilterUtil; -import org.matrix.androidsdk.util.Log; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; /** * A `EventTimeline` instance represents a contiguous sequence of events in a room. @@ -58,276 +40,75 @@ * with events on calls of [MXEventTimeline paginate] in backwards or forwards direction. * Events are stored in a in-memory store (MXMemoryStore). */ -public class EventTimeline implements IEventTimeline { - private static final String LOG_TAG = EventTimeline.class.getSimpleName(); - - /** - * The initial event id used to initialise the timeline. - * null in case of live timeline. - */ - private String mInitialEventId; - - /** - * Indicate if this timeline is a live one. - */ - private boolean mIsLiveTimeline; - - /** - * The associated room. - */ - private final Room mRoom; - - /** - * the room Id - */ - private String mRoomId; - - /** - * The store. - */ - private IMXStore mStore; - - /** - * MXStore does only back pagination. So, the forward pagination token for - * past timelines is managed locally. - */ - private String mForwardsPaginationToken; - private boolean mHasReachedHomeServerForwardsPaginationEnd; - - /** - * The data handler : used to retrieve data from the store or to trigger REST requests. - */ - private MXDataHandler mDataHandler; - - /** - * Pending request statuses - */ - private boolean mIsBackPaginating = false; - private boolean mIsForwardPaginating = false; - - /** - * true if the back history has been retrieved. - */ - public boolean mCanBackPaginate = true; - - /** - * true if the last back chunck has been received - */ - private boolean mIsLastBackChunk; - - /** - * the server provides a token even for the first room message (which should never change it is the creator message). - * so requestHistory always triggers a remote request which returns an empty json. - * try to avoid such behaviour - */ - private String mBackwardTopToken = "not yet found"; - - // true when the current timeline is an historical one - private boolean mIsHistorical; - - /** - * Unique identifier - */ - private final String mTimelineId = System.currentTimeMillis() + ""; - - private final TimelineEventSaver mTimelineEventSaver; - private final TimelineStateHolder mStateHolder; - private final TimelineEventListeners mEventListeners; - private final TimelineLiveEventHandler mLiveEventHandler; - - /** - * Constructor with package visibility. Creation should be done through EventTimelineFactory - * - * @param store the store associated (in case of past timeline, the store is memory only) - * @param dataHandler the dataHandler - * @param room the room - * @param roomId the room id - * @param eventId the eventId - * @param isLive true if the timeline is a live one - */ - EventTimeline(@NonNull final IMXStore store, - @NonNull final MXDataHandler dataHandler, - @NonNull final Room room, - @NonNull final String roomId, - @Nullable final String eventId, - final boolean isLive) { - mIsLiveTimeline = isLive; - mInitialEventId = eventId; - mDataHandler = dataHandler; - mRoom = room; - mRoomId = roomId; - mStore = store; - mEventListeners = new TimelineEventListeners(); - mStateHolder = new TimelineStateHolder(mDataHandler, mStore, roomId); - final StateEventRedactionChecker stateEventRedactionChecker = new StateEventRedactionChecker(this, mStateHolder); - mTimelineEventSaver = new TimelineEventSaver(this, mStateHolder); - final TimelinePushWorker timelinePushWorker = new TimelinePushWorker(mDataHandler); - mLiveEventHandler = new TimelineLiveEventHandler(this, - mTimelineEventSaver, - stateEventRedactionChecker, - timelinePushWorker, - mStateHolder, - mEventListeners); - } - +public interface EventTimeline { /** * Defines that the current timeline is an historical one * * @param isHistorical true when the current timeline is an historical one */ - @Override - public void setIsHistorical(boolean isHistorical) { - mIsHistorical = isHistorical; - } + void setIsHistorical(boolean isHistorical); /** * Returns true if the current timeline is an historical one */ - @Override - public boolean isHistorical() { - return mIsHistorical; - } + boolean isHistorical(); - /* + /** * @return the unique identifier */ - @Override - public String getTimelineId() { - return mTimelineId; - } + String getTimelineId(); /** * @return the dedicated room */ - @Override - public Room getRoom() { - return mRoom; - } + Room getRoom(); /** * @return the used store */ - @Override - public IMXStore getStore() { - return mStore; - } + IMXStore getStore(); /** * @return the initial event id. */ - public String getInitialEventId() { - return mInitialEventId; - } + String getInitialEventId(); /** * @return true if this timeline is the live one */ - @Override - public boolean isLiveTimeline() { - return mIsLiveTimeline; - } + boolean isLiveTimeline(); /** * Get whether we are at the end of the message stream * * @return true if end has been reached */ - public boolean hasReachedHomeServerForwardsPaginationEnd() { - return mHasReachedHomeServerForwardsPaginationEnd; - } - + boolean hasReachedHomeServerForwardsPaginationEnd(); /** * Reset the back state so that future history requests start over from live. * Must be called when opening a room if interested in history. */ - @Override - public void initHistory() { - final RoomState backState = getState().deepCopy(); - setBackState(backState); - mCanBackPaginate = true; - - mIsBackPaginating = false; - mIsForwardPaginating = false; - - // sanity check - if ((null != mDataHandler) && (null != mDataHandler.getDataRetriever())) { - mDataHandler.resetReplayAttackCheckInTimeline(getTimelineId()); - mDataHandler.getDataRetriever().cancelHistoryRequest(mRoomId); - } - } + void initHistory(); /** * @return The state of the room at the top most recent event of the timeline. */ - public RoomState getState() { - return mStateHolder.getState(); - } + RoomState getState(); /** * Update the state. * * @param state the new state. */ - public void setState(RoomState state) { - mStateHolder.setState(state); - } - - /** - * Update the backState. - * - * @param state the new backState. - */ - private void setBackState(RoomState state) { - mStateHolder.setBackState(state); - } - - /** - * @return the backState. - */ - private RoomState getBackState() { - return mStateHolder.getBackState(); - } - - /** - * Lock over the backPaginate process - * - * @param canBackPaginate the state of the lock (true/false) - */ - @Override - public void setCanBackPaginate(final boolean canBackPaginate) { - mCanBackPaginate = canBackPaginate; - } - - /** - * Make a deep copy or the dedicated state. - * - * @param direction the room state direction to deep copy. - */ - public void deepCopyState(Direction direction) { - mStateHolder.deepCopyState(direction); - } - - /** - * Process a state event to keep the internal live and back states up to date. - * - * @param event the state event - * @param direction the direction; ie. forwards for live state, backwards for back state - * @return true if the event has been processed. - */ - private boolean processStateEvent(Event event, Direction direction) { - return mStateHolder.processStateEvent(event, direction); - } + void setState(RoomState state); /** * Handle the invitation room events * * @param invitedRoomSync the invitation room events. */ - public void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync) { - final TimelineInvitedRoomSyncHandler invitedRoomSyncHandler = new TimelineInvitedRoomSyncHandler(this, mLiveEventHandler, invitedRoomSync); - invitedRoomSyncHandler.handle(); - } + void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync); /** * Manage the joined room events. @@ -335,244 +116,21 @@ public void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync) { * @param roomSync the roomSync. * @param isGlobalInitialSync true if the sync has been triggered by a global initial sync */ - public void handleJoinedRoomSync(@NonNull final RoomSync roomSync, final boolean isGlobalInitialSync) { - final TimelineJoinRoomSyncHandler joinRoomSyncHandler = new TimelineJoinRoomSyncHandler(this, - roomSync, - mStateHolder, - mLiveEventHandler, isGlobalInitialSync); - joinRoomSyncHandler.handle(); - } + void handleJoinedRoomSync(@NonNull RoomSync roomSync, boolean isGlobalInitialSync); /** * Store an outgoing event. * * @param event the event to store */ - public void storeOutgoingEvent(Event event) { - if (mIsLiveTimeline) { - storeEvent(event); - } - } - - /** - * Store the event and update the dedicated room summary - * - * @param event the event to store - */ - private void storeEvent(Event event) { - mTimelineEventSaver.storeEvent(event); - } - - //================================================================================ - // History request - //================================================================================ - - private static final int MAX_EVENT_COUNT_PER_PAGINATION = 30; - - // the storage events are buffered to provide a small bunch of events - // the storage can provide a big bunch which slows down the UI. - public class SnapshotEvent { - public final Event mEvent; - public final RoomState mState; - - public SnapshotEvent(Event event, RoomState state) { - mEvent = event; - mState = state; - } - } - - // avoid adding to many events - // the room history request can provide more than expected event. - private final List mSnapshotEvents = new ArrayList<>(); - - /** - * Send MAX_EVENT_COUNT_PER_PAGINATION events to the caller. - * - * @param maxEventCount the max event count - * @param callback the callback. - */ - private void manageBackEvents(int maxEventCount, final ApiCallback callback) { - // check if the SDK was not logged out - if (!mDataHandler.isAlive()) { - Log.d(LOG_TAG, "manageEvents : mDataHandler is not anymore active."); - - return; - } - - int count = Math.min(mSnapshotEvents.size(), maxEventCount); - - Event latestSupportedEvent = null; - - for (int i = 0; i < count; i++) { - SnapshotEvent snapshotedEvent = mSnapshotEvents.get(0); - - // in some cases, there is no displayed summary - // https://github.com/vector-im/vector-android/pull/354 - if ((null == latestSupportedEvent) && RoomSummary.isSupportedEvent(snapshotedEvent.mEvent)) { - latestSupportedEvent = snapshotedEvent.mEvent; - } - - mSnapshotEvents.remove(0); - mEventListeners.onEvent(snapshotedEvent.mEvent, Direction.BACKWARDS, snapshotedEvent.mState); - } - - // https://github.com/vector-im/vector-android/pull/354 - // defines a new summary if the known is not supported - RoomSummary summary = mStore.getSummary(mRoomId); - - if ((null != latestSupportedEvent) && ((null == summary) || !RoomSummary.isSupportedEvent(summary.getLatestReceivedEvent()))) { - mStore.storeSummary(new RoomSummary(null, latestSupportedEvent, getState(), mDataHandler.getUserId())); - } - - Log.d(LOG_TAG, "manageEvents : commit"); - mStore.commit(); - - if ((mSnapshotEvents.size() < MAX_EVENT_COUNT_PER_PAGINATION) && mIsLastBackChunk) { - mCanBackPaginate = false; - } - mIsBackPaginating = false; - if (callback != null) { - try { - callback.onSuccess(count); - } catch (Exception e) { - Log.e(LOG_TAG, "requestHistory exception " + e.getMessage(), e); - } - } - } - - /** - * Add some events in a dedicated direction. - * - * @param events the events list - * @param stateEvents the received state events (in case of lazy loading of room members) - * @param direction the direction - */ - private void addPaginationEvents(List events, - @Nullable List stateEvents, - Direction direction) { - RoomSummary summary = mStore.getSummary(mRoomId); - boolean shouldCommitStore = false; - - // Process additional state events (this happens in case of lazy loading) - if (stateEvents != null) { - for (Event stateEvent : stateEvents) { - if (direction == Direction.BACKWARDS) { - // Enrich the timeline root state with the additional state events observed during back pagination - processStateEvent(stateEvent, Direction.FORWARDS); - } - - processStateEvent(stateEvent, direction); - } - } - - // the backward events have a dedicated management to avoid providing too many events for each request - for (Event event : events) { - boolean processedEvent = true; - - if (event.stateKey != null) { - deepCopyState(direction); - processedEvent = processStateEvent(event, direction); - } - - // Decrypt event if necessary - mDataHandler.decryptEvent(event, getTimelineId()); - - if (processedEvent) { - // warn the listener only if the message is processed. - // it should avoid duplicated events. - if (direction == Direction.BACKWARDS) { - if (mIsLiveTimeline) { - // update the summary is the event has been received after the oldest known event - // it might happen after a timeline update (hole in the chat history) - if ((null != summary) - && ((null == summary.getLatestReceivedEvent()) - || (event.isValidOriginServerTs() - && (summary.getLatestReceivedEvent().originServerTs < event.originServerTs) - && RoomSummary.isSupportedEvent(event)))) { - summary.setLatestReceivedEvent(event, getState()); - mStore.storeSummary(summary); - shouldCommitStore = true; - } - } - mSnapshotEvents.add(new SnapshotEvent(event, getBackState())); - // onEvent will be called in manageBackEvents - } - } - } - - if (shouldCommitStore) { - mStore.commit(); - } - } - - /** - * Add some events in a dedicated direction. - * - * @param events the events list - * @param stateEvents the received state events (in case of lazy loading of room members) - * @param direction the direction - * @param callback the callback. - */ - private void addPaginationEvents(final List events, - @Nullable final List stateEvents, - final Direction direction, - final ApiCallback callback) { - AsyncTask task = new AsyncTask() { - @Override - protected Void doInBackground(Void... params) { - addPaginationEvents(events, stateEvents, direction); - return null; - } - - @Override - protected void onPostExecute(Void args) { - if (direction == Direction.BACKWARDS) { - manageBackEvents(MAX_EVENT_COUNT_PER_PAGINATION, callback); - } else { - for (Event event : events) { - mEventListeners.onEvent(event, Direction.FORWARDS, getState()); - } - - if (null != callback) { - callback.onSuccess(events.size()); - } - } - } - }; - - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (final Exception e) { - Log.e(LOG_TAG, "## addPaginationEvents() failed " + e.getMessage(), e); - task.cancel(true); - - (new android.os.Handler(Looper.getMainLooper())).post(new Runnable() { - @Override - public void run() { - if (null != callback) { - callback.onUnexpectedError(e); - } - } - }); - } - } + void storeOutgoingEvent(Event event); /** * Tells if a back pagination can be triggered. * * @return true if a back pagination can be triggered. */ - @Override - public boolean canBackPaginate() { - // One at a time please - return !mIsBackPaginating - // history_visibility flag management - && getState().canBackPaginate(mRoom.isJoined(), mRoom.isInvited()) - // If we have already reached the end of history - && mCanBackPaginate - // If the room is not finished being set up - && mRoom.isReady(); - } + boolean canBackPaginate(); /** * Request older messages. @@ -580,9 +138,7 @@ && getState().canBackPaginate(mRoom.isJoined(), mRoom.isInvited()) * @param callback the asynchronous callback * @return true if request starts */ - public boolean backPaginate(final ApiCallback callback) { - return backPaginate(MAX_EVENT_COUNT_PER_PAGINATION, callback); - } + boolean backPaginate(ApiCallback callback); /** * Request older messages. @@ -591,9 +147,7 @@ public boolean backPaginate(final ApiCallback callback) { * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. * @return true if request starts */ - public boolean backPaginate(final int eventCount, final ApiCallback callback) { - return backPaginate(eventCount, false, callback); - } + boolean backPaginate(int eventCount, ApiCallback callback); /** * Request older messages. @@ -603,138 +157,7 @@ public boolean backPaginate(final int eventCount, final ApiCallback cal * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. * @return true if request starts */ - public boolean backPaginate(final int eventCount, final boolean useCachedOnly, final ApiCallback callback) { - if (!canBackPaginate()) { - Log.d(LOG_TAG, "cannot requestHistory " + mIsBackPaginating + " " + !getState().canBackPaginate(mRoom.isJoined(), mRoom.isInvited()) - + " " + !mCanBackPaginate + " " + !mRoom.isReady()); - return false; - } - - Log.d(LOG_TAG, "backPaginate starts"); - - // restart the pagination - if (null == getBackState().getToken()) { - mSnapshotEvents.clear(); - } - - final String fromBackToken = getBackState().getToken(); - - mIsBackPaginating = true; - - // enough buffered data - if (useCachedOnly - || (mSnapshotEvents.size() >= eventCount) - || TextUtils.equals(fromBackToken, mBackwardTopToken) - || TextUtils.equals(fromBackToken, Event.PAGINATE_BACK_TOKEN_END)) { - - mIsLastBackChunk = TextUtils.equals(fromBackToken, mBackwardTopToken) || TextUtils.equals(fromBackToken, Event.PAGINATE_BACK_TOKEN_END); - - final android.os.Handler handler = new android.os.Handler(Looper.getMainLooper()); - final int maxEventsCount; - - if (useCachedOnly) { - Log.d(LOG_TAG, "backPaginate : load " + mSnapshotEvents.size() + "cached events list"); - maxEventsCount = Math.min(mSnapshotEvents.size(), eventCount); - } else if ((mSnapshotEvents.size() >= eventCount)) { - Log.d(LOG_TAG, "backPaginate : the events are already loaded."); - maxEventsCount = eventCount; - } else { - Log.d(LOG_TAG, "backPaginate : reach the history top"); - maxEventsCount = eventCount; - } - - // call the callback with a delay - // to reproduce the same behaviour as a network request. - Runnable r = new Runnable() { - @Override - public void run() { - handler.postDelayed(new Runnable() { - public void run() { - manageBackEvents(maxEventsCount, callback); - } - }, 0); - } - }; - - Thread t = new Thread(r); - t.start(); - - return true; - } - - mDataHandler.getDataRetriever().backPaginate(mStore, mRoomId, getBackState().getToken(), eventCount, mDataHandler.isLazyLoadingEnabled(), - new SimpleApiCallback(callback) { - @Override - public void onSuccess(TokensChunkEvents response) { - if (mDataHandler.isAlive()) { - - if (null != response.chunk) { - Log.d(LOG_TAG, "backPaginate : " + response.chunk.size() + " events are retrieved."); - } else { - Log.d(LOG_TAG, "backPaginate : there is no event"); - } - - mIsLastBackChunk = ((null != response.chunk) - && (0 == response.chunk.size()) - && TextUtils.equals(response.end, response.start)) - || (null == response.end); - - if (mIsLastBackChunk && (null != response.end)) { - // save its token to avoid useless request - mBackwardTopToken = fromBackToken; - } else { - // the server returns a null pagination token when there is no more available data - if (null == response.end) { - getBackState().setToken(Event.PAGINATE_BACK_TOKEN_END); - } else { - getBackState().setToken(response.end); - } - } - - addPaginationEvents((null == response.chunk) ? new ArrayList() : response.chunk, - response.stateEvents, - Direction.BACKWARDS, - callback); - - } else { - Log.d(LOG_TAG, "mDataHandler is not active."); - } - } - - @Override - public void onMatrixError(MatrixError e) { - Log.d(LOG_TAG, "backPaginate onMatrixError"); - - // When we've retrieved all the messages from a room, the pagination token is some invalid value - if (MatrixError.UNKNOWN.equals(e.errcode)) { - mCanBackPaginate = false; - } - mIsBackPaginating = false; - - super.onMatrixError(e); - } - - @Override - public void onNetworkError(Exception e) { - Log.d(LOG_TAG, "backPaginate onNetworkError"); - - mIsBackPaginating = false; - - super.onNetworkError(e); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.d(LOG_TAG, "backPaginate onUnexpectedError"); - - mIsBackPaginating = false; - - super.onUnexpectedError(e); - } - }); - - return true; - } + boolean backPaginate(int eventCount, boolean useCachedOnly, ApiCallback callback); /** * Request older messages. @@ -742,65 +165,7 @@ public void onUnexpectedError(Exception e) { * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. * @return true if request starts */ - public boolean forwardPaginate(final ApiCallback callback) { - if (mIsLiveTimeline) { - Log.d(LOG_TAG, "Cannot forward paginate on Live timeline"); - return false; - } - - if (mIsForwardPaginating || mHasReachedHomeServerForwardsPaginationEnd) { - Log.d(LOG_TAG, "forwardPaginate " + mIsForwardPaginating - + " mHasReachedHomeServerForwardsPaginationEnd " + mHasReachedHomeServerForwardsPaginationEnd); - return false; - } - - mIsForwardPaginating = true; - - mDataHandler.getDataRetriever().paginate(mStore, mRoomId, mForwardsPaginationToken, Direction.FORWARDS, mDataHandler.isLazyLoadingEnabled(), - new SimpleApiCallback(callback) { - @Override - public void onSuccess(TokensChunkEvents response) { - if (mDataHandler.isAlive()) { - Log.d(LOG_TAG, "forwardPaginate : " + response.chunk.size() + " are retrieved."); - - mHasReachedHomeServerForwardsPaginationEnd = (0 == response.chunk.size()) && TextUtils.equals(response.end, response.start); - mForwardsPaginationToken = response.end; - - addPaginationEvents(response.chunk, - response.stateEvents, - Direction.FORWARDS, - callback); - - mIsForwardPaginating = false; - } else { - Log.d(LOG_TAG, "mDataHandler is not active."); - } - } - - @Override - public void onMatrixError(MatrixError e) { - mIsForwardPaginating = false; - - super.onMatrixError(e); - } - - @Override - public void onNetworkError(Exception e) { - mIsForwardPaginating = false; - - super.onNetworkError(e); - } - - @Override - public void onUnexpectedError(Exception e) { - mIsForwardPaginating = false; - - super.onUnexpectedError(e); - } - }); - - return true; - } + boolean forwardPaginate(ApiCallback callback); /** * Trigger a pagination in the expected direction. @@ -809,26 +174,12 @@ public void onUnexpectedError(Exception e) { * @param callback the callback. * @return true if the operation succeeds */ - public boolean paginate(Direction direction, final ApiCallback callback) { - if (Direction.BACKWARDS == direction) { - return backPaginate(callback); - } else { - return forwardPaginate(callback); - } - } + boolean paginate(EventTimeline.Direction direction, ApiCallback callback); /** * Cancel any pending pagination requests */ - public void cancelPaginationRequest() { - mDataHandler.getDataRetriever().cancelHistoryRequest(mRoomId); - mIsBackPaginating = false; - mIsForwardPaginating = false; - } - - //============================================================================================================== - // pagination methods - //============================================================================================================== + void cancelPaginationRequest(); /** * Reset the pagination timelime and start loading the context around its `initialEventId`. @@ -837,133 +188,48 @@ public void cancelPaginationRequest() { * @param limit the maximum number of messages to get around the initial event. * @param callback the operation callback */ - public void resetPaginationAroundInitialEvent(final int limit, final ApiCallback callback) { - // Reset the store - mStore.deleteRoomData(mRoomId); - - mDataHandler.resetReplayAttackCheckInTimeline(getTimelineId()); - - mForwardsPaginationToken = null; - mHasReachedHomeServerForwardsPaginationEnd = false; - - mDataHandler.getDataRetriever() - .getRoomsRestClient() - .getContextOfEvent(mRoomId, mInitialEventId, limit, FilterUtil.createRoomEventFilter(mDataHandler.isLazyLoadingEnabled()), - new SimpleApiCallback(callback) { - @Override - public void onSuccess(final EventContext eventContext) { - - AsyncTask task = new AsyncTask() { - @Override - protected Void doInBackground(Void... params) { - // the state is the one after the latest event of the chunk i.e. the last message of eventContext.eventsAfter - for (Event event : eventContext.state) { - processStateEvent(event, Direction.FORWARDS); - } - - // init the room states - initHistory(); - - // build the events list - List events = new ArrayList<>(); - - Collections.reverse(eventContext.eventsAfter); - events.addAll(eventContext.eventsAfter); - events.add(eventContext.event); - events.addAll(eventContext.eventsBefore); - - // add events after - addPaginationEvents(events, null, Direction.BACKWARDS); - - return null; - } - - @Override - protected void onPostExecute(Void args) { - // create dummy forward events list - // to center the selected event id - // else if might be out of screen - List nextSnapshotEvents = new ArrayList<>(mSnapshotEvents.subList(0, (mSnapshotEvents.size() + 1) / 2)); - - // put in the right order - Collections.reverse(nextSnapshotEvents); - - // send them one by one - for (SnapshotEvent snapshotEvent : nextSnapshotEvents) { - mSnapshotEvents.remove(snapshotEvent); - mEventListeners.onEvent(snapshotEvent.mEvent, Direction.FORWARDS, snapshotEvent.mState); - } - - // init the tokens - getBackState().setToken(eventContext.start); - mForwardsPaginationToken = eventContext.end; - - // send the back events to complete pagination - manageBackEvents(MAX_EVENT_COUNT_PER_PAGINATION, new ApiCallback() { - @Override - public void onSuccess(Integer info) { - Log.d(LOG_TAG, "addPaginationEvents succeeds"); - } - - @Override - public void onNetworkError(Exception e) { - Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage(), e); - } - - @Override - public void onMatrixError(MatrixError e) { - Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage()); - } - - @Override - public void onUnexpectedError(Exception e) { - Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage(), e); - } - }); - - // everything is done - callback.onSuccess(null); - } - }; - - try { - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } catch (final Exception e) { - Log.e(LOG_TAG, "## resetPaginationAroundInitialEvent() failed " + e.getMessage(), e); - task.cancel(true); - - (new android.os.Handler(Looper.getMainLooper())).post(new Runnable() { - @Override - public void run() { - if (callback != null) { - callback.onUnexpectedError(e); - } - } - }); - } - } - }); - } - - //============================================================================================================== - // onEvent listener management. - //============================================================================================================== + void resetPaginationAroundInitialEvent(int limit, ApiCallback callback); /** * Add an events listener. * * @param listener the listener to add. */ - public void addEventTimelineListener(EventTimelineListener listener) { - mEventListeners.add(listener); - } + void addEventTimelineListener(EventTimeline.EventTimelineListener listener); /** * Remove an events listener. * * @param listener the listener to remove. */ - public void removeEventTimelineListener(EventTimelineListener listener) { - mEventListeners.remove(listener); + void removeEventTimelineListener(EventTimeline.EventTimelineListener listener); + + /** + * The direction from which an incoming event is considered. + */ + enum Direction { + /** + * Forwards when the event is added to the end of the timeline. + * These events come from the /sync stream or from forwards pagination. + */ + FORWARDS, + + /** + * Backwards when the event is added to the start of the timeline. + * These events come from a back pagination. + */ + BACKWARDS + } + + interface EventTimelineListener { + + /** + * Call when an event has been handled in the timeline. + * + * @param event the event. + * @param direction the direction. + * @param roomState the room state + */ + void onEvent(Event event, Direction direction, RoomState roomState); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java index 0e3fa140f..ef4e50fbf 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java @@ -35,7 +35,7 @@ public class EventTimelineFactory { public static EventTimeline liveTimeline(@NonNull final MXDataHandler dataHandler, @NonNull final Room room, @NonNull final String roomId) { - return new EventTimeline(dataHandler.getStore(roomId), dataHandler, room, roomId, null, true); + return new MXEventTimeline(dataHandler.getStore(roomId), dataHandler, room, roomId, null, true); } /** @@ -63,7 +63,7 @@ public static EventTimeline pastTimeline(@NonNull MXDataHandler dataHandler, @Nullable String eventId) { final MXMemoryStore store = new MXMemoryStore(dataHandler.getCredentials(), null); final Room room = dataHandler.getRoom(store, roomId, true); - final EventTimeline eventTimeline = new EventTimeline(store, dataHandler, room, roomId, eventId, false); + final EventTimeline eventTimeline = new MXEventTimeline(store, dataHandler, room, roomId, eventId, false); room.setTimeline(eventTimeline); room.setReadyState(true); return eventTimeline; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java deleted file mode 100644 index 8c27c40cb..000000000 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/IEventTimeline.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2018 New Vector Ltd - * - * 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 org.matrix.androidsdk.data.timeline; - -import org.matrix.androidsdk.data.Room; -import org.matrix.androidsdk.data.RoomState; -import org.matrix.androidsdk.data.store.IMXStore; -import org.matrix.androidsdk.rest.model.Event; - -interface IEventTimeline { - void setIsHistorical(boolean isHistorical); - - boolean isHistorical(); - - void initHistory(); - - Room getRoom(); - - IMXStore getStore(); - - boolean isLiveTimeline(); - - String getTimelineId(); - - boolean canBackPaginate(); - - void setCanBackPaginate(boolean canBackPaginate); - - /** - * The direction from which an incoming event is considered. - */ - enum Direction { - /** - * Forwards when the event is added to the end of the timeline. - * These events come from the /sync stream or from forwards pagination. - */ - FORWARDS, - - /** - * Backwards when the event is added to the start of the timeline. - * These events come from a back pagination. - */ - BACKWARDS - } - - interface EventTimelineListener { - - /** - * Call when an event has been handled in the timeline. - * - * @param event the event. - * @param direction the direction. - * @param roomState the room state - */ - void onEvent(Event event, Direction direction, RoomState roomState); - } -} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java new file mode 100644 index 000000000..9ce27f3da --- /dev/null +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java @@ -0,0 +1,984 @@ +/* + * Copyright 2016 OpenMarket Ltd + * Copyright 2017 Vector Creations Ltd + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.data.timeline; + +import android.os.AsyncTask; +import android.os.Looper; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import org.matrix.androidsdk.MXDataHandler; +import org.matrix.androidsdk.data.Room; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.data.RoomSummary; +import org.matrix.androidsdk.data.store.IMXStore; +import org.matrix.androidsdk.rest.callback.ApiCallback; +import org.matrix.androidsdk.rest.callback.SimpleApiCallback; +import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.rest.model.EventContext; +import org.matrix.androidsdk.rest.model.MatrixError; +import org.matrix.androidsdk.rest.model.TokensChunkEvents; +import org.matrix.androidsdk.rest.model.sync.InvitedRoomSync; +import org.matrix.androidsdk.rest.model.sync.RoomSync; +import org.matrix.androidsdk.util.FilterUtil; +import org.matrix.androidsdk.util.Log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A `EventTimeline` instance represents a contiguous sequence of events in a room. + *

    + * There are two kinds of timeline: + *

    + * - live timelines: they receive live events from the events stream. You can paginate + * backwards but not forwards. + * All (live or backwards) events they receive are stored in the store of the current + * MXSession. + *

    + * - past timelines: they start in the past from an `initialEventId`. They are filled + * with events on calls of [MXEventTimeline paginate] in backwards or forwards direction. + * Events are stored in a in-memory store (MXMemoryStore). + */ +class MXEventTimeline implements EventTimeline { + private static final String LOG_TAG = MXEventTimeline.class.getSimpleName(); + + /** + * The initial event id used to initialise the timeline. + * null in case of live timeline. + */ + private String mInitialEventId; + + /** + * Indicate if this timeline is a live one. + */ + private boolean mIsLiveTimeline; + + /** + * The associated room. + */ + private final Room mRoom; + + /** + * the room Id + */ + private String mRoomId; + + /** + * The store. + */ + private IMXStore mStore; + + /** + * MXStore does only back pagination. So, the forward pagination token for + * past timelines is managed locally. + */ + private String mForwardsPaginationToken; + private boolean mHasReachedHomeServerForwardsPaginationEnd; + + /** + * The data handler : used to retrieve data from the store or to trigger REST requests. + */ + private MXDataHandler mDataHandler; + + /** + * Pending request statuses + */ + private boolean mIsBackPaginating = false; + private boolean mIsForwardPaginating = false; + + /** + * true if the back history has been retrieved. + */ + public boolean mCanBackPaginate = true; + + /** + * true if the last back chunck has been received + */ + private boolean mIsLastBackChunk; + + /** + * the server provides a token even for the first room message (which should never change it is the creator message). + * so requestHistory always triggers a remote request which returns an empty json. + * try to avoid such behaviour + */ + private String mBackwardTopToken = "not yet found"; + + // true when the current timeline is an historical one + private boolean mIsHistorical; + + /** + * Unique identifier + */ + private final String mTimelineId = System.currentTimeMillis() + ""; + + private final TimelineEventSaver mTimelineEventSaver; + private final TimelineStateHolder mStateHolder; + private final TimelineEventListeners mEventListeners; + private final TimelineLiveEventHandler mLiveEventHandler; + + /** + * Constructor with package visibility. Creation should be done through EventTimelineFactory + * + * @param store the store associated (in case of past timeline, the store is memory only) + * @param dataHandler the dataHandler + * @param room the room + * @param roomId the room id + * @param eventId the eventId + * @param isLive true if the timeline is a live one + */ + MXEventTimeline(@NonNull final IMXStore store, + @NonNull final MXDataHandler dataHandler, + @NonNull final Room room, + @NonNull final String roomId, + @Nullable final String eventId, + final boolean isLive) { + mIsLiveTimeline = isLive; + mInitialEventId = eventId; + mDataHandler = dataHandler; + mRoom = room; + mRoomId = roomId; + mStore = store; + mEventListeners = new TimelineEventListeners(); + mStateHolder = new TimelineStateHolder(mDataHandler, mStore, roomId); + final StateEventRedactionChecker stateEventRedactionChecker = new StateEventRedactionChecker(this, mStateHolder); + mTimelineEventSaver = new TimelineEventSaver(mStore, mRoom, mStateHolder); + final TimelinePushWorker timelinePushWorker = new TimelinePushWorker(mDataHandler); + mLiveEventHandler = new TimelineLiveEventHandler(this, + mTimelineEventSaver, + stateEventRedactionChecker, + timelinePushWorker, + mStateHolder, + mEventListeners); + } + + /** + * Defines that the current timeline is an historical one + * + * @param isHistorical true when the current timeline is an historical one + */ + @Override + public void setIsHistorical(boolean isHistorical) { + mIsHistorical = isHistorical; + } + + /** + * Returns true if the current timeline is an historical one + */ + @Override + public boolean isHistorical() { + return mIsHistorical; + } + + /* + * @return the unique identifier + */ + @Override + public String getTimelineId() { + return mTimelineId; + } + + /** + * @return the dedicated room + */ + @Override + public Room getRoom() { + return mRoom; + } + + /** + * @return the used store + */ + @Override + public IMXStore getStore() { + return mStore; + } + + /** + * @return the initial event id. + */ + @Override + public String getInitialEventId() { + return mInitialEventId; + } + + /** + * @return true if this timeline is the live one + */ + @Override + public boolean isLiveTimeline() { + return mIsLiveTimeline; + } + + /** + * Get whether we are at the end of the message stream + * + * @return true if end has been reached + */ + @Override + public boolean hasReachedHomeServerForwardsPaginationEnd() { + return mHasReachedHomeServerForwardsPaginationEnd; + } + + + /** + * Reset the back state so that future history requests start over from live. + * Must be called when opening a room if interested in history. + */ + @Override + public void initHistory() { + final RoomState backState = getState().deepCopy(); + setBackState(backState); + mCanBackPaginate = true; + + mIsBackPaginating = false; + mIsForwardPaginating = false; + + // sanity check + if ((null != mDataHandler) && (null != mDataHandler.getDataRetriever())) { + mDataHandler.resetReplayAttackCheckInTimeline(getTimelineId()); + mDataHandler.getDataRetriever().cancelHistoryRequest(mRoomId); + } + } + + /** + * @return The state of the room at the top most recent event of the timeline. + */ + @Override + public RoomState getState() { + return mStateHolder.getState(); + } + + /** + * Update the state. + * + * @param state the new state. + */ + @Override + public void setState(RoomState state) { + mStateHolder.setState(state); + } + + /** + * Update the backState. + * + * @param state the new backState. + */ + private void setBackState(RoomState state) { + mStateHolder.setBackState(state); + } + + /** + * @return the backState. + */ + private RoomState getBackState() { + return mStateHolder.getBackState(); + } + + /** + * Lock over the backPaginate process + * + * @param canBackPaginate the state of the lock (true/false) + */ + protected void setCanBackPaginate(final boolean canBackPaginate) { + mCanBackPaginate = canBackPaginate; + } + + /** + * Make a deep copy or the dedicated state. + * + * @param direction the room state direction to deep copy. + */ + private void deepCopyState(Direction direction) { + mStateHolder.deepCopyState(direction); + } + + /** + * Process a state event to keep the internal live and back states up to date. + * + * @param event the state event + * @param direction the direction; ie. forwards for live state, backwards for back state + * @return true if the event has been processed. + */ + private boolean processStateEvent(Event event, Direction direction) { + return mStateHolder.processStateEvent(event, direction); + } + + /** + * Handle the invitation room events + * + * @param invitedRoomSync the invitation room events. + */ + @Override + public void handleInvitedRoomSync(InvitedRoomSync invitedRoomSync) { + final TimelineInvitedRoomSyncHandler invitedRoomSyncHandler = new TimelineInvitedRoomSyncHandler(mRoom, mLiveEventHandler, invitedRoomSync); + invitedRoomSyncHandler.handle(); + } + + /** + * Manage the joined room events. + * + * @param roomSync the roomSync. + * @param isGlobalInitialSync true if the sync has been triggered by a global initial sync + */ + @Override + public void handleJoinedRoomSync(@NonNull final RoomSync roomSync, final boolean isGlobalInitialSync) { + final TimelineJoinRoomSyncHandler joinRoomSyncHandler = new TimelineJoinRoomSyncHandler(this, + roomSync, + mStateHolder, + mLiveEventHandler, isGlobalInitialSync); + joinRoomSyncHandler.handle(); + } + + /** + * Store an outgoing event. + * + * @param event the event to store + */ + @Override + public void storeOutgoingEvent(Event event) { + if (mIsLiveTimeline) { + storeEvent(event); + } + } + + /** + * Store the event and update the dedicated room summary + * + * @param event the event to store + */ + private void storeEvent(Event event) { + mTimelineEventSaver.storeEvent(event); + } + + //================================================================================ + // History request + //================================================================================ + + private static final int MAX_EVENT_COUNT_PER_PAGINATION = 30; + + // the storage events are buffered to provide a small bunch of events + // the storage can provide a big bunch which slows down the UI. + public class SnapshotEvent { + public final Event mEvent; + public final RoomState mState; + + public SnapshotEvent(Event event, RoomState state) { + mEvent = event; + mState = state; + } + } + + // avoid adding to many events + // the room history request can provide more than expected event. + private final List mSnapshotEvents = new ArrayList<>(); + + /** + * Send MAX_EVENT_COUNT_PER_PAGINATION events to the caller. + * + * @param maxEventCount the max event count + * @param callback the callback. + */ + private void manageBackEvents(int maxEventCount, final ApiCallback callback) { + // check if the SDK was not logged out + if (!mDataHandler.isAlive()) { + Log.d(LOG_TAG, "manageEvents : mDataHandler is not anymore active."); + + return; + } + + int count = Math.min(mSnapshotEvents.size(), maxEventCount); + + Event latestSupportedEvent = null; + + for (int i = 0; i < count; i++) { + SnapshotEvent snapshotedEvent = mSnapshotEvents.get(0); + + // in some cases, there is no displayed summary + // https://github.com/vector-im/vector-android/pull/354 + if ((null == latestSupportedEvent) && RoomSummary.isSupportedEvent(snapshotedEvent.mEvent)) { + latestSupportedEvent = snapshotedEvent.mEvent; + } + + mSnapshotEvents.remove(0); + mEventListeners.onEvent(snapshotedEvent.mEvent, Direction.BACKWARDS, snapshotedEvent.mState); + } + + // https://github.com/vector-im/vector-android/pull/354 + // defines a new summary if the known is not supported + RoomSummary summary = mStore.getSummary(mRoomId); + + if ((null != latestSupportedEvent) && ((null == summary) || !RoomSummary.isSupportedEvent(summary.getLatestReceivedEvent()))) { + mStore.storeSummary(new RoomSummary(null, latestSupportedEvent, getState(), mDataHandler.getUserId())); + } + + Log.d(LOG_TAG, "manageEvents : commit"); + mStore.commit(); + + if ((mSnapshotEvents.size() < MAX_EVENT_COUNT_PER_PAGINATION) && mIsLastBackChunk) { + mCanBackPaginate = false; + } + mIsBackPaginating = false; + if (callback != null) { + try { + callback.onSuccess(count); + } catch (Exception e) { + Log.e(LOG_TAG, "requestHistory exception " + e.getMessage(), e); + } + } + } + + /** + * Add some events in a dedicated direction. + * + * @param events the events list + * @param stateEvents the received state events (in case of lazy loading of room members) + * @param direction the direction + */ + private void addPaginationEvents(List events, + @Nullable List stateEvents, + Direction direction) { + RoomSummary summary = mStore.getSummary(mRoomId); + boolean shouldCommitStore = false; + + // Process additional state events (this happens in case of lazy loading) + if (stateEvents != null) { + for (Event stateEvent : stateEvents) { + if (direction == Direction.BACKWARDS) { + // Enrich the timeline root state with the additional state events observed during back pagination + processStateEvent(stateEvent, Direction.FORWARDS); + } + + processStateEvent(stateEvent, direction); + } + } + + // the backward events have a dedicated management to avoid providing too many events for each request + for (Event event : events) { + boolean processedEvent = true; + + if (event.stateKey != null) { + deepCopyState(direction); + processedEvent = processStateEvent(event, direction); + } + + // Decrypt event if necessary + mDataHandler.decryptEvent(event, getTimelineId()); + + if (processedEvent) { + // warn the listener only if the message is processed. + // it should avoid duplicated events. + if (direction == Direction.BACKWARDS) { + if (mIsLiveTimeline) { + // update the summary is the event has been received after the oldest known event + // it might happen after a timeline update (hole in the chat history) + if ((null != summary) + && ((null == summary.getLatestReceivedEvent()) + || (event.isValidOriginServerTs() + && (summary.getLatestReceivedEvent().originServerTs < event.originServerTs) + && RoomSummary.isSupportedEvent(event)))) { + summary.setLatestReceivedEvent(event, getState()); + mStore.storeSummary(summary); + shouldCommitStore = true; + } + } + mSnapshotEvents.add(new SnapshotEvent(event, getBackState())); + // onEvent will be called in manageBackEvents + } + } + } + + if (shouldCommitStore) { + mStore.commit(); + } + } + + /** + * Add some events in a dedicated direction. + * + * @param events the events list + * @param stateEvents the received state events (in case of lazy loading of room members) + * @param direction the direction + * @param callback the callback. + */ + private void addPaginationEvents(final List events, + @Nullable final List stateEvents, + final Direction direction, + final ApiCallback callback) { + AsyncTask task = new AsyncTask() { + @Override + protected Void doInBackground(Void... params) { + addPaginationEvents(events, stateEvents, direction); + return null; + } + + @Override + protected void onPostExecute(Void args) { + if (direction == Direction.BACKWARDS) { + manageBackEvents(MAX_EVENT_COUNT_PER_PAGINATION, callback); + } else { + for (Event event : events) { + mEventListeners.onEvent(event, Direction.FORWARDS, getState()); + } + + if (null != callback) { + callback.onSuccess(events.size()); + } + } + } + }; + + try { + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } catch (final Exception e) { + Log.e(LOG_TAG, "## addPaginationEvents() failed " + e.getMessage(), e); + task.cancel(true); + + (new android.os.Handler(Looper.getMainLooper())).post(new Runnable() { + @Override + public void run() { + if (null != callback) { + callback.onUnexpectedError(e); + } + } + }); + } + } + + /** + * Tells if a back pagination can be triggered. + * + * @return true if a back pagination can be triggered. + */ + @Override + public boolean canBackPaginate() { + // One at a time please + return !mIsBackPaginating + // history_visibility flag management + && getState().canBackPaginate(mRoom.isJoined(), mRoom.isInvited()) + // If we have already reached the end of history + && mCanBackPaginate + // If the room is not finished being set up + && mRoom.isReady(); + } + + /** + * Request older messages. + * + * @param callback the asynchronous callback + * @return true if request starts + */ + @Override + public boolean backPaginate(final ApiCallback callback) { + return backPaginate(MAX_EVENT_COUNT_PER_PAGINATION, callback); + } + + /** + * Request older messages. + * + * @param eventCount number of events we want to retrieve + * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. + * @return true if request starts + */ + @Override + public boolean backPaginate(final int eventCount, final ApiCallback callback) { + return backPaginate(eventCount, false, callback); + } + + /** + * Request older messages. + * + * @param eventCount number of events we want to retrieve + * @param useCachedOnly to use the cached events list only (i.e no request will be triggered) + * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. + * @return true if request starts + */ + @Override + public boolean backPaginate(final int eventCount, final boolean useCachedOnly, final ApiCallback callback) { + if (!canBackPaginate()) { + Log.d(LOG_TAG, "cannot requestHistory " + mIsBackPaginating + " " + !getState().canBackPaginate(mRoom.isJoined(), mRoom.isInvited()) + + " " + !mCanBackPaginate + " " + !mRoom.isReady()); + return false; + } + + Log.d(LOG_TAG, "backPaginate starts"); + + // restart the pagination + if (null == getBackState().getToken()) { + mSnapshotEvents.clear(); + } + + final String fromBackToken = getBackState().getToken(); + + mIsBackPaginating = true; + + // enough buffered data + if (useCachedOnly + || (mSnapshotEvents.size() >= eventCount) + || TextUtils.equals(fromBackToken, mBackwardTopToken) + || TextUtils.equals(fromBackToken, Event.PAGINATE_BACK_TOKEN_END)) { + + mIsLastBackChunk = TextUtils.equals(fromBackToken, mBackwardTopToken) || TextUtils.equals(fromBackToken, Event.PAGINATE_BACK_TOKEN_END); + + final android.os.Handler handler = new android.os.Handler(Looper.getMainLooper()); + final int maxEventsCount; + + if (useCachedOnly) { + Log.d(LOG_TAG, "backPaginate : load " + mSnapshotEvents.size() + "cached events list"); + maxEventsCount = Math.min(mSnapshotEvents.size(), eventCount); + } else if ((mSnapshotEvents.size() >= eventCount)) { + Log.d(LOG_TAG, "backPaginate : the events are already loaded."); + maxEventsCount = eventCount; + } else { + Log.d(LOG_TAG, "backPaginate : reach the history top"); + maxEventsCount = eventCount; + } + + // call the callback with a delay + // to reproduce the same behaviour as a network request. + Runnable r = new Runnable() { + @Override + public void run() { + handler.postDelayed(new Runnable() { + public void run() { + manageBackEvents(maxEventsCount, callback); + } + }, 0); + } + }; + + Thread t = new Thread(r); + t.start(); + + return true; + } + + mDataHandler.getDataRetriever().backPaginate(mStore, mRoomId, getBackState().getToken(), eventCount, mDataHandler.isLazyLoadingEnabled(), + new SimpleApiCallback(callback) { + @Override + public void onSuccess(TokensChunkEvents response) { + if (mDataHandler.isAlive()) { + + if (null != response.chunk) { + Log.d(LOG_TAG, "backPaginate : " + response.chunk.size() + " events are retrieved."); + } else { + Log.d(LOG_TAG, "backPaginate : there is no event"); + } + + mIsLastBackChunk = ((null != response.chunk) + && (0 == response.chunk.size()) + && TextUtils.equals(response.end, response.start)) + || (null == response.end); + + if (mIsLastBackChunk && (null != response.end)) { + // save its token to avoid useless request + mBackwardTopToken = fromBackToken; + } else { + // the server returns a null pagination token when there is no more available data + if (null == response.end) { + getBackState().setToken(Event.PAGINATE_BACK_TOKEN_END); + } else { + getBackState().setToken(response.end); + } + } + + addPaginationEvents((null == response.chunk) ? new ArrayList() : response.chunk, + response.stateEvents, + Direction.BACKWARDS, + callback); + + } else { + Log.d(LOG_TAG, "mDataHandler is not active."); + } + } + + @Override + public void onMatrixError(MatrixError e) { + Log.d(LOG_TAG, "backPaginate onMatrixError"); + + // When we've retrieved all the messages from a room, the pagination token is some invalid value + if (MatrixError.UNKNOWN.equals(e.errcode)) { + mCanBackPaginate = false; + } + mIsBackPaginating = false; + + super.onMatrixError(e); + } + + @Override + public void onNetworkError(Exception e) { + Log.d(LOG_TAG, "backPaginate onNetworkError"); + + mIsBackPaginating = false; + + super.onNetworkError(e); + } + + @Override + public void onUnexpectedError(Exception e) { + Log.d(LOG_TAG, "backPaginate onUnexpectedError"); + + mIsBackPaginating = false; + + super.onUnexpectedError(e); + } + }); + + return true; + } + + /** + * Request older messages. + * + * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. + * @return true if request starts + */ + @Override + public boolean forwardPaginate(final ApiCallback callback) { + if (mIsLiveTimeline) { + Log.d(LOG_TAG, "Cannot forward paginate on Live timeline"); + return false; + } + + if (mIsForwardPaginating || mHasReachedHomeServerForwardsPaginationEnd) { + Log.d(LOG_TAG, "forwardPaginate " + mIsForwardPaginating + + " mHasReachedHomeServerForwardsPaginationEnd " + mHasReachedHomeServerForwardsPaginationEnd); + return false; + } + + mIsForwardPaginating = true; + + mDataHandler.getDataRetriever().paginate(mStore, mRoomId, mForwardsPaginationToken, Direction.FORWARDS, mDataHandler.isLazyLoadingEnabled(), + new SimpleApiCallback(callback) { + @Override + public void onSuccess(TokensChunkEvents response) { + if (mDataHandler.isAlive()) { + Log.d(LOG_TAG, "forwardPaginate : " + response.chunk.size() + " are retrieved."); + + mHasReachedHomeServerForwardsPaginationEnd = (0 == response.chunk.size()) && TextUtils.equals(response.end, response.start); + mForwardsPaginationToken = response.end; + + addPaginationEvents(response.chunk, + response.stateEvents, + Direction.FORWARDS, + callback); + + mIsForwardPaginating = false; + } else { + Log.d(LOG_TAG, "mDataHandler is not active."); + } + } + + @Override + public void onMatrixError(MatrixError e) { + mIsForwardPaginating = false; + + super.onMatrixError(e); + } + + @Override + public void onNetworkError(Exception e) { + mIsForwardPaginating = false; + + super.onNetworkError(e); + } + + @Override + public void onUnexpectedError(Exception e) { + mIsForwardPaginating = false; + + super.onUnexpectedError(e); + } + }); + + return true; + } + + /** + * Trigger a pagination in the expected direction. + * + * @param direction the direction. + * @param callback the callback. + * @return true if the operation succeeds + */ + @Override + public boolean paginate(Direction direction, final ApiCallback callback) { + if (Direction.BACKWARDS == direction) { + return backPaginate(callback); + } else { + return forwardPaginate(callback); + } + } + + /** + * Cancel any pending pagination requests + */ + @Override + public void cancelPaginationRequest() { + mDataHandler.getDataRetriever().cancelHistoryRequest(mRoomId); + mIsBackPaginating = false; + mIsForwardPaginating = false; + } + + //============================================================================================================== + // pagination methods + //============================================================================================================== + + /** + * Reset the pagination timelime and start loading the context around its `initialEventId`. + * The retrieved (backwards and forwards) events will be sent to registered listeners. + * + * @param limit the maximum number of messages to get around the initial event. + * @param callback the operation callback + */ + @Override + public void resetPaginationAroundInitialEvent(final int limit, final ApiCallback callback) { + // Reset the store + mStore.deleteRoomData(mRoomId); + + mDataHandler.resetReplayAttackCheckInTimeline(getTimelineId()); + + mForwardsPaginationToken = null; + mHasReachedHomeServerForwardsPaginationEnd = false; + + mDataHandler.getDataRetriever() + .getRoomsRestClient() + .getContextOfEvent(mRoomId, mInitialEventId, limit, FilterUtil.createRoomEventFilter(mDataHandler.isLazyLoadingEnabled()), + new SimpleApiCallback(callback) { + @Override + public void onSuccess(final EventContext eventContext) { + + AsyncTask task = new AsyncTask() { + @Override + protected Void doInBackground(Void... params) { + // the state is the one after the latest event of the chunk i.e. the last message of eventContext.eventsAfter + for (Event event : eventContext.state) { + processStateEvent(event, Direction.FORWARDS); + } + + // init the room states + initHistory(); + + // build the events list + List events = new ArrayList<>(); + + Collections.reverse(eventContext.eventsAfter); + events.addAll(eventContext.eventsAfter); + events.add(eventContext.event); + events.addAll(eventContext.eventsBefore); + + // add events after + addPaginationEvents(events, null, Direction.BACKWARDS); + + return null; + } + + @Override + protected void onPostExecute(Void args) { + // create dummy forward events list + // to center the selected event id + // else if might be out of screen + List nextSnapshotEvents = new ArrayList<>(mSnapshotEvents.subList(0, (mSnapshotEvents.size() + 1) / 2)); + + // put in the right order + Collections.reverse(nextSnapshotEvents); + + // send them one by one + for (SnapshotEvent snapshotEvent : nextSnapshotEvents) { + mSnapshotEvents.remove(snapshotEvent); + mEventListeners.onEvent(snapshotEvent.mEvent, Direction.FORWARDS, snapshotEvent.mState); + } + + // init the tokens + getBackState().setToken(eventContext.start); + mForwardsPaginationToken = eventContext.end; + + // send the back events to complete pagination + manageBackEvents(MAX_EVENT_COUNT_PER_PAGINATION, new ApiCallback() { + @Override + public void onSuccess(Integer info) { + Log.d(LOG_TAG, "addPaginationEvents succeeds"); + } + + @Override + public void onNetworkError(Exception e) { + Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage(), e); + } + + @Override + public void onMatrixError(MatrixError e) { + Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage()); + } + + @Override + public void onUnexpectedError(Exception e) { + Log.e(LOG_TAG, "addPaginationEvents failed " + e.getMessage(), e); + } + }); + + // everything is done + callback.onSuccess(null); + } + }; + + try { + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } catch (final Exception e) { + Log.e(LOG_TAG, "## resetPaginationAroundInitialEvent() failed " + e.getMessage(), e); + task.cancel(true); + + (new android.os.Handler(Looper.getMainLooper())).post(new Runnable() { + @Override + public void run() { + if (callback != null) { + callback.onUnexpectedError(e); + } + } + }); + } + } + }); + } + + //============================================================================================================== + // onEvent listener management. + //============================================================================================================== + + /** + * Add an events listener. + * + * @param listener the listener to add. + */ + @Override + public void addEventTimelineListener(EventTimelineListener listener) { + mEventListeners.add(listener); + } + + /** + * Remove an events listener. + * + * @param listener the listener to remove. + */ + @Override + public void removeEventTimelineListener(EventTimelineListener listener) { + mEventListeners.remove(listener); + } +} diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java index 2d93accb2..b1aafd17b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java @@ -38,10 +38,10 @@ class StateEventRedactionChecker { private static final String LOG_TAG = StateEventRedactionChecker.class.getSimpleName(); - private final IEventTimeline mEventTimeline; + private final EventTimeline mEventTimeline; private final TimelineStateHolder mTimelineStateHolder; - StateEventRedactionChecker(@NonNull final IEventTimeline eventTimeline, @NonNull final TimelineStateHolder timelineStateHolder) { + StateEventRedactionChecker(@NonNull final EventTimeline eventTimeline, @NonNull final TimelineStateHolder timelineStateHolder) { mEventTimeline = eventTimeline; mTimelineStateHolder = timelineStateHolder; } @@ -78,7 +78,7 @@ public void onSuccess(List stateEvents) { stateEvent.prune(redactionEvent); stateEvents.set(index, stateEvent); // digest the updated state - mTimelineStateHolder.processStateEvent(stateEvent, IEventTimeline.Direction.FORWARDS); + mTimelineStateHolder.processStateEvent(stateEvent, EventTimeline.Direction.FORWARDS); isFound = true; break; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java index 31c0787ba..118830a33 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java @@ -37,14 +37,14 @@ public class TimelineEventListeners { private static final String LOG_TAG = TimelineEventListeners.class.getSimpleName(); // The inner listeners - private final List mEventTimelineListeners = new ArrayList<>(); + private final List mEventTimelineListeners = new ArrayList<>(); /** * Add an events listener. * * @param listener the listener to add. */ - public void add(@Nullable final IEventTimeline.EventTimelineListener listener) { + public void add(@Nullable final EventTimeline.EventTimelineListener listener) { if (listener != null) { synchronized (this) { if (mEventTimelineListeners.indexOf(listener) == -1) { @@ -59,7 +59,7 @@ public void add(@Nullable final IEventTimeline.EventTimelineListener listener) { * * @param listener the listener to remove. */ - public void remove(@Nullable final IEventTimeline.EventTimelineListener listener) { + public void remove(@Nullable final EventTimeline.EventTimelineListener listener) { if (null != listener) { synchronized (this) { mEventTimelineListeners.remove(listener); @@ -75,15 +75,15 @@ public void remove(@Nullable final IEventTimeline.EventTimelineListener listener * @param roomState the roomState. */ public void onEvent(@NonNull final Event event, - @NonNull final IEventTimeline.Direction direction, + @NonNull final EventTimeline.Direction direction, @NonNull final RoomState roomState) { // ensure that the listeners are called in the UI thread if (Looper.getMainLooper().getThread() == Thread.currentThread()) { - final List listeners; + final List listeners; synchronized (this) { listeners = new ArrayList<>(mEventTimelineListeners); } - for (IEventTimeline.EventTimelineListener listener : listeners) { + for (EventTimeline.EventTimelineListener listener : listeners) { try { listener.onEvent(event, direction, roomState); } catch (Exception e) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java index 22caa0107..78810528a 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java @@ -28,11 +28,15 @@ class TimelineEventSaver { - private final IEventTimeline mEventTimeline; + private final IMXStore mStore; + private final Room mRoom; private final TimelineStateHolder mTimelineStateHolder; - TimelineEventSaver(@NonNull final IEventTimeline eventTimeline, @NonNull final TimelineStateHolder timelineStateHolder) { - mEventTimeline = eventTimeline; + TimelineEventSaver(@NonNull final IMXStore store, + @NonNull final Room room, + @NonNull final TimelineStateHolder timelineStateHolder) { + mStore = store; + mRoom = room; mTimelineStateHolder = timelineStateHolder; } @@ -43,26 +47,24 @@ class TimelineEventSaver { */ public void storeEvent(Event event) { - final IMXStore store = mEventTimeline.getStore(); - final Room room = mEventTimeline.getRoom(); - final MXDataHandler dataHandler = room.getDataHandler(); + final MXDataHandler dataHandler = mRoom.getDataHandler(); final String myUserId = dataHandler.getCredentials().userId; // create dummy read receipt for any incoming event // to avoid not synchronized read receipt and event if ((null != event.getSender()) && (null != event.eventId)) { - room.handleReceiptData(new ReceiptData(event.getSender(), event.eventId, event.originServerTs)); + mRoom.handleReceiptData(new ReceiptData(event.getSender(), event.eventId, event.originServerTs)); } - store.storeLiveRoomEvent(event); + mStore.storeLiveRoomEvent(event); if (RoomSummary.isSupportedEvent(event)) { final RoomState roomState = mTimelineStateHolder.getState(); - RoomSummary summary = store.getSummary(event.roomId); + RoomSummary summary = mStore.getSummary(event.roomId); if (null == summary) { summary = new RoomSummary(summary, event, roomState, myUserId); } else { summary.setLatestReceivedEvent(event, roomState); } - store.storeSummary(summary); + mStore.storeSummary(summary); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java index 1b1b93ef7..4d1cdadaf 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java @@ -22,7 +22,6 @@ import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.sync.InvitedRoomSync; -import javax.annotation.Nonnull; import javax.annotation.Nullable; /** @@ -30,14 +29,14 @@ */ class TimelineInvitedRoomSyncHandler { - private final IEventTimeline mEventTimeline; + private final Room mRoom; private final TimelineLiveEventHandler mLiveEventHandler; private final InvitedRoomSync mInvitedRoomSync; - TimelineInvitedRoomSyncHandler(@Nonnull final IEventTimeline eventTimeline, + TimelineInvitedRoomSyncHandler(@NonNull final Room room, @NonNull final TimelineLiveEventHandler liveEventHandler, @Nullable final InvitedRoomSync invitedRoomSync) { - mEventTimeline = eventTimeline; + mRoom = room; mLiveEventHandler = liveEventHandler; mInvitedRoomSync = invitedRoomSync; } @@ -48,8 +47,7 @@ class TimelineInvitedRoomSyncHandler { public void handle() { // Handle the state events as live events (the room state will be updated, and the listeners (if any) will be notified). if ((mInvitedRoomSync != null) && (mInvitedRoomSync.inviteState != null) && (mInvitedRoomSync.inviteState.events != null)) { - final Room room = mEventTimeline.getRoom(); - final String roomId = room.getRoomId(); + final String roomId = mRoom.getRoomId(); for (Event event : mInvitedRoomSync.inviteState.events) { // Add a fake event id if none in order to be able to store the event @@ -62,7 +60,7 @@ public void handle() { mLiveEventHandler.handleLiveEvent(event, false, true); } // The room related to the pending invite can be considered as ready from now - room.setReadyState(true); + mRoom.setReadyState(true); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java index f333dbc01..24f922ffc 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java @@ -25,13 +25,13 @@ class TimelineJoinRoomSyncHandler { private static final String LOG_TAG = TimelineJoinRoomSyncHandler.class.getSimpleName(); - private final IEventTimeline mEventTimeline; + private final MXEventTimeline mEventTimeline; private final RoomSync mRoomSync; private final TimelineStateHolder mTimelineStateHolder; private final TimelineLiveEventHandler mTimelineLiveEventHandler; private final boolean mIsGlobalInitialSync; - TimelineJoinRoomSyncHandler(@NonNull final IEventTimeline eventTimeline, + TimelineJoinRoomSyncHandler(@NonNull final MXEventTimeline eventTimeline, @NonNull final RoomSync roomSync, @NonNull final TimelineStateHolder timelineStateHolder, @NonNull final TimelineLiveEventHandler timelineLiveEventHandler, diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java index 0b2f0f613..f9cd2c827 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java @@ -41,14 +41,14 @@ class TimelineLiveEventHandler { private static final String LOG_TAG = TimelineLiveEventHandler.class.getSimpleName(); - private final IEventTimeline mEventTimeline; + private final MXEventTimeline mEventTimeline; private final TimelineEventSaver mTimelineEventSaver; private final StateEventRedactionChecker mStateEventRedactionChecker; private final TimelinePushWorker mTimelinePushWorker; private final TimelineStateHolder mTimelineStateHolder; private final TimelineEventListeners mEventListeners; - TimelineLiveEventHandler(@Nonnull final IEventTimeline eventTimeline, + TimelineLiveEventHandler(@Nonnull final MXEventTimeline eventTimeline, @Nonnull final TimelineEventSaver timelineEventSaver, @Nonnull final StateEventRedactionChecker stateEventRedactionChecker, @Nonnull final TimelinePushWorker timelinePushWorker, @@ -91,7 +91,7 @@ public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolea // general listeners dataHandler.onLiveEvent(event, roomState); // timeline listeners - mEventListeners.onEvent(event, IEventTimeline.Direction.FORWARDS, roomState); + mEventListeners.onEvent(event, EventTimeline.Direction.FORWARDS, roomState); } // trigger pushes when it is required @@ -160,9 +160,9 @@ public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolea final RoomState previousState = mTimelineStateHolder.getState(); if (event.stateKey != null) { // copy the live state before applying any update - mTimelineStateHolder.deepCopyState(IEventTimeline.Direction.FORWARDS); + mTimelineStateHolder.deepCopyState(EventTimeline.Direction.FORWARDS); // check if the event has been processed - if (!mTimelineStateHolder.processStateEvent(event, IEventTimeline.Direction.FORWARDS)) { + if (!mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.FORWARDS)) { // not processed -> do not warn the application // assume that the event is a duplicated one. return; @@ -175,7 +175,7 @@ public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolea dataHandler.onLiveEvent(event, previousState); // timeline listeners - mEventListeners.onEvent(event, IEventTimeline.Direction.FORWARDS, previousState); + mEventListeners.onEvent(event, EventTimeline.Direction.FORWARDS, previousState); // trigger pushes when it is required if (withPush) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java index 505768e84..112049149 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java @@ -92,8 +92,8 @@ public void setBackState(@NonNull final RoomState state) { * * @param direction the room state direction to deep copy. */ - public void deepCopyState(final IEventTimeline.Direction direction) { - if (direction == IEventTimeline.Direction.FORWARDS) { + public void deepCopyState(final EventTimeline.Direction direction) { + if (direction == EventTimeline.Direction.FORWARDS) { mState = mState.deepCopy(); } else { mBackState = mBackState.deepCopy(); @@ -107,10 +107,10 @@ public void deepCopyState(final IEventTimeline.Direction direction) { * @param direction the direction; ie. forwards for live state, backwards for back state * @return true if the event has been processed. */ - public boolean processStateEvent(@NonNull final Event event, final IEventTimeline.Direction direction) { - final RoomState affectedState = (direction == IEventTimeline.Direction.FORWARDS) ? mState : mBackState; + public boolean processStateEvent(@NonNull final Event event, final EventTimeline.Direction direction) { + final RoomState affectedState = (direction == EventTimeline.Direction.FORWARDS) ? mState : mBackState; boolean isProcessed = affectedState.applyState(mStore, event, direction); - if (isProcessed && direction == IEventTimeline.Direction.FORWARDS) { + if (isProcessed && direction == EventTimeline.Direction.FORWARDS) { mStore.storeLiveStateForRoom(mRoomId); } return isProcessed; From 8eee1f56bcc7060b7cdf59caef4759b37bd63738 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 26 Sep 2018 19:26:12 +0200 Subject: [PATCH 208/236] Timeline : add unit test for StateHolder --- .../timeline/TimelineStateHolderTest.java | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelineStateHolderTest.java diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelineStateHolderTest.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelineStateHolderTest.java new file mode 100644 index 000000000..31128f090 --- /dev/null +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelineStateHolderTest.java @@ -0,0 +1,102 @@ +package org.matrix.androidsdk.data.timeline; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.matrix.androidsdk.MXDataHandler; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.data.store.IMXStore; +import org.matrix.androidsdk.rest.model.Event; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +import static org.matrix.androidsdk.rest.model.Event.EVENT_TYPE_STATE_ROOM_NAME; + +@RunWith(RobolectricTestRunner.class) +public class TimelineStateHolderTest { + + private static final String ROOM_ID = "roomId"; + + @Mock + MXDataHandler mDataHandler; + @Mock + IMXStore mIMXStore; + + private TimelineStateHolder mTimelineStateHolder; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mTimelineStateHolder = new TimelineStateHolder(mDataHandler, mIMXStore, ROOM_ID); + } + + @Test + public void State_WhenProcessForward__ShouldStoreLiveState() { + final Event event = new Event(); + event.roomId = ROOM_ID; + event.stateKey = EVENT_TYPE_STATE_ROOM_NAME; + event.type = EVENT_TYPE_STATE_ROOM_NAME; + mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.FORWARDS); + Mockito.verify(mIMXStore, Mockito.times(1)).storeLiveStateForRoom(Mockito.anyString()); + } + + @Test + public void State_WhenProcessWithNoStateKey__ShouldNotBeProcessed() { + final Event event = new Event(); + event.roomId = ROOM_ID; + event.type = EVENT_TYPE_STATE_ROOM_NAME; + Assert.assertFalse(mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.FORWARDS)); + } + + @Test + public void State_WhenProcessForward__ShouldUseState() { + final Event event = new Event(); + event.roomId = ROOM_ID; + event.stateKey = EVENT_TYPE_STATE_ROOM_NAME; + event.type = EVENT_TYPE_STATE_ROOM_NAME; + final RoomState state = Mockito.spy(mTimelineStateHolder.getState()); + mTimelineStateHolder.setState(state); + mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.FORWARDS); + Mockito.verify(state).applyState(mIMXStore, event, EventTimeline.Direction.FORWARDS); + } + + @Test + public void State_WhenProcessBackward__ShouldUseBackState() { + final Event event = new Event(); + event.roomId = ROOM_ID; + event.stateKey = EVENT_TYPE_STATE_ROOM_NAME; + event.type = EVENT_TYPE_STATE_ROOM_NAME; + final RoomState backState = Mockito.spy(mTimelineStateHolder.getBackState()); + mTimelineStateHolder.setBackState(backState); + mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.BACKWARDS); + Mockito.verify(backState).applyState(mIMXStore, event, EventTimeline.Direction.BACKWARDS); + } + + @Test + public void State_WhenDeepCopyForward__ShouldUseState() { + final RoomState state = Mockito.spy(new RoomState()); + final RoomState backState = Mockito.spy(new RoomState()); + mTimelineStateHolder.setState(state); + mTimelineStateHolder.setBackState(backState); + mTimelineStateHolder.deepCopyState(EventTimeline.Direction.FORWARDS); + Mockito.verify(state).deepCopy(); + Mockito.verify(backState, Mockito.never()).deepCopy(); + } + + @Test + public void State_WhenDeepCopyBackward__ShouldUseBackState() { + final RoomState state = Mockito.spy(new RoomState()); + final RoomState backState = Mockito.spy(new RoomState()); + mTimelineStateHolder.setState(state); + mTimelineStateHolder.setBackState(backState); + mTimelineStateHolder.deepCopyState(EventTimeline.Direction.BACKWARDS); + Mockito.verify(backState).deepCopy(); + Mockito.verify(state, Mockito.never()).deepCopy(); + } + + +} From 743200805e868ec891eca125a7a299fdbbc1f672 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 27 Sep 2018 11:46:50 +0200 Subject: [PATCH 209/236] EventTimeline : clean files --- .../data/timeline/EventTimeline.java | 6 +- .../data/timeline/EventTimelineFactory.java | 11 ++- .../data/timeline/MXEventTimeline.java | 76 ++++++++++--------- .../timeline/StateEventRedactionChecker.java | 7 +- .../data/timeline/TimelineEventListeners.java | 2 +- .../data/timeline/TimelineEventSaver.java | 9 ++- .../TimelineInvitedRoomSyncHandler.java | 4 +- .../timeline/TimelineJoinRoomSyncHandler.java | 24 +++--- .../timeline/TimelineLiveEventHandler.java | 18 +++-- .../data/timeline/TimelinePushWorker.java | 4 +- .../data/timeline/TimelineStateHolder.java | 17 ++++- 11 files changed, 99 insertions(+), 79 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java index 509e69df5..7f1958dc8 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java @@ -174,7 +174,7 @@ public interface EventTimeline { * @param callback the callback. * @return true if the operation succeeds */ - boolean paginate(EventTimeline.Direction direction, ApiCallback callback); + boolean paginate(Direction direction, ApiCallback callback); /** * Cancel any pending pagination requests @@ -195,14 +195,14 @@ public interface EventTimeline { * * @param listener the listener to add. */ - void addEventTimelineListener(EventTimeline.EventTimelineListener listener); + void addEventTimelineListener(EventTimelineListener listener); /** * Remove an events listener. * * @param listener the listener to remove. */ - void removeEventTimelineListener(EventTimeline.EventTimelineListener listener); + void removeEventTimelineListener(EventTimelineListener listener); /** * The direction from which an incoming event is considered. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java index ef4e50fbf..c7af892a1 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java @@ -44,9 +44,8 @@ public static EventTimeline liveTimeline(@NonNull final MXDataHandler dataHandle * @param dataHandler the data handler * @param roomId the room id. */ - public static EventTimeline pastTimeline( - @NonNull MXDataHandler dataHandler, - @NonNull String roomId) { + public static EventTimeline pastTimeline(@NonNull final MXDataHandler dataHandler, + @NonNull final String roomId) { return pastTimeline(dataHandler, roomId, null); } @@ -58,9 +57,9 @@ public static EventTimeline pastTimeline( * @param roomId the room id. * @param eventId the event id */ - public static EventTimeline pastTimeline(@NonNull MXDataHandler dataHandler, - @NonNull String roomId, - @Nullable String eventId) { + public static EventTimeline pastTimeline(@NonNull final MXDataHandler dataHandler, + @NonNull final String roomId, + @Nullable final String eventId) { final MXMemoryStore store = new MXMemoryStore(dataHandler.getCredentials(), null); final Room room = dataHandler.getRoom(store, roomId, true); final EventTimeline eventTimeline = new MXEventTimeline(store, dataHandler, room, roomId, eventId, false); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java index 9ce27f3da..0bb68a66e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java @@ -45,18 +45,8 @@ import java.util.List; /** - * A `EventTimeline` instance represents a contiguous sequence of events in a room. - *

    - * There are two kinds of timeline: - *

    - * - live timelines: they receive live events from the events stream. You can paginate - * backwards but not forwards. - * All (live or backwards) events they receive are stored in the store of the current - * MXSession. - *

    - * - past timelines: they start in the past from an `initialEventId`. They are filled - * with events on calls of [MXEventTimeline paginate] in backwards or forwards direction. - * Events are stored in a in-memory store (MXMemoryStore). + * A private implementation of EventTimeline interface. It's not exposed as you don't have to directly instantiate it. + * Should be instantiated through EventTimelineFactory. */ class MXEventTimeline implements EventTimeline { private static final String LOG_TAG = MXEventTimeline.class.getSimpleName(); @@ -130,9 +120,24 @@ class MXEventTimeline implements EventTimeline { */ private final String mTimelineId = System.currentTimeMillis() + ""; + /** + * * This class handles storing a live room event in a dedicated store. + */ private final TimelineEventSaver mTimelineEventSaver; + + /** + * This class is responsible for holding the state and backState of a room timeline + */ private final TimelineStateHolder mStateHolder; + + /** + * This class handle the timeline event listeners + */ private final TimelineEventListeners mEventListeners; + + /** + * This class is responsible for handling events coming down from the event stream. + */ private final TimelineLiveEventHandler mLiveEventHandler; /** @@ -253,7 +258,7 @@ public void initHistory() { mIsForwardPaginating = false; // sanity check - if ((null != mDataHandler) && (null != mDataHandler.getDataRetriever())) { + if (null != mDataHandler && null != mDataHandler.getDataRetriever()) { mDataHandler.resetReplayAttackCheckInTimeline(getTimelineId()); mDataHandler.getDataRetriever().cancelHistoryRequest(mRoomId); } @@ -344,7 +349,8 @@ public void handleJoinedRoomSync(@NonNull final RoomSync roomSync, final boolean final TimelineJoinRoomSyncHandler joinRoomSyncHandler = new TimelineJoinRoomSyncHandler(this, roomSync, mStateHolder, - mLiveEventHandler, isGlobalInitialSync); + mLiveEventHandler, + isGlobalInitialSync); joinRoomSyncHandler.handle(); } @@ -414,7 +420,7 @@ private void manageBackEvents(int maxEventCount, final ApiCallback call // in some cases, there is no displayed summary // https://github.com/vector-im/vector-android/pull/354 - if ((null == latestSupportedEvent) && RoomSummary.isSupportedEvent(snapshotedEvent.mEvent)) { + if (null == latestSupportedEvent && RoomSummary.isSupportedEvent(snapshotedEvent.mEvent)) { latestSupportedEvent = snapshotedEvent.mEvent; } @@ -426,14 +432,14 @@ private void manageBackEvents(int maxEventCount, final ApiCallback call // defines a new summary if the known is not supported RoomSummary summary = mStore.getSummary(mRoomId); - if ((null != latestSupportedEvent) && ((null == summary) || !RoomSummary.isSupportedEvent(summary.getLatestReceivedEvent()))) { + if (null != latestSupportedEvent && (null == summary || !RoomSummary.isSupportedEvent(summary.getLatestReceivedEvent()))) { mStore.storeSummary(new RoomSummary(null, latestSupportedEvent, getState(), mDataHandler.getUserId())); } Log.d(LOG_TAG, "manageEvents : commit"); mStore.commit(); - if ((mSnapshotEvents.size() < MAX_EVENT_COUNT_PER_PAGINATION) && mIsLastBackChunk) { + if (mSnapshotEvents.size() < MAX_EVENT_COUNT_PER_PAGINATION && mIsLastBackChunk) { mCanBackPaginate = false; } mIsBackPaginating = false; @@ -490,11 +496,11 @@ private void addPaginationEvents(List events, if (mIsLiveTimeline) { // update the summary is the event has been received after the oldest known event // it might happen after a timeline update (hole in the chat history) - if ((null != summary) - && ((null == summary.getLatestReceivedEvent()) - || (event.isValidOriginServerTs() - && (summary.getLatestReceivedEvent().originServerTs < event.originServerTs) - && RoomSummary.isSupportedEvent(event)))) { + if (null != summary + && (null == summary.getLatestReceivedEvent() + || event.isValidOriginServerTs() + && summary.getLatestReceivedEvent().originServerTs < event.originServerTs + && RoomSummary.isSupportedEvent(event))) { summary.setLatestReceivedEvent(event, getState()); mStore.storeSummary(summary); shouldCommitStore = true; @@ -552,7 +558,7 @@ protected void onPostExecute(Void args) { Log.e(LOG_TAG, "## addPaginationEvents() failed " + e.getMessage(), e); task.cancel(true); - (new android.os.Handler(Looper.getMainLooper())).post(new Runnable() { + new android.os.Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { if (null != callback) { @@ -632,7 +638,7 @@ public boolean backPaginate(final int eventCount, final boolean useCachedOnly, f // enough buffered data if (useCachedOnly - || (mSnapshotEvents.size() >= eventCount) + || mSnapshotEvents.size() >= eventCount || TextUtils.equals(fromBackToken, mBackwardTopToken) || TextUtils.equals(fromBackToken, Event.PAGINATE_BACK_TOKEN_END)) { @@ -644,7 +650,7 @@ public boolean backPaginate(final int eventCount, final boolean useCachedOnly, f if (useCachedOnly) { Log.d(LOG_TAG, "backPaginate : load " + mSnapshotEvents.size() + "cached events list"); maxEventsCount = Math.min(mSnapshotEvents.size(), eventCount); - } else if ((mSnapshotEvents.size() >= eventCount)) { + } else if (mSnapshotEvents.size() >= eventCount) { Log.d(LOG_TAG, "backPaginate : the events are already loaded."); maxEventsCount = eventCount; } else { @@ -683,12 +689,12 @@ public void onSuccess(TokensChunkEvents response) { Log.d(LOG_TAG, "backPaginate : there is no event"); } - mIsLastBackChunk = ((null != response.chunk) - && (0 == response.chunk.size()) - && TextUtils.equals(response.end, response.start)) - || (null == response.end); + mIsLastBackChunk = null != response.chunk + && 0 == response.chunk.size() + && TextUtils.equals(response.end, response.start) + || null == response.end; - if (mIsLastBackChunk && (null != response.end)) { + if (mIsLastBackChunk && null != response.end) { // save its token to avoid useless request mBackwardTopToken = fromBackToken; } else { @@ -700,7 +706,7 @@ public void onSuccess(TokensChunkEvents response) { } } - addPaginationEvents((null == response.chunk) ? new ArrayList() : response.chunk, + addPaginationEvents(null == response.chunk ? new ArrayList() : response.chunk, response.stateEvents, Direction.BACKWARDS, callback); @@ -773,7 +779,7 @@ public void onSuccess(TokensChunkEvents response) { if (mDataHandler.isAlive()) { Log.d(LOG_TAG, "forwardPaginate : " + response.chunk.size() + " are retrieved."); - mHasReachedHomeServerForwardsPaginationEnd = (0 == response.chunk.size()) && TextUtils.equals(response.end, response.start); + mHasReachedHomeServerForwardsPaginationEnd = 0 == response.chunk.size() && TextUtils.equals(response.end, response.start); mForwardsPaginationToken = response.end; addPaginationEvents(response.chunk, @@ -945,7 +951,7 @@ public void onUnexpectedError(Exception e) { Log.e(LOG_TAG, "## resetPaginationAroundInitialEvent() failed " + e.getMessage(), e); task.cancel(true); - (new android.os.Handler(Looper.getMainLooper())).post(new Runnable() { + new android.os.Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { if (callback != null) { @@ -968,7 +974,7 @@ public void run() { * @param listener the listener to add. */ @Override - public void addEventTimelineListener(EventTimelineListener listener) { + public void addEventTimelineListener(@Nullable final EventTimelineListener listener) { mEventListeners.add(listener); } @@ -978,7 +984,7 @@ public void addEventTimelineListener(EventTimelineListener listener) { * @param listener the listener to remove. */ @Override - public void removeEventTimelineListener(EventTimelineListener listener) { + public void removeEventTimelineListener(@Nullable final EventTimelineListener listener) { mEventListeners.remove(listener); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java index b1aafd17b..8c2d00d45 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java @@ -41,7 +41,8 @@ class StateEventRedactionChecker { private final EventTimeline mEventTimeline; private final TimelineStateHolder mTimelineStateHolder; - StateEventRedactionChecker(@NonNull final EventTimeline eventTimeline, @NonNull final TimelineStateHolder timelineStateHolder) { + StateEventRedactionChecker(@NonNull final EventTimeline eventTimeline, + @NonNull final TimelineStateHolder timelineStateHolder) { mEventTimeline = eventTimeline; mTimelineStateHolder = timelineStateHolder; } @@ -52,7 +53,7 @@ class StateEventRedactionChecker { * * @param redactionEvent the redaction event */ - public void checkStateEventRedaction(final Event redactionEvent) { + public void checkStateEventRedaction(@NonNull final Event redactionEvent) { final IMXStore store = mEventTimeline.getStore(); final Room room = mEventTimeline.getRoom(); final MXDataHandler dataHandler = room.getDataHandler(); @@ -141,7 +142,7 @@ private void checkStateEventRedactionWithHomeserver(@Nonnull final MXDataHandler dataHandler.getDataRetriever().getRoomsRestClient().getEvent(roomId, eventId, new ApiCallback() { @Override public void onSuccess(Event event) { - if ((null != event) && (null != event.stateKey)) { + if (null != event && null != event.stateKey) { Log.d(LOG_TAG, "checkStateEventRedactionWithHomeserver : the redacted event is a state event in the past." + " TODO: prune prev_content of the new state event"); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java index 118830a33..fab2d5701 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java @@ -32,7 +32,7 @@ * Handle the timeline event listeners * Is responsible for dispatching events */ -public class TimelineEventListeners { +class TimelineEventListeners { private static final String LOG_TAG = TimelineEventListeners.class.getSimpleName(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java index 78810528a..74ee1df1e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventSaver.java @@ -26,6 +26,9 @@ import org.matrix.androidsdk.rest.model.Event; import org.matrix.androidsdk.rest.model.ReceiptData; +/** + * This class handles storing a live room event in a dedicated store. + */ class TimelineEventSaver { private final IMXStore mStore; @@ -46,20 +49,20 @@ class TimelineEventSaver { * @param event the event to be stored. */ - public void storeEvent(Event event) { + public void storeEvent(@NonNull final Event event) { final MXDataHandler dataHandler = mRoom.getDataHandler(); final String myUserId = dataHandler.getCredentials().userId; // create dummy read receipt for any incoming event // to avoid not synchronized read receipt and event - if ((null != event.getSender()) && (null != event.eventId)) { + if (event.getSender() != null && event.eventId != null) { mRoom.handleReceiptData(new ReceiptData(event.getSender(), event.eventId, event.originServerTs)); } mStore.storeLiveRoomEvent(event); if (RoomSummary.isSupportedEvent(event)) { final RoomState roomState = mTimelineStateHolder.getState(); RoomSummary summary = mStore.getSummary(event.roomId); - if (null == summary) { + if (summary == null) { summary = new RoomSummary(summary, event, roomState, myUserId); } else { summary.setLatestReceivedEvent(event, roomState); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java index 4d1cdadaf..65a781dec 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineInvitedRoomSyncHandler.java @@ -46,12 +46,12 @@ class TimelineInvitedRoomSyncHandler { */ public void handle() { // Handle the state events as live events (the room state will be updated, and the listeners (if any) will be notified). - if ((mInvitedRoomSync != null) && (mInvitedRoomSync.inviteState != null) && (mInvitedRoomSync.inviteState.events != null)) { + if (mInvitedRoomSync != null && mInvitedRoomSync.inviteState != null && mInvitedRoomSync.inviteState.events != null) { final String roomId = mRoom.getRoomId(); for (Event event : mInvitedRoomSync.inviteState.events) { // Add a fake event id if none in order to be able to store the event - if (null == event.eventId) { + if (event.eventId == null) { event.eventId = roomId + "-" + System.currentTimeMillis() + "-" + event.hashCode(); } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java index 24f922ffc..cfc01bdce 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineJoinRoomSyncHandler.java @@ -54,14 +54,14 @@ public void handle() { final RoomSummary currentSummary = store.getSummary(roomId); final String membership = selfMember != null ? selfMember.membership : null; - final boolean isRoomInitialSync = (membership == null) || TextUtils.equals(membership, RoomMember.MEMBERSHIP_INVITE); + final boolean isRoomInitialSync = membership == null || TextUtils.equals(membership, RoomMember.MEMBERSHIP_INVITE); // Check whether the room was pending on an invitation. if (RoomMember.MEMBERSHIP_INVITE.equals(membership)) { // Reset the storage of this room. An initial sync of the room will be done with the provided 'roomSync'. cleanInvitedRoom(store, roomId); } - if ((mRoomSync.state != null) && (mRoomSync.state.events != null) && (mRoomSync.state.events.size() > 0)) { + if (mRoomSync.state != null && mRoomSync.state.events != null && mRoomSync.state.events.size() > 0) { handleRoomSyncState(room, store, isRoomInitialSync); } // Handle now timeline.events, the room state is updated during this step too (Note: timeline events are in chronological order) @@ -83,7 +83,9 @@ public void handle() { } } - private void handleRoomSyncState(@NonNull final Room room, @NonNull final IMXStore store, boolean isRoomInitialSync) { + private void handleRoomSyncState(@NonNull final Room room, + @NonNull final IMXStore store, + final boolean isRoomInitialSync) { if (isRoomInitialSync) { Log.d(LOG_TAG, "##" + mRoomSync.state.events.size() + " events " + "for room " + room.getRoomId() @@ -167,9 +169,8 @@ private void handleRoomSyncTimeline(@NonNull final IMXStore store, } // any event ? - if ((null != mRoomSync.timeline.events) && (mRoomSync.timeline.events.size() > 0)) { - List events = mRoomSync.timeline.events; - + if (mRoomSync.timeline.events != null && !mRoomSync.timeline.events.isEmpty()) { + final List events = mRoomSync.timeline.events; // save the back token events.get(0).mToken = mRoomSync.timeline.prevBatch; @@ -179,7 +180,7 @@ private void handleRoomSyncTimeline(@NonNull final IMXStore store, // the roomId is not defined. event.roomId = roomId; try { - boolean isLimited = (null != mRoomSync.timeline) && mRoomSync.timeline.limited; + boolean isLimited = mRoomSync.timeline != null && mRoomSync.timeline.limited; // digest the forward event mTimelineLiveEventHandler.handleLiveEvent(event, !isLimited && !mIsGlobalInitialSync, !mIsGlobalInitialSync && !isRoomInitialSync); @@ -226,7 +227,7 @@ else if (currentSummary != null) { store.commit(); } // try to build a summary from the state events - else if ((mRoomSync.state != null) && (mRoomSync.state.events != null) && (mRoomSync.state.events.size() > 0)) { + else if (mRoomSync.state != null && mRoomSync.state.events != null && mRoomSync.state.events.size() > 0) { final List events = new ArrayList<>(mRoomSync.state.events); Collections.reverse(events); @@ -255,7 +256,7 @@ else if ((mRoomSync.state != null) && (mRoomSync.state.events != null) && (mRoom notifCount = mRoomSync.unreadNotifications.notificationCount; } - if ((notifCount != state.getNotificationCount()) || (state.getHighlightCount() != highlightCount)) { + if (notifCount != state.getNotificationCount() || state.getHighlightCount() != highlightCount) { Log.d(LOG_TAG, "## handleJoinedRoomSync() : update room state notifs count for room id " + roomId + ": highlightCount " + highlightCount + " - notifCount " + notifCount); @@ -267,9 +268,8 @@ else if ((mRoomSync.state != null) && (mRoomSync.state.events != null) && (mRoom // some users reported that the summary notification counts were sometimes invalid // so check roomstates and summaries separately - RoomSummary summary = store.getSummary(roomId); - - if ((null != summary) && ((notifCount != summary.getNotificationCount()) || (summary.getHighlightCount() != highlightCount))) { + final RoomSummary summary = store.getSummary(roomId); + if (summary != null && (notifCount != summary.getNotificationCount() || summary.getHighlightCount() != highlightCount)) { Log.d(LOG_TAG, "## handleJoinedRoomSync() : update room summary notifs count for room id " + roomId + ": highlightCount " + highlightCount + " - notifCount " + notifCount); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java index f9cd2c827..10e5a0daa 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java @@ -69,7 +69,9 @@ class TimelineLiveEventHandler { * @param checkRedactedStateEvent set to true to check if it triggers a state event redaction * @param withPush set to true to trigger pushes when it is required */ - public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolean withPush) { + public void handleLiveEvent(@NonNull final Event event, + final boolean checkRedactedStateEvent, + final boolean withPush) { final IMXStore store = mEventTimeline.getStore(); final Room room = mEventTimeline.getRoom(); final MXDataHandler dataHandler = room.getDataHandler(); @@ -83,7 +85,7 @@ public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolea if (event.isCallEvent()) { final RoomState roomState = mTimelineStateHolder.getState(); dataHandler.getCallsManager().handleCallEvent(store, event); - storeLiveRoomEvent(dataHandler, store, false, event); + storeLiveRoomEvent(dataHandler, store, event, false); // the candidates events are not tracked // because the users don't need to see the peer exchanges. if (!TextUtils.equals(event.getType(), Event.EVENT_TYPE_CALL_CANDIDATES)) { @@ -103,7 +105,7 @@ public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolea final Event storedEvent = store.getEvent(event.eventId, event.roomId); // avoid processing event twice - if (null != storedEvent) { + if (storedEvent != null) { // an event has been echoed if (storedEvent.getAge() == Event.DUMMY_EVENT_AGE) { store.deleteEvent(storedEvent); @@ -168,7 +170,7 @@ public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolea return; } } - storeLiveRoomEvent(dataHandler, store, checkRedactedStateEvent, event); + storeLiveRoomEvent(dataHandler, store, event, checkRedactedStateEvent); // warn the listeners // general listeners @@ -193,10 +195,10 @@ public void handleLiveEvent(Event event, boolean checkRedactedStateEvent, boolea * @param event The event to be stored. * @param checkRedactedStateEvent true to check if this event redacts a state event */ - private void storeLiveRoomEvent(final MXDataHandler dataHandler, - final IMXStore store, - final boolean checkRedactedStateEvent, - Event event) { + private void storeLiveRoomEvent(@NonNull final MXDataHandler dataHandler, + @NonNull final IMXStore store, + @NonNull Event event, + final boolean checkRedactedStateEvent) { boolean shouldBeSaved = false; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java index 2bed64f64..c3983e372 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java @@ -58,8 +58,8 @@ public void triggerPush(@NonNull final RoomState state, final BingRulesManager bingRulesManager = mDataHandler.getBingRulesManager(); // If the bing rules apply, bing if (!outOfTimeEvent - && (bingRulesManager != null) - && (null != (bingRule = bingRulesManager.fulfilledBingRule(event)))) { + && bingRulesManager != null + && (bingRule = bingRulesManager.fulfilledBingRule(event)) != null) { if (bingRule.shouldNotify()) { // bing the call events only if they make sense diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java index 112049149..06efac789 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineStateHolder.java @@ -42,13 +42,18 @@ class TimelineStateHolder { */ private RoomState mBackState; - TimelineStateHolder(@NonNull final MXDataHandler dataHandler, @NonNull final IMXStore store, final String roomId) { + TimelineStateHolder(@NonNull final MXDataHandler dataHandler, + @NonNull final IMXStore store, + @NonNull final String roomId) { mDataHandler = dataHandler; mStore = store; mRoomId = roomId; initStates(); } + /** + * Clear the states + */ public void clear() { initStates(); } @@ -107,9 +112,10 @@ public void deepCopyState(final EventTimeline.Direction direction) { * @param direction the direction; ie. forwards for live state, backwards for back state * @return true if the event has been processed. */ - public boolean processStateEvent(@NonNull final Event event, final EventTimeline.Direction direction) { - final RoomState affectedState = (direction == EventTimeline.Direction.FORWARDS) ? mState : mBackState; - boolean isProcessed = affectedState.applyState(mStore, event, direction); + public boolean processStateEvent(@NonNull final Event event, + @NonNull final EventTimeline.Direction direction) { + final RoomState affectedState = direction == EventTimeline.Direction.FORWARDS ? mState : mBackState; + final boolean isProcessed = affectedState.applyState(mStore, event, direction); if (isProcessed && direction == EventTimeline.Direction.FORWARDS) { mStore.storeLiveStateForRoom(mRoomId); } @@ -127,6 +133,9 @@ public void setRoomId(@NonNull final String roomId) { mBackState.roomId = roomId; } + /** + * Initialize the state and backState to default, with roomId and dataHandler + */ private void initStates() { mBackState = new RoomState(); mBackState.setDataHandler(mDataHandler); From ef7f098825bc4bb003ccabc4774fdf167ae063f4 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 27 Sep 2018 15:47:10 +0200 Subject: [PATCH 210/236] Timeline : change name of tests of StateHolder class --- .../timeline/TimelineStateHolderTest.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelineStateHolderTest.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelineStateHolderTest.java index 31128f090..aa580aa64 100644 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelineStateHolderTest.java +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelineStateHolderTest.java @@ -35,7 +35,7 @@ public void setUp() { } @Test - public void State_WhenProcessForward__ShouldStoreLiveState() { + public void processStateEvent_WhenDirectionIsForward__ShouldStoreLiveState() { final Event event = new Event(); event.roomId = ROOM_ID; event.stateKey = EVENT_TYPE_STATE_ROOM_NAME; @@ -45,7 +45,7 @@ public void State_WhenProcessForward__ShouldStoreLiveState() { } @Test - public void State_WhenProcessWithNoStateKey__ShouldNotBeProcessed() { + public void processStateEvent_WhenNoStateKeyIsGiven__ShouldNotBeProcessed() { final Event event = new Event(); event.roomId = ROOM_ID; event.type = EVENT_TYPE_STATE_ROOM_NAME; @@ -53,7 +53,16 @@ public void State_WhenProcessWithNoStateKey__ShouldNotBeProcessed() { } @Test - public void State_WhenProcessForward__ShouldUseState() { + public void processStateEvent_WithConformingEvent__ShouldBeProcessed() { + final Event event = new Event(); + event.roomId = ROOM_ID; + event.type = EVENT_TYPE_STATE_ROOM_NAME; + event.stateKey = EVENT_TYPE_STATE_ROOM_NAME; + Assert.assertTrue(mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.FORWARDS)); + } + + @Test + public void processStateEvent_WhenDirectionIsForward__ShouldUseState() { final Event event = new Event(); event.roomId = ROOM_ID; event.stateKey = EVENT_TYPE_STATE_ROOM_NAME; @@ -65,7 +74,7 @@ public void State_WhenProcessForward__ShouldUseState() { } @Test - public void State_WhenProcessBackward__ShouldUseBackState() { + public void processStateEvent_WhenDirectionIsBackward__ShouldUseBackState() { final Event event = new Event(); event.roomId = ROOM_ID; event.stateKey = EVENT_TYPE_STATE_ROOM_NAME; @@ -77,7 +86,7 @@ public void State_WhenProcessBackward__ShouldUseBackState() { } @Test - public void State_WhenDeepCopyForward__ShouldUseState() { + public void deepCopyState_WhenDirectionIsForward__ShouldCopyState() { final RoomState state = Mockito.spy(new RoomState()); final RoomState backState = Mockito.spy(new RoomState()); mTimelineStateHolder.setState(state); @@ -88,7 +97,7 @@ public void State_WhenDeepCopyForward__ShouldUseState() { } @Test - public void State_WhenDeepCopyBackward__ShouldUseBackState() { + public void deepCopyState_WhenDirectionIsBackward__ShouldCopyBackState() { final RoomState state = Mockito.spy(new RoomState()); final RoomState backState = Mockito.spy(new RoomState()); mTimelineStateHolder.setState(state); From 1a3efad337e8c95239bf07ddc764c9f95b5e5ae2 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 27 Sep 2018 15:47:26 +0200 Subject: [PATCH 211/236] Timeline : add push worker tests --- .../data/timeline/TimelinePushWorkerTest.java | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelinePushWorkerTest.java diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelinePushWorkerTest.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelinePushWorkerTest.java new file mode 100644 index 000000000..65445e828 --- /dev/null +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelinePushWorkerTest.java @@ -0,0 +1,119 @@ +/* + * Copyright 2018 New Vector Ltd + * + * 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 org.matrix.androidsdk.data.timeline; + +import com.google.gson.Gson; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.matrix.androidsdk.MXDataHandler; +import org.matrix.androidsdk.data.RoomState; +import org.matrix.androidsdk.rest.model.Event; +import org.matrix.androidsdk.rest.model.bingrules.BingRule; +import org.matrix.androidsdk.util.BingRulesManager; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +import java.util.HashMap; +import java.util.Map; + +import static org.matrix.androidsdk.rest.model.Event.EVENT_TYPE_CALL_INVITE; + +@RunWith(RobolectricTestRunner.class) +public class TimelinePushWorkerTest { + + @Mock + MXDataHandler mDataHandler; + @Mock + BingRulesManager mBingRulesManager; + private TimelinePushWorker mTimelinePushWorker; + + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + Mockito.when(mDataHandler.getBingRulesManager()).thenReturn(mBingRulesManager); + mTimelinePushWorker = new TimelinePushWorker(mDataHandler); + } + + @Test + public void triggerPush_WhenEventBingRuleDoesNotAllowNotify_ShouldNotTriggerPush() { + final BingRule bingRule = Mockito.mock(BingRule.class); + Mockito.when(bingRule.shouldNotify()).thenReturn(false); + Mockito.when(mBingRulesManager.fulfilledBingRule(Mockito.any(Event.class))).thenReturn(bingRule); + final Event event = new Event(); + final RoomState roomState = new RoomState(); + mTimelinePushWorker.triggerPush(roomState, event); + Mockito.verify(mDataHandler, Mockito.never()).onBingEvent(event, roomState, bingRule); + } + + @Test + public void triggerPush_WhenEventHasNoLifetime_ShouldTriggerPush() { + final BingRule bingRule = Mockito.mock(BingRule.class); + Mockito.when(bingRule.shouldNotify()).thenReturn(true); + Mockito.when(mBingRulesManager.fulfilledBingRule(Mockito.any(Event.class))).thenReturn(bingRule); + final Event event = new Event(); + final RoomState roomState = new RoomState(); + mTimelinePushWorker.triggerPush(roomState, event); + Mockito.verify(mDataHandler).onBingEvent(event, roomState, bingRule); + } + + @Test + public void triggerPush_WhenMaxLifetimeIsReached_ShouldNotTriggerPush() { + final Gson gson = new Gson(); + final BingRule bingRule = Mockito.mock(BingRule.class); + Mockito.when(bingRule.shouldNotify()).thenReturn(true); + Mockito.when(mBingRulesManager.fulfilledBingRule(Mockito.any(Event.class))).thenReturn(bingRule); + final Event event = new Event(); + Map contentMap = new HashMap<>(); + contentMap.put("lifetime", "10000"); + event.content = gson.toJsonTree(contentMap); + event.originServerTs = System.currentTimeMillis() - 50000; + final RoomState roomState = new RoomState(); + mTimelinePushWorker.triggerPush(roomState, event); + Mockito.verify(mDataHandler, Mockito.never()).onBingEvent(event, roomState, bingRule); + } + + @Test + public void triggerPush_WhenCallTimeoutIsReached_ShouldNotTriggerPush() { + final BingRule bingRule = Mockito.mock(BingRule.class); + Mockito.when(bingRule.shouldNotify()).thenReturn(true); + Mockito.when(mBingRulesManager.fulfilledBingRule(Mockito.any(Event.class))).thenReturn(bingRule); + final Event event = new Event(); + event.type = EVENT_TYPE_CALL_INVITE; + event.originServerTs = System.currentTimeMillis() - 124000; + final RoomState roomState = new RoomState(); + mTimelinePushWorker.triggerPush(roomState, event); + Mockito.verify(mDataHandler, Mockito.never()).onBingEvent(event, roomState, bingRule); + } + + @Test + public void triggerPush_WhenCallTimeoutIsNotReached_ShouldTriggerPush() { + final BingRule bingRule = Mockito.mock(BingRule.class); + Mockito.when(bingRule.shouldNotify()).thenReturn(true); + Mockito.when(mBingRulesManager.fulfilledBingRule(Mockito.any(Event.class))).thenReturn(bingRule); + final Event event = new Event(); + event.type = EVENT_TYPE_CALL_INVITE; + event.originServerTs = System.currentTimeMillis() - 8000; + final RoomState roomState = new RoomState(); + mTimelinePushWorker.triggerPush(roomState, event); + Mockito.verify(mDataHandler).onBingEvent(event, roomState, bingRule); + } +} From e4f24acdf108a1bff826fdc3b3751b8b1833a9fe Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 27 Sep 2018 17:13:29 +0200 Subject: [PATCH 212/236] Timeline : rename listener --- .../matrix/androidsdk/crypto/CryptoTest.java | 28 +++++++++---------- .../androidsdk/lazyloading/RoomStateTest.java | 8 +++--- .../data/timeline/EventTimeline.java | 6 ++-- .../data/timeline/MXEventTimeline.java | 4 +-- .../data/timeline/TimelineEventListeners.java | 18 ++++++------ .../fragments/MatrixMessagesFragment.java | 2 +- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index a8bb619e1..90b87fdbf 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -1123,7 +1123,7 @@ public void onCryptoSyncComplete() { final CountDownLatch lock2 = new CountDownLatch(6); final List receivedEvents = new ArrayList<>(); - EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { receivedEvents.add(event); @@ -1179,7 +1179,7 @@ public void test12_testAliceAndBobInAEncryptedRoomBackPaginationFromHomeServer() final CountDownLatch lock2 = new CountDownLatch(6); final List receivedEvents = new ArrayList<>(); - EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { receivedEvents.add(event); @@ -1608,7 +1608,7 @@ public void onToDeviceEvent(Event event) { bobSession.getDataHandler().addListener(bobEventListener); final List receivedEvents = new ArrayList<>(); - EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { receivedEvents.add(event); @@ -1689,7 +1689,7 @@ public void onToDeviceEvent(Event event) { bobSession.getDataHandler().addListener(bobEventListener); final List receivedEvents = new ArrayList<>(); - EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { receivedEvents.add(event); @@ -1792,7 +1792,7 @@ public void onToDeviceEvent(Event event) { bobSession.getDataHandler().addListener(bobEventListener); final List receivedEvents = new ArrayList<>(); - EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { receivedEvents.add(event); @@ -1863,7 +1863,7 @@ public void onToDeviceEvent(Event event) { final List receivedEvents4 = new ArrayList<>(); final CountDownLatch lock4 = new CountDownLatch(1); - EventTimeline.EventTimelineListener eventTimelineListener4 = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener4 = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { receivedEvents4.add(event); @@ -1929,7 +1929,7 @@ public void onToDeviceEvent(Event event) { bobSession.getDataHandler().addListener(bobEventListener); final List receivedEvents = new ArrayList<>(); - EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { receivedEvents.add(event); @@ -2000,7 +2000,7 @@ public void onSuccess(Void info) { final CountDownLatch lock4 = new CountDownLatch(1); final List receivedEvents2 = new ArrayList<>(); - EventTimeline.EventTimelineListener eventTimelineListener2 = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener2 = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { receivedEvents2.add(event); @@ -2047,7 +2047,7 @@ public void test20_testAliceAndBlockedBob() throws Exception { final CountDownLatch lock1 = new CountDownLatch(1); final List receivedEvents = new ArrayList<>(); - EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { receivedEvents.add(event); @@ -2091,7 +2091,7 @@ public void onSuccess(Void info) { final CountDownLatch lock2 = new CountDownLatch(1); final List receivedEvents2 = new ArrayList<>(); - EventTimeline.EventTimelineListener eventTimelineListener2 = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener2 = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE_ENCRYPTED)) { receivedEvents2.add(event); @@ -2136,7 +2136,7 @@ public void onSuccess(Void info) { final CountDownLatch lock3 = new CountDownLatch(1); final List receivedEvents3 = new ArrayList<>(); - EventTimeline.EventTimelineListener eventTimelineListener3 = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener3 = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { receivedEvents3.add(event); @@ -2579,7 +2579,7 @@ public void onSuccess(String info) { Room roomFromBobPOV = bobSession.getDataHandler().getRoom(aliceRoomId); final CountDownLatch lock3 = new CountDownLatch(1); final List receivedEvents = new ArrayList<>(); - EventTimeline.EventTimelineListener eventTimelineListener = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { receivedEvents.add(event); @@ -2638,7 +2638,7 @@ public void onSuccess(String info) { final CountDownLatch lock6 = new CountDownLatch(1); final List receivedEvents2 = new ArrayList<>(); - EventTimeline.EventTimelineListener eventTimelineListener2 = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener2 = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { receivedEvents2.add(event); @@ -3075,7 +3075,7 @@ public void onSuccess(Void info) { final CountDownLatch lock4 = new CountDownLatch(1); final List receivedEvents2 = new ArrayList<>(); - EventTimeline.EventTimelineListener eventTimelineListener2 = new EventTimeline.EventTimelineListener() { + EventTimeline.Listener eventTimelineListener2 = new EventTimeline.Listener() { public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (TextUtils.equals(event.getType(), Event.EVENT_TYPE_MESSAGE)) { receivedEvents2.add(event); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java index 0d6e32911..3d613bc30 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomStateTest.java @@ -88,7 +88,7 @@ private void RoomState_IncomingMessage(final boolean withLazyLoading) throws Exc mTestHelper.syncSession(data.samSession, false); final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); final CountDownLatch lock = new CountDownLatch(1); - aliceRoom.getTimeline().addEventTimelineListener(new EventTimeline.EventTimelineListener() { + aliceRoom.getTimeline().addEventTimelineListener(new EventTimeline.Listener() { @Override public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { lock.countDown(); @@ -125,7 +125,7 @@ private void RoomState_BackPaginate(final boolean withLazyLoading) throws Except final Room aliceRoom = data.aliceSession.getDataHandler().getRoom(data.roomId); final CountDownLatch lock = new CountDownLatch(1); final EventTimeline liveTimeline = aliceRoom.getTimeline(); - liveTimeline.addEventTimelineListener(new EventTimeline.EventTimelineListener() { + liveTimeline.addEventTimelineListener(new EventTimeline.Listener() { int messageCount = 0; @Override @@ -223,7 +223,7 @@ private void RoomState_PermalinkWithBackPagination(final boolean withLazyLoading mTestHelper.syncSession(data.aliceSession, false); final CountDownLatch lock = new CountDownLatch(1); final EventTimeline eventTimeline = EventTimelineFactory.pastTimeline(data.aliceSession.getDataHandler(), data.roomId, data.bobMessageId); - eventTimeline.addEventTimelineListener(new EventTimeline.EventTimelineListener() { + eventTimeline.addEventTimelineListener(new EventTimeline.Listener() { int messageCount = 0; @Override @@ -288,7 +288,7 @@ private void RoomState_PermalinkWithForwardPagination(final boolean withLazyLoad mTestHelper.syncSession(data.aliceSession, false); final CountDownLatch lock = new CountDownLatch(1); final EventTimeline eventTimeline = EventTimelineFactory.pastTimeline(data.aliceSession.getDataHandler(), data.roomId, data.bobMessageId); - eventTimeline.addEventTimelineListener(new EventTimeline.EventTimelineListener() { + eventTimeline.addEventTimelineListener(new EventTimeline.Listener() { int messageCount = 0; @Override diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java index 7f1958dc8..62ba6c1aa 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java @@ -195,14 +195,14 @@ public interface EventTimeline { * * @param listener the listener to add. */ - void addEventTimelineListener(EventTimelineListener listener); + void addEventTimelineListener(Listener listener); /** * Remove an events listener. * * @param listener the listener to remove. */ - void removeEventTimelineListener(EventTimelineListener listener); + void removeEventTimelineListener(Listener listener); /** * The direction from which an incoming event is considered. @@ -221,7 +221,7 @@ enum Direction { BACKWARDS } - interface EventTimelineListener { + interface Listener { /** * Call when an event has been handled in the timeline. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java index 0bb68a66e..76f53df2f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java @@ -974,7 +974,7 @@ public void run() { * @param listener the listener to add. */ @Override - public void addEventTimelineListener(@Nullable final EventTimelineListener listener) { + public void addEventTimelineListener(@Nullable final Listener listener) { mEventListeners.add(listener); } @@ -984,7 +984,7 @@ public void addEventTimelineListener(@Nullable final EventTimelineListener liste * @param listener the listener to remove. */ @Override - public void removeEventTimelineListener(@Nullable final EventTimelineListener listener) { + public void removeEventTimelineListener(@Nullable final Listener listener) { mEventListeners.remove(listener); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java index fab2d5701..6e926049e 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java @@ -37,18 +37,18 @@ class TimelineEventListeners { private static final String LOG_TAG = TimelineEventListeners.class.getSimpleName(); // The inner listeners - private final List mEventTimelineListeners = new ArrayList<>(); + private final List mListeners = new ArrayList<>(); /** * Add an events listener. * * @param listener the listener to add. */ - public void add(@Nullable final EventTimeline.EventTimelineListener listener) { + public void add(@Nullable final EventTimeline.Listener listener) { if (listener != null) { synchronized (this) { - if (mEventTimelineListeners.indexOf(listener) == -1) { - mEventTimelineListeners.add(listener); + if (mListeners.indexOf(listener) == -1) { + mListeners.add(listener); } } } @@ -59,10 +59,10 @@ public void add(@Nullable final EventTimeline.EventTimelineListener listener) { * * @param listener the listener to remove. */ - public void remove(@Nullable final EventTimeline.EventTimelineListener listener) { + public void remove(@Nullable final EventTimeline.Listener listener) { if (null != listener) { synchronized (this) { - mEventTimelineListeners.remove(listener); + mListeners.remove(listener); } } } @@ -79,11 +79,11 @@ public void onEvent(@NonNull final Event event, @NonNull final RoomState roomState) { // ensure that the listeners are called in the UI thread if (Looper.getMainLooper().getThread() == Thread.currentThread()) { - final List listeners; + final List listeners; synchronized (this) { - listeners = new ArrayList<>(mEventTimelineListeners); + listeners = new ArrayList<>(mListeners); } - for (EventTimeline.EventTimelineListener listener : listeners) { + for (EventTimeline.Listener listener : listeners) { try { listener.onEvent(event, direction, roomState); } catch (Exception e) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java index 239bed0f2..59acb48ee 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java @@ -144,7 +144,7 @@ public void onEventSent(Event event, String prevEventId) { } }; - private final EventTimeline.EventTimelineListener mEventTimelineListener = new EventTimeline.EventTimelineListener() { + private final EventTimeline.Listener mEventTimelineListener = new EventTimeline.Listener() { @Override public void onEvent(Event event, EventTimeline.Direction direction, RoomState roomState) { if (null != mMatrixMessagesListener) { From 7f4e56997941820ff701d58ae865a51f2f210e1a Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 28 Sep 2018 12:06:20 +0200 Subject: [PATCH 213/236] Test lazyloading : Add search test --- .../androidsdk/lazyloading/SearchTest.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/SearchTest.java diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/SearchTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/SearchTest.java new file mode 100644 index 000000000..ae279e62e --- /dev/null +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/SearchTest.java @@ -0,0 +1,56 @@ +package org.matrix.androidsdk.lazyloading; + +import android.support.test.InstrumentationRegistry; + +import junit.framework.Assert; + +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; +import org.matrix.androidsdk.RestClient; +import org.matrix.androidsdk.common.CommonTestHelper; +import org.matrix.androidsdk.common.TestApiCallback; +import org.matrix.androidsdk.rest.model.search.SearchResponse; + +import java.util.Collections; +import java.util.concurrent.CountDownLatch; + +@FixMethodOrder(MethodSorters.JVM) +public class SearchTest { + + private CommonTestHelper mTestHelper = new CommonTestHelper(); + private LazyLoadingTestHelper mLazyLoadingTestHelper = new LazyLoadingTestHelper(mTestHelper); + + @BeforeClass + public static void init() { + RestClient.initUserAgent(InstrumentationRegistry.getContext()); + } + + @Test + public void Search_CheckMessageSearch_LazyLoadedMembers() throws Exception { + Search_CheckMessageSearch_(true); + } + + @Test + public void Search_CheckMessageSearch_LoadAllMembers() throws Exception { + Search_CheckMessageSearch_(false); + } + + private void Search_CheckMessageSearch_(boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); + final CountDownLatch lock = new CountDownLatch(1); + data.aliceSession.pauseEventStream(); + data.aliceSession.resumeEventStream(); + data.aliceSession.getDataHandler().clear(); + data.aliceSession.searchMessageText("Bob message", Collections.singletonList(data.roomId), 0, 0, null, new TestApiCallback(lock) { + @Override + public void onSuccess(SearchResponse info) { + Assert.assertEquals(1, info.searchCategories.roomEvents.results.size()); + super.onSuccess(info); + } + }); + mTestHelper.await(lock); + } + +} From 7c702e92cad9b3bbd01040c943c9e6195e23025e Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 28 Sep 2018 12:09:25 +0200 Subject: [PATCH 214/236] Tests : add one RoomSummary test and clean RoomMembers tests --- .../lazyloading/RoomMembersTest.java | 7 +++-- .../lazyloading/RoomSummaryTest.java | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomMembersTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomMembersTest.java index 663b67f15..82c3aee1a 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomMembersTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomMembersTest.java @@ -61,7 +61,7 @@ private void RoomMembers_CheckTotalCountAsync(final boolean withLazyLoading) thr @Override public void onSuccess(List roomMembers) { Assert.assertEquals(4, roomMembers.size()); - lock.countDown(); + super.onSuccess(roomMembers); } }); mTestHelper.await(lock); @@ -86,7 +86,7 @@ private void RoomMembers_CheckActiveCountAsync(final boolean withLazyLoading) th @Override public void onSuccess(List roomMembers) { Assert.assertEquals(4, roomMembers.size()); - lock.countDown(); + super.onSuccess(roomMembers); } }); mTestHelper.await(lock); @@ -111,7 +111,7 @@ private void RoomMembers_CheckJoinedCountAsync(final boolean withLazyLoading) th @Override public void onSuccess(List roomMembers) { Assert.assertEquals(3, roomMembers.size()); - lock.countDown(); + super.onSuccess(roomMembers); } }); mTestHelper.await(lock); @@ -139,5 +139,4 @@ private void RoomMembers_CheckAlreadyLoadedCount(final boolean withLazyLoading) } } - } diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java index dbc88c7ea..cf458d388 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java @@ -25,9 +25,12 @@ import org.junit.runners.MethodSorters; import org.matrix.androidsdk.RestClient; import org.matrix.androidsdk.common.CommonTestHelper; +import org.matrix.androidsdk.common.TestApiCallback; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomSummary; +import java.util.concurrent.CountDownLatch; + @FixMethodOrder(MethodSorters.JVM) public class RoomSummaryTest { @@ -84,4 +87,27 @@ private void RoomSummary_MemberCount(boolean withLazyLoading) throws Exception { Assert.assertEquals(1, roomSummary.getNumberOfInvitedMembers()); } + @Test + public void RoomSummary_CheckRoomSummaryIsNullAfterLeavingFromAnotherDevice_LazyLoadedMembers() throws Exception { + RoomSummary_CheckRoomSummaryIsNullAfterLeavingFromAnotherDevice(true); + } + + @Test + public void RoomSummary_CheckRoomSummaryIsNullAfterLeavingFromAnotherDevice_LoadAllMembers() throws Exception { + RoomSummary_CheckRoomSummaryIsNullAfterLeavingFromAnotherDevice(false); + } + + private void RoomSummary_CheckRoomSummaryIsNullAfterLeavingFromAnotherDevice(boolean withLazyLoading) throws Exception { + final LazyLoadingScenarioData data = mLazyLoadingTestHelper.createScenario(withLazyLoading); + final CountDownLatch lock = new CountDownLatch(1); + data.aliceSession.getDataHandler().getDataRetriever().getRoomsRestClient().leaveRoom(data.roomId, new TestApiCallback(lock)); + mTestHelper.await(lock); + mTestHelper.syncSession(data.bobSession, false); + final Room bobRoom = data.bobSession.getDataHandler().getRoom(data.roomId); + mTestHelper.sendTextMessage(bobRoom, "New bob message", 50); + mTestHelper.syncSession(data.aliceSession, false); + final RoomSummary roomSummary = data.aliceSession.getDataHandler().getStore().getSummary(data.roomId); + Assert.assertNull(roomSummary); + } + } From eaa6a3fbf5c344e3ae3174cf27a34c38462ea758 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 28 Sep 2018 15:43:34 +0200 Subject: [PATCH 215/236] Update CHANGES.rst file --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index 76ba1eb9b..d851bcae6 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -20,6 +20,7 @@ API Change: - Extract patterns and corresponding methods from MXSession to a dedicated MXPatterns class. - MatrixMessageListFragment is now abstract and take an Adapter type as class parameter - Parameter guestAccess removed from MxSession.createRoom(). It had no effect. + - EventTimeline is now exposed as an interface. Use EventTimelineFactory to instantiate it. Translations: - From c87138474a27ff6ff2ddde1ccb828e3f1910c668 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 28 Sep 2018 16:43:19 +0200 Subject: [PATCH 216/236] Ensure created account has a human readable prefix to simplify debugging (log, ...) --- .../androidsdk/common/CommonTestHelper.java | 14 ++++----- .../androidsdk/common/TestConstants.java | 5 +++- .../androidsdk/crypto/CryptoRestTest.java | 9 +++--- .../matrix/androidsdk/crypto/CryptoTest.java | 29 ++++++++++--------- .../lazyloading/LazyLoadingTestHelper.java | 7 +++-- 5 files changed, 35 insertions(+), 29 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index 18958b91b..664db809d 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -58,8 +58,8 @@ */ public class CommonTestHelper { - public MXSession createAccount(final SessionTestParams testParams) throws InterruptedException { - return createAccount(TestConstants.USER_ID, TestConstants.PASSWORD, testParams); + public MXSession createAccount(final String userNamePrefix, final SessionTestParams testParams) throws InterruptedException { + return createAccount(userNamePrefix, TestConstants.PASSWORD, testParams); } public MXSession logIntoAccount(final String userId, final SessionTestParams testParams) throws InterruptedException { @@ -166,18 +166,18 @@ public void onEncryptionFailed(RoomMediaMessage roomMediaMessage) { /** * Creates a unique account * - * @param userId the base userId - * @param password the password - * @param testParams test params about the session + * @param userNamePrefix the user name prefix + * @param password the password + * @param testParams test params about the session * @return the session associated with the newly created account */ - private MXSession createAccount(@NonNull final String userId, + private MXSession createAccount(@NonNull final String userNamePrefix, @NonNull final String password, @NonNull final SessionTestParams testParams) throws InterruptedException { final Context context = InstrumentationRegistry.getContext(); final MXSession session = createAccountAndSync( context, - userId + System.currentTimeMillis() + UUID.randomUUID(), + userNamePrefix + "_" + System.currentTimeMillis() + UUID.randomUUID(), password, testParams.withInitialSync, testParams.withCryptoEnabled diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java index faa4b7a08..da69d433c 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/TestConstants.java @@ -23,6 +23,9 @@ public class TestConstants { // Time out to use when waiting for server response public static final int AWAIT_TIME_OUT_MILLIS = 30000; - public static final String USER_ID = "userid"; + public static final String USER_ALICE = "Alice"; + public static final String USER_BOB = "Bob"; + public static final String USER_SAM = "Sam"; + public static final String PASSWORD = "password"; } \ No newline at end of file diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java index b131a0bc1..7c84954d3 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java @@ -30,6 +30,7 @@ import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.common.SessionTestParams; import org.matrix.androidsdk.common.TestApiCallback; +import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXKey; import org.matrix.androidsdk.crypto.data.MXUsersDevicesMap; @@ -54,7 +55,7 @@ public class CryptoRestTest { public void test01_testDeviceKeys() throws Exception { final Context context = InstrumentationRegistry.getContext(); final SessionTestParams testParams = SessionTestParams.newBuilder().withInitialSync(true).build(); - final MXSession bobSession = mTestHelper.createAccount(testParams); + final MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, testParams); final Map results = new HashMap<>(); String ed25519key = "wV5E3EUSHpHuoZLljNzojlabjGdXT3Mz7rugG9zgbkI"; @@ -120,7 +121,7 @@ public void onSuccess(KeysQueryResponse keysQueryResponse) { public void test02_testOneTimeKeys() throws Exception { Context context = InstrumentationRegistry.getContext(); final SessionTestParams testParams = SessionTestParams.newBuilder().withInitialSync(true).build(); - final MXSession bobSession = mTestHelper.createAccount(testParams); + final MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, testParams); final Map results = new HashMap<>(); final Map otks = new HashMap<>(); @@ -153,8 +154,8 @@ public void onSuccess(KeysUploadResponse keysUploadResponse) { public void test03_testClaimOneTimeKeysForUsersDevices() throws Exception { Context context = InstrumentationRegistry.getContext(); final SessionTestParams testParams = SessionTestParams.newBuilder().withInitialSync(true).build(); - final MXSession bobSession = mTestHelper.createAccount(testParams); - final MXSession aliceSession = mTestHelper.createAccount(testParams); + final MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, testParams); + final MXSession aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, testParams); final Map results = new HashMap<>(); final Map otks = new HashMap<>(); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 90b87fdbf..9a29ad8b3 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -41,6 +41,7 @@ import org.matrix.androidsdk.common.SessionAndRoomId; import org.matrix.androidsdk.common.SessionTestParams; import org.matrix.androidsdk.common.TestApiCallback; +import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.common.Triple; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXOlmSessionResult; @@ -92,7 +93,7 @@ public void test01_testCryptoNoDeviceId() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams); Assert.assertNull(bobSession.getCrypto()); bobSession.getCredentials().deviceId = null; @@ -120,7 +121,7 @@ public void test02_testCryptoPersistenceInStore() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams); bobSession.getCredentials().deviceId = "BobDevice"; Assert.assertNull(bobSession.getCrypto()); @@ -230,7 +231,7 @@ public void test03_testKeysUploadAndDownload() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession aliceSession = mTestHelper.createAccount(defaultSessionParams); + MXSession aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams); aliceSession.getCredentials().deviceId = "AliceDevice"; CountDownLatch lock0 = new CountDownLatch(1); @@ -244,7 +245,7 @@ public void onSuccess(Void info) { mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("enableCrypto")); - MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams); CountDownLatch lock2 = new CountDownLatch(1); bobSession.getCredentials().deviceId = "BobDevice"; bobSession.enableCrypto(true, new TestApiCallback(lock2) { @@ -417,7 +418,7 @@ public void test04_testEnsureOlmSessionsForUsers() throws Exception { Context context = InstrumentationRegistry.getContext(); - MXSession aliceSession = mTestHelper.createAccount(defaultSessionParams); + MXSession aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams); final Map results = new HashMap<>(); aliceSession.getCredentials().deviceId = "AliceDevice"; @@ -435,7 +436,7 @@ public void onSuccess(Void info) { mTestHelper.await(lock0); Assert.assertTrue(results.containsKey("enableCryptoAlice")); - MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams); CountDownLatch lock2 = new CountDownLatch(1); bobSession.enableCrypto(true, new TestApiCallback(lock2) { @@ -582,7 +583,7 @@ public void test05_testRoomIsEncrypted() throws Exception { Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams); CountDownLatch lock0 = new CountDownLatch(1); bobSession.enableCrypto(true, new TestApiCallback(lock0) { @@ -2524,8 +2525,8 @@ public void test25_testLeftAndJoinedBob() throws Exception { final Map results = new HashMap<>(); - MXSession aliceSession = mTestHelper.createAccount(defaultSessionParams); - MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); + MXSession aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams); CountDownLatch lock_1 = new CountDownLatch(2); @@ -2988,8 +2989,8 @@ public void test27_testEnableEncryptionAfterNonEncryptedMessages() throws Except final String messageFromAlice = "Hello I'm Alice!"; final String message2FromAlice = "I'm still Alice!"; - MXSession aliceSession = mTestHelper.createAccount(defaultSessionParams); - MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); + MXSession aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams); CountDownLatch lock00b = new CountDownLatch(2); aliceSession.enableCrypto(true, new TestApiCallback(lock00b) { @@ -3342,7 +3343,7 @@ public void onToDeviceEvent(Event event) { */ private SessionAndRoomId doE2ETestWithAliceInARoom() throws Exception { final Map results = new HashMap<>(); - MXSession aliceSession = mTestHelper.createAccount(defaultSessionParams); + MXSession aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, defaultSessionParams); CountDownLatch lock0 = new CountDownLatch(1); aliceSession.enableCrypto(true, new TestApiCallback(lock0) { @@ -3399,7 +3400,7 @@ private Pair doE2ETestWithAliceAndBobInARoom(boolea Room room = aliceSession.getDataHandler().getRoom(aliceRoomId); - MXSession bobSession = mTestHelper.createAccount(defaultSessionParams); + MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, defaultSessionParams); CountDownLatch lock0 = new CountDownLatch(1); bobSession.enableCrypto(cryptedBob, new TestApiCallback(lock0) { @@ -3506,7 +3507,7 @@ private Triple doE2ETestWithAliceAndBobA Room room = aliceSession.getDataHandler().getRoom(aliceRoomId); - MXSession samSession = mTestHelper.createAccount(defaultSessionParams); + MXSession samSession = mTestHelper.createAccount(TestConstants.USER_SAM, defaultSessionParams); CountDownLatch lock0 = new CountDownLatch(1); samSession.enableCrypto(true, new TestApiCallback(lock0) { diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java index ac7720a4c..9427e4929 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java @@ -24,6 +24,7 @@ import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.common.SessionTestParams; import org.matrix.androidsdk.common.TestApiCallback; +import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.rest.model.Event; @@ -61,9 +62,9 @@ public LazyLoadingTestHelper(CommonTestHelper mCommonTestHelper) { public LazyLoadingScenarioData createScenario(boolean withLazyLoading) throws Exception { final SessionTestParams createSessionParams = SessionTestParams.newBuilder().withInitialSync(true).build(); - MXSession aliceSession = mTestHelper.createAccount(createSessionParams); - MXSession bobSession = mTestHelper.createAccount(createSessionParams); - MXSession samSession = mTestHelper.createAccount(createSessionParams); + MXSession aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, createSessionParams); + MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, createSessionParams); + MXSession samSession = mTestHelper.createAccount(TestConstants.USER_SAM, createSessionParams); final String aliceId = aliceSession.getMyUserId(); final String bobId = bobSession.getMyUserId(); From 7a3a7223e535cbd5420968b1502f8235d22ced9d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 28 Sep 2018 16:45:12 +0200 Subject: [PATCH 217/236] Code lisibility --- .../org/matrix/androidsdk/crypto/CryptoRestTest.java | 12 +++++++++--- .../org/matrix/androidsdk/crypto/CryptoTest.java | 9 +++++++-- .../lazyloading/LazyLoadingScenarioData.java | 1 - .../lazyloading/LazyLoadingTestHelper.java | 8 ++++++-- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java index 7c84954d3..ae79721c2 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java @@ -54,7 +54,9 @@ public class CryptoRestTest { @Test public void test01_testDeviceKeys() throws Exception { final Context context = InstrumentationRegistry.getContext(); - final SessionTestParams testParams = SessionTestParams.newBuilder().withInitialSync(true).build(); + final SessionTestParams testParams = SessionTestParams.newBuilder() + .withInitialSync(true) + .build(); final MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, testParams); final Map results = new HashMap<>(); @@ -120,7 +122,9 @@ public void onSuccess(KeysQueryResponse keysQueryResponse) { @Test public void test02_testOneTimeKeys() throws Exception { Context context = InstrumentationRegistry.getContext(); - final SessionTestParams testParams = SessionTestParams.newBuilder().withInitialSync(true).build(); + final SessionTestParams testParams = SessionTestParams.newBuilder() + .withInitialSync(true) + .build(); final MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, testParams); final Map results = new HashMap<>(); @@ -153,7 +157,9 @@ public void onSuccess(KeysUploadResponse keysUploadResponse) { @Test public void test03_testClaimOneTimeKeysForUsersDevices() throws Exception { Context context = InstrumentationRegistry.getContext(); - final SessionTestParams testParams = SessionTestParams.newBuilder().withInitialSync(true).build(); + final SessionTestParams testParams = SessionTestParams.newBuilder() + .withInitialSync(true) + .build(); final MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, testParams); final MXSession aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, testParams); diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 9a29ad8b3..efce6fdd8 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -79,8 +79,13 @@ public class CryptoTest { private CommonTestHelper mTestHelper = new CommonTestHelper(); - private final SessionTestParams defaultSessionParams = SessionTestParams.newBuilder().withInitialSync(true).build(); - private final SessionTestParams encryptedSessionParams = SessionTestParams.newBuilder().withInitialSync(true).withCryptoEnabled(true).build(); + private final SessionTestParams defaultSessionParams = SessionTestParams.newBuilder() + .withInitialSync(true) + .build(); + private final SessionTestParams encryptedSessionParams = SessionTestParams.newBuilder() + .withInitialSync(true) + .withCryptoEnabled(true) + .build(); private static final String LOG_TAG = "CryptoTest"; diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingScenarioData.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingScenarioData.java index 9b5903b07..c7f3798be 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingScenarioData.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingScenarioData.java @@ -17,7 +17,6 @@ import org.matrix.androidsdk.MXSession; - /** * Data holder for lazy loading tests * The sessions are not synced by default as you want to perform some custom tests diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java index 9427e4929..5b36e7b66 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/LazyLoadingTestHelper.java @@ -61,7 +61,9 @@ public LazyLoadingTestHelper(CommonTestHelper mCommonTestHelper) { */ public LazyLoadingScenarioData createScenario(boolean withLazyLoading) throws Exception { - final SessionTestParams createSessionParams = SessionTestParams.newBuilder().withInitialSync(true).build(); + final SessionTestParams createSessionParams = SessionTestParams.newBuilder() + .withInitialSync(true) + .build(); MXSession aliceSession = mTestHelper.createAccount(TestConstants.USER_ALICE, createSessionParams); MXSession bobSession = mTestHelper.createAccount(TestConstants.USER_BOB, createSessionParams); MXSession samSession = mTestHelper.createAccount(TestConstants.USER_SAM, createSessionParams); @@ -128,7 +130,9 @@ public void onSuccess(String info) { samSession.clear(context); - final SessionTestParams logSessionParams = SessionTestParams.newBuilder().withLazyLoading(withLazyLoading).build(); + final SessionTestParams logSessionParams = SessionTestParams.newBuilder() + .withLazyLoading(withLazyLoading) + .build(); aliceSession = mTestHelper.logIntoAccount(aliceId, logSessionParams); bobSession = mTestHelper.logIntoAccount(bobId, logSessionParams); samSession = mTestHelper.logIntoAccount(samId, logSessionParams); From a60538f73162866b9e58de8425d936d50604333d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Oct 2018 15:17:08 +0200 Subject: [PATCH 218/236] For RoomSummary_MemberCount test, Android implementation is not the same than for iOS --- .../androidsdk/lazyloading/RoomSummaryTest.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java index cf458d388..03ecb85b5 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/lazyloading/RoomSummaryTest.java @@ -83,8 +83,15 @@ private void RoomSummary_MemberCount(boolean withLazyLoading) throws Exception { mTestHelper.syncSession(data.aliceSession, false); final RoomSummary roomSummary = data.aliceSession.getDataHandler().getStore().getSummary(data.roomId); Assert.assertNotNull(roomSummary); - Assert.assertEquals(3, roomSummary.getNumberOfJoinedMembers()); - Assert.assertEquals(1, roomSummary.getNumberOfInvitedMembers()); + + if (withLazyLoading) { + Assert.assertEquals(3, roomSummary.getNumberOfJoinedMembers()); + Assert.assertEquals(1, roomSummary.getNumberOfInvitedMembers()); + } else { + // Without lazy loading the room summary does not contains this data yet + Assert.assertEquals(0, roomSummary.getNumberOfJoinedMembers()); + Assert.assertEquals(0, roomSummary.getNumberOfInvitedMembers()); + } } @Test From 208d70fc5325dba5558f2b87634167f6c58bd4dc Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Oct 2018 15:24:53 +0200 Subject: [PATCH 219/236] Better code --- .../androidsdk/common/CommonTestHelper.java | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java index 664db809d..bcbef2901 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/common/CommonTestHelper.java @@ -198,7 +198,7 @@ private MXSession logIntoAccount(@NonNull final String userId, @NonNull final String password, @NonNull final SessionTestParams testParams) throws InterruptedException { final Context context = InstrumentationRegistry.getContext(); - final MXSession session = logAccountAndSync(context, userId, password, testParams.withInitialSync, testParams.withCryptoEnabled, testParams.withLazyLoading); + final MXSession session = logAccountAndSync(context, userId, password, testParams); Assert.assertNotNull(session); return session; } @@ -298,19 +298,15 @@ public void onSuccess(Credentials credentials) { /** * Start an account login * - * @param context the context - * @param userName the account username - * @param password the password - * @param withInitialSync true to perform an initial sync - * @param enableCrypto true to set enableCryptoWhenStarting - * @param withLazyLoading true to enable lazyLoading + * @param context the context + * @param userName the account username + * @param password the password + * @param sessionTestParams session test params */ private MXSession logAccountAndSync(final Context context, final String userName, final String password, - final boolean withInitialSync, - final boolean enableCrypto, - final boolean withLazyLoading) throws InterruptedException { + final SessionTestParams sessionTestParams) throws InterruptedException { final HomeServerConnectionConfig hs = createHomeServerConfig(null); LoginRestClient loginRestClient = new LoginRestClient(hs); final Map params = new HashMap<>(); @@ -336,16 +332,16 @@ public void onSuccess(Credentials credentials) { final IMXStore store = new MXFileStore(hs, false, context); MXDataHandler mxDataHandler = new MXDataHandler(store, credentials); - mxDataHandler.setLazyLoadingEnabled(withLazyLoading); + mxDataHandler.setLazyLoadingEnabled(sessionTestParams.withLazyLoading); final MXSession mxSession = new MXSession.Builder(hs, mxDataHandler, context) .build(); - if (enableCrypto) { + if (sessionTestParams.withCryptoEnabled) { mxSession.enableCryptoWhenStarting(); } - if (withInitialSync) { - syncSession(mxSession, enableCrypto); + if (sessionTestParams.withInitialSync) { + syncSession(mxSession, sessionTestParams.withCryptoEnabled); } return mxSession; } From 8df3e06d66d3da662ab23a0d73dfd8a8863ad9bb Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Oct 2018 17:15:43 +0200 Subject: [PATCH 220/236] Minor change after my own review --- .../matrix/androidsdk/data/DataRetriever.java | 4 +- .../java/org/matrix/androidsdk/data/Room.java | 10 ++++- .../data/timeline/EventTimeline.java | 4 +- .../data/timeline/EventTimelineFactory.java | 39 ++++++++++++++----- .../data/timeline/MXEventTimeline.java | 8 ++-- .../timeline/StateEventRedactionChecker.java | 4 +- .../data/timeline/TimelineEventListeners.java | 2 +- .../timeline/TimelineLiveEventHandler.java | 5 ++- .../data/timeline/TimelinePushWorker.java | 3 ++ .../fragments/MatrixMessageListFragment.java | 4 +- .../data/timeline/TimelinePushWorkerTest.java | 6 +-- .../timeline/TimelineStateHolderTest.java | 20 +++++----- 12 files changed, 69 insertions(+), 40 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java index 3c0bdb158..f2eccb7cd 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/DataRetriever.java @@ -70,8 +70,8 @@ public Collection getCachedRoomMessages(final IMXStore store, final Strin * * @param roomId the room id. */ - public void cancelHistoryRequest(final String roomId) { - Log.d(LOG_TAG, "## cancelHistoryRequest() : roomId " + roomId); + public void cancelHistoryRequests(final String roomId) { + Log.d(LOG_TAG, "## cancelHistoryRequests() : roomId " + roomId); clearPendingToken(mPendingForwardRequestTokenByRoomId, roomId); clearPendingToken(mPendingBackwardRequestTokenByRoomId, roomId); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java index f2b2ed9a2..0706ed978 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/Room.java @@ -136,6 +136,14 @@ public class Room { // true when the current room is a left one private boolean mIsLeft; + /** + * Constructor + * FIXME All this @NonNull annotation must be also added to the class members and getters + * + * @param dataHandler the data handler + * @param store the store + * @param roomId the room id + */ public Room(@NonNull final MXDataHandler dataHandler, @NonNull final IMXStore store, @NonNull final String roomId) { mDataHandler = dataHandler; mStore = store; @@ -406,7 +414,7 @@ public void cancelRemoteHistoryRequest() { //================================================================================ public String getRoomId() { - return mTimeline.getState().roomId; + return getState().roomId; } public void setAccountData(RoomAccountData accountData) { diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java index 62ba6c1aa..2d026cb47 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java @@ -160,7 +160,7 @@ public interface EventTimeline { boolean backPaginate(int eventCount, boolean useCachedOnly, ApiCallback callback); /** - * Request older messages. + * Request newer messages. * * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. * @return true if request starts @@ -179,7 +179,7 @@ public interface EventTimeline { /** * Cancel any pending pagination requests */ - void cancelPaginationRequest(); + void cancelPaginationRequests(); /** * Reset the pagination timelime and start loading the context around its `initialEventId`. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java index c7af892a1..ab0b8317d 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimelineFactory.java @@ -23,14 +23,17 @@ import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.store.MXMemoryStore; +/** + * This factory creates MXEventTimeline instances + */ public class EventTimelineFactory { /** * Method to create a live timeline associated with the room. * * @param dataHandler the dataHandler - * @param room the linked room. - * @param roomId the roomId + * @param room the linked room + * @param roomId the room id */ public static EventTimeline liveTimeline(@NonNull final MXDataHandler dataHandler, @NonNull final Room room, @@ -39,14 +42,14 @@ public static EventTimeline liveTimeline(@NonNull final MXDataHandler dataHandle } /** - * Method to create a past timeline. + * Method to create an in memory timeline for a room. * * @param dataHandler the data handler * @param roomId the room id. */ - public static EventTimeline pastTimeline(@NonNull final MXDataHandler dataHandler, - @NonNull final String roomId) { - return pastTimeline(dataHandler, roomId, null); + public static EventTimeline inMemoryTimeline(@NonNull final MXDataHandler dataHandler, + @NonNull final String roomId) { + return inMemoryTimeline(dataHandler, roomId, null); } /** @@ -54,12 +57,30 @@ public static EventTimeline pastTimeline(@NonNull final MXDataHandler dataHandle * It will create a memory store and a room * * @param dataHandler the data handler - * @param roomId the room id. + * @param roomId the room id * @param eventId the event id */ public static EventTimeline pastTimeline(@NonNull final MXDataHandler dataHandler, @NonNull final String roomId, - @Nullable final String eventId) { + @NonNull final String eventId) { + return inMemoryTimeline(dataHandler, roomId, eventId); + } + + /* ========================================================================================== + * Private + * ========================================================================================== */ + + /** + * Method to create a in memory timeline. + * It will create a memory store and a room + * + * @param dataHandler the data handler + * @param roomId the room id + * @param eventId the event id or null + */ + private static EventTimeline inMemoryTimeline(@NonNull final MXDataHandler dataHandler, + @NonNull final String roomId, + @Nullable final String eventId) { final MXMemoryStore store = new MXMemoryStore(dataHandler.getCredentials(), null); final Room room = dataHandler.getRoom(store, roomId, true); final EventTimeline eventTimeline = new MXEventTimeline(store, dataHandler, room, roomId, eventId, false); @@ -67,6 +88,4 @@ public static EventTimeline pastTimeline(@NonNull final MXDataHandler dataHandle room.setReadyState(true); return eventTimeline; } - - } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java index 76f53df2f..31cf9cbb7 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java @@ -260,7 +260,7 @@ public void initHistory() { // sanity check if (null != mDataHandler && null != mDataHandler.getDataRetriever()) { mDataHandler.resetReplayAttackCheckInTimeline(getTimelineId()); - mDataHandler.getDataRetriever().cancelHistoryRequest(mRoomId); + mDataHandler.getDataRetriever().cancelHistoryRequests(mRoomId); } } @@ -752,7 +752,7 @@ public void onUnexpectedError(Exception e) { } /** - * Request older messages. + * Request newer messages. * * @param callback callback to implement to be informed that the pagination request has been completed. Can be null. * @return true if request starts @@ -838,8 +838,8 @@ public boolean paginate(Direction direction, final ApiCallback callback * Cancel any pending pagination requests */ @Override - public void cancelPaginationRequest() { - mDataHandler.getDataRetriever().cancelHistoryRequest(mRoomId); + public void cancelPaginationRequests() { + mDataHandler.getDataRetriever().cancelHistoryRequests(mRoomId); mIsBackPaginating = false; mIsForwardPaginating = false; } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java index 8c2d00d45..a69dd7014 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java @@ -34,7 +34,9 @@ import javax.annotation.Nonnull; - +/** + * This class is responsible of checking state events redaction. + */ class StateEventRedactionChecker { private static final String LOG_TAG = StateEventRedactionChecker.class.getSimpleName(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java index 6e926049e..88c66337b 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineEventListeners.java @@ -47,7 +47,7 @@ class TimelineEventListeners { public void add(@Nullable final EventTimeline.Listener listener) { if (listener != null) { synchronized (this) { - if (mListeners.indexOf(listener) == -1) { + if (!mListeners.contains(listener)) { mListeners.add(listener); } } diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java index 10e5a0daa..28926a2e2 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java @@ -37,6 +37,9 @@ import javax.annotation.Nonnull; +/** + * This class is responsible for handling live event + */ class TimelineLiveEventHandler { private static final String LOG_TAG = TimelineLiveEventHandler.class.getSimpleName(); @@ -199,8 +202,6 @@ private void storeLiveRoomEvent(@NonNull final MXDataHandler dataHandler, @NonNull final IMXStore store, @NonNull Event event, final boolean checkRedactedStateEvent) { - - boolean shouldBeSaved = false; String myUserId = dataHandler.getCredentials().userId; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java index c3983e372..a5365349f 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelinePushWorker.java @@ -28,6 +28,9 @@ import org.matrix.androidsdk.util.BingRulesManager; import org.matrix.androidsdk.util.Log; +/** + * This class is responsible for handling push rules for an event + */ class TimelinePushWorker { private static final String LOG_TAG = TimelinePushWorker.class.getSimpleName(); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java index 81eb0fec1..575490de7 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessageListFragment.java @@ -517,7 +517,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, // display a room preview else if (PREVIEW_MODE_READ_ONLY.equals(previewMode)) { mAdapter.setIsPreviewMode(true); - mEventTimeLine = EventTimelineFactory.pastTimeline(mSession.getDataHandler(), mRoomId); + mEventTimeLine = EventTimelineFactory.inMemoryTimeline(mSession.getDataHandler(), mRoomId); mRoom = mEventTimeLine.getRoom(); } // standard case @@ -1726,7 +1726,7 @@ public void cancelCatchingRequests() { mPattern = null; if (null != mEventTimeLine) { - mEventTimeLine.cancelPaginationRequest(); + mEventTimeLine.cancelPaginationRequests(); } mIsInitialSyncing = false; diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelinePushWorkerTest.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelinePushWorkerTest.java index 65445e828..420d6c615 100644 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelinePushWorkerTest.java +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelinePushWorkerTest.java @@ -34,8 +34,6 @@ import java.util.HashMap; import java.util.Map; -import static org.matrix.androidsdk.rest.model.Event.EVENT_TYPE_CALL_INVITE; - @RunWith(RobolectricTestRunner.class) public class TimelinePushWorkerTest { @@ -97,7 +95,7 @@ public void triggerPush_WhenCallTimeoutIsReached_ShouldNotTriggerPush() { Mockito.when(bingRule.shouldNotify()).thenReturn(true); Mockito.when(mBingRulesManager.fulfilledBingRule(Mockito.any(Event.class))).thenReturn(bingRule); final Event event = new Event(); - event.type = EVENT_TYPE_CALL_INVITE; + event.type = Event.EVENT_TYPE_CALL_INVITE; event.originServerTs = System.currentTimeMillis() - 124000; final RoomState roomState = new RoomState(); mTimelinePushWorker.triggerPush(roomState, event); @@ -110,7 +108,7 @@ public void triggerPush_WhenCallTimeoutIsNotReached_ShouldTriggerPush() { Mockito.when(bingRule.shouldNotify()).thenReturn(true); Mockito.when(mBingRulesManager.fulfilledBingRule(Mockito.any(Event.class))).thenReturn(bingRule); final Event event = new Event(); - event.type = EVENT_TYPE_CALL_INVITE; + event.type = Event.EVENT_TYPE_CALL_INVITE; event.originServerTs = System.currentTimeMillis() - 8000; final RoomState roomState = new RoomState(); mTimelinePushWorker.triggerPush(roomState, event); diff --git a/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelineStateHolderTest.java b/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelineStateHolderTest.java index aa580aa64..27e07643c 100644 --- a/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelineStateHolderTest.java +++ b/matrix-sdk/src/test/java/org/matrix/androidsdk/data/timeline/TimelineStateHolderTest.java @@ -14,8 +14,6 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; -import static org.matrix.androidsdk.rest.model.Event.EVENT_TYPE_STATE_ROOM_NAME; - @RunWith(RobolectricTestRunner.class) public class TimelineStateHolderTest { @@ -38,8 +36,8 @@ public void setUp() { public void processStateEvent_WhenDirectionIsForward__ShouldStoreLiveState() { final Event event = new Event(); event.roomId = ROOM_ID; - event.stateKey = EVENT_TYPE_STATE_ROOM_NAME; - event.type = EVENT_TYPE_STATE_ROOM_NAME; + event.stateKey = Event.EVENT_TYPE_STATE_ROOM_NAME; + event.type = Event.EVENT_TYPE_STATE_ROOM_NAME; mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.FORWARDS); Mockito.verify(mIMXStore, Mockito.times(1)).storeLiveStateForRoom(Mockito.anyString()); } @@ -48,7 +46,7 @@ public void processStateEvent_WhenDirectionIsForward__ShouldStoreLiveState() { public void processStateEvent_WhenNoStateKeyIsGiven__ShouldNotBeProcessed() { final Event event = new Event(); event.roomId = ROOM_ID; - event.type = EVENT_TYPE_STATE_ROOM_NAME; + event.type = Event.EVENT_TYPE_STATE_ROOM_NAME; Assert.assertFalse(mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.FORWARDS)); } @@ -56,8 +54,8 @@ public void processStateEvent_WhenNoStateKeyIsGiven__ShouldNotBeProcessed() { public void processStateEvent_WithConformingEvent__ShouldBeProcessed() { final Event event = new Event(); event.roomId = ROOM_ID; - event.type = EVENT_TYPE_STATE_ROOM_NAME; - event.stateKey = EVENT_TYPE_STATE_ROOM_NAME; + event.type = Event.EVENT_TYPE_STATE_ROOM_NAME; + event.stateKey = Event.EVENT_TYPE_STATE_ROOM_NAME; Assert.assertTrue(mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.FORWARDS)); } @@ -65,8 +63,8 @@ public void processStateEvent_WithConformingEvent__ShouldBeProcessed() { public void processStateEvent_WhenDirectionIsForward__ShouldUseState() { final Event event = new Event(); event.roomId = ROOM_ID; - event.stateKey = EVENT_TYPE_STATE_ROOM_NAME; - event.type = EVENT_TYPE_STATE_ROOM_NAME; + event.stateKey = Event.EVENT_TYPE_STATE_ROOM_NAME; + event.type = Event.EVENT_TYPE_STATE_ROOM_NAME; final RoomState state = Mockito.spy(mTimelineStateHolder.getState()); mTimelineStateHolder.setState(state); mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.FORWARDS); @@ -77,8 +75,8 @@ public void processStateEvent_WhenDirectionIsForward__ShouldUseState() { public void processStateEvent_WhenDirectionIsBackward__ShouldUseBackState() { final Event event = new Event(); event.roomId = ROOM_ID; - event.stateKey = EVENT_TYPE_STATE_ROOM_NAME; - event.type = EVENT_TYPE_STATE_ROOM_NAME; + event.stateKey = Event.EVENT_TYPE_STATE_ROOM_NAME; + event.type = Event.EVENT_TYPE_STATE_ROOM_NAME; final RoomState backState = Mockito.spy(mTimelineStateHolder.getBackState()); mTimelineStateHolder.setBackState(backState); mTimelineStateHolder.processStateEvent(event, EventTimeline.Direction.BACKWARDS); From 5bcb05de4c292c8ecf62f95c8caea77506c666fd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Oct 2018 17:40:03 +0200 Subject: [PATCH 221/236] typo --- .../java/org/matrix/androidsdk/data/timeline/EventTimeline.java | 2 +- .../org/matrix/androidsdk/data/timeline/MXEventTimeline.java | 2 +- .../org/matrix/androidsdk/fragments/MatrixMessagesFragment.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java index 2d026cb47..d6aacc876 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/EventTimeline.java @@ -182,7 +182,7 @@ public interface EventTimeline { void cancelPaginationRequests(); /** - * Reset the pagination timelime and start loading the context around its `initialEventId`. + * Reset the pagination timeline and start loading the context around its `initialEventId`. * The retrieved (backwards and forwards) events will be sent to registered listeners. * * @param limit the maximum number of messages to get around the initial event. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java index 31cf9cbb7..a5f1fad5a 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/MXEventTimeline.java @@ -849,7 +849,7 @@ public void cancelPaginationRequests() { //============================================================================================================== /** - * Reset the pagination timelime and start loading the context around its `initialEventId`. + * Reset the pagination timeline and start loading the context around its `initialEventId`. * The retrieved (backwards and forwards) events will be sent to registered listeners. * * @param limit the maximum number of messages to get around the initial event. diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java index 59acb48ee..b48958424 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/fragments/MatrixMessagesFragment.java @@ -194,7 +194,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa if (mSession == null) { throw new RuntimeException("Must have valid default MXSession."); } - // get the timelime + // get the timeline if (null == mEventTimeline) { mEventTimeline = mMatrixMessagesListener.getEventTimeLine(); } else { From 268ad8696a8c808331ed3894120b8d042df3cc7a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Oct 2018 17:43:11 +0200 Subject: [PATCH 222/236] Fix unchecked assignment --- .../java/org/matrix/androidsdk/crypto/CryptoRestTest.java | 3 +-- .../java/org/matrix/androidsdk/crypto/CryptoTest.java | 8 ++++---- .../matrix/androidsdk/crypto/MXEncryptedAttachments.java | 2 +- .../java/org/matrix/androidsdk/crypto/MXOlmDevice.java | 2 +- .../matrix/androidsdk/rest/client/CryptoRestClient.java | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java index ae79721c2..4a13e1837 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java @@ -30,7 +30,6 @@ import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.common.SessionTestParams; import org.matrix.androidsdk.common.TestApiCallback; -import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXKey; import org.matrix.androidsdk.crypto.data.MXUsersDevicesMap; @@ -66,7 +65,7 @@ public void test01_testDeviceKeys() throws Exception { bobDevice.userId = bobSession.getMyUserId(); bobDevice.algorithms = Arrays.asList(MXCryptoAlgorithms.MXCRYPTO_ALGORITHM_OLM); - Map keysMap = new HashMap(); + Map keysMap = new HashMap<>(); keysMap.put("ed25519:" + bobDevice.deviceId, ed25519key); bobDevice.keys = keysMap; diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index efce6fdd8..26372f112 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -46,12 +46,12 @@ import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXOlmSessionResult; import org.matrix.androidsdk.crypto.data.MXUsersDevicesMap; -import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.Room; import org.matrix.androidsdk.data.RoomState; import org.matrix.androidsdk.data.store.IMXStore; import org.matrix.androidsdk.data.store.MXFileStore; import org.matrix.androidsdk.data.store.MXStoreListener; +import org.matrix.androidsdk.data.timeline.EventTimeline; import org.matrix.androidsdk.data.timeline.EventTimelineFactory; import org.matrix.androidsdk.listeners.MXEventListener; import org.matrix.androidsdk.rest.callback.ApiCallback; @@ -1080,7 +1080,7 @@ public void test11_testAliceAndBobInAEncryptedRoomBackPaginationFromMemoryStore( Log.e(LOG_TAG, "test11_testAliceAndBobInAEncryptedRoomBackPaginationFromMemoryStore"); Context context = InstrumentationRegistry.getContext(); - final Map results = new HashMap(); + final Map results = new HashMap<>(); Pair pair = doE2ETestWithAliceAndBobInARoom(true); MXSession aliceSession = pair.first.first; @@ -1171,7 +1171,7 @@ public void test12_testAliceAndBobInAEncryptedRoomBackPaginationFromHomeServer() Log.e(LOG_TAG, "test12_testAliceAndBobInAEncryptedRoomBackPaginationFromHomeServer"); Context context = InstrumentationRegistry.getContext(); - final Map results = new HashMap(); + final Map results = new HashMap<>(); Pair pair = doE2ETestWithAliceAndBobInARoom(true); MXSession aliceSession = pair.first.first; @@ -1225,7 +1225,7 @@ public void onSuccess(Integer info) { public void test13_testAliceAndNotEncryptedBobInACryptedRoom() throws Exception { Log.e(LOG_TAG, "test13_testAliceAndNotEncryptedBobInACryptedRoom"); - final Map results = new HashMap(); + final Map results = new HashMap<>(); Pair pair = doE2ETestWithAliceAndBobInARoom(false); final MXSession aliceSession = pair.first.first; diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXEncryptedAttachments.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXEncryptedAttachments.java index 6e300ef7c..40c05b0d8 100755 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXEncryptedAttachments.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXEncryptedAttachments.java @@ -117,7 +117,7 @@ public static EncryptionResult encryptAttachment(InputStream attachmentStream, S result.mEncryptedFileInfo.iv = Base64.encodeToString(initVectorBytes, Base64.DEFAULT).replace("\n", "").replace("=", ""); result.mEncryptedFileInfo.v = "v2"; - result.mEncryptedFileInfo.hashes = new HashMap(); + result.mEncryptedFileInfo.hashes = new HashMap<>(); result.mEncryptedFileInfo.hashes.put("sha256", base64ToUnpaddedBase64(Base64.encodeToString(messageDigest.digest(), Base64.DEFAULT))); result.mEncryptedStream = new ByteArrayInputStream(outStream.toByteArray()); diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXOlmDevice.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXOlmDevice.java index f23683de7..748591032 100755 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXOlmDevice.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/crypto/MXOlmDevice.java @@ -129,7 +129,7 @@ public MXOlmDevice(IMXCryptoStore store) { Log.e(LOG_TAG, "## MXOlmDevice : cannot find " + OlmAccount.JSON_KEY_FINGER_PRINT_KEY + " with error " + e.getMessage(), e); } - mInboundGroupSessionMessageIndexes = new HashMap(); + mInboundGroupSessionMessageIndexes = new HashMap<>(); } /** diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/CryptoRestClient.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/CryptoRestClient.java index 819cf8c08..4d441fd99 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/CryptoRestClient.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/client/CryptoRestClient.java @@ -160,7 +160,7 @@ public void onRetry() { public void success(KeysClaimResponse keysClaimResponse, Response response) { onEventSent(); - Map> map = new HashMap(); + Map> map = new HashMap<>(); if (null != keysClaimResponse.oneTimeKeys) { for (String userId : keysClaimResponse.oneTimeKeys.keySet()) { From 676531dbd38151831c807f222bb1f90ec532b188 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Oct 2018 17:59:32 +0200 Subject: [PATCH 223/236] Fix test 11 and 12 --- .../java/org/matrix/androidsdk/crypto/CryptoTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 26372f112..4dd0a0dbc 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -1082,7 +1082,7 @@ public void test11_testAliceAndBobInAEncryptedRoomBackPaginationFromMemoryStore( Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(true); MXSession aliceSession = pair.first.first; final String aliceRoomId = pair.first.second; MXSession bobSession = pair.second; @@ -1173,7 +1173,7 @@ public void test12_testAliceAndBobInAEncryptedRoomBackPaginationFromHomeServer() Context context = InstrumentationRegistry.getContext(); final Map results = new HashMap<>(); - Pair pair = doE2ETestWithAliceAndBobInARoom(true); + Pair pair = doE2ETestWithAliceAndBobInARoomWithEncryptedMessages(true); MXSession aliceSession = pair.first.first; final String aliceRoomId = pair.first.second; MXSession bobSession = pair.second; From b76e12f50874f78adf56ff565461edd354882820 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Oct 2018 18:12:22 +0200 Subject: [PATCH 224/236] Fix test 26 --- .../java/org/matrix/androidsdk/crypto/CryptoTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 4dd0a0dbc..8a707d645 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -2906,7 +2906,7 @@ public void onSuccess(Void info) { Assert.assertFalse(results.containsKey("eventListenerEncyptedSam2")); // verify the bob device - CountDownLatch lock8 = new CountDownLatch(3); + CountDownLatch lock8 = new CountDownLatch(1); aliceSession.getCrypto().setDeviceVerification(MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED, bobSession.getCrypto().getMyDevice().deviceId, bobSession.getMyUserId(), new TestApiCallback(lock8) { @@ -2920,7 +2920,7 @@ public void onSuccess(Void info) { mTestHelper.await(lock8); Assert.assertTrue(results.containsKey("setDeviceVerificationBob")); - CountDownLatch lock9 = new CountDownLatch(3); + CountDownLatch lock9 = new CountDownLatch(1); aliceSession.getCrypto().setRoomBlacklistUnverifiedDevices(roomFromAlicePOV.getRoomId(), new TestApiCallback(lock9) { @Override public void onSuccess(Void info) { @@ -2948,7 +2948,7 @@ public void onSuccess(Void info) { Assert.assertFalse(results.containsKey("eventListenerEncyptedBob2")); Assert.assertTrue(results.containsKey("eventListenerEncyptedSam2")); - CountDownLatch lock11 = new CountDownLatch(3); + CountDownLatch lock11 = new CountDownLatch(1); aliceSession.getCrypto().setRoomUnblacklistUnverifiedDevices(roomFromAlicePOV.getRoomId(), new TestApiCallback(lock11) { @Override public void onSuccess(Void info) { From 38dc8edc24a38ea90885dc9191e32b31e11ebaba Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Oct 2018 18:13:35 +0200 Subject: [PATCH 225/236] Fix test 27 --- .../java/org/matrix/androidsdk/crypto/CryptoTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java index 8a707d645..d19a996b7 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoTest.java @@ -3010,6 +3010,7 @@ public void onSuccess(Void info) { @Override public void onSuccess(Void info) { results.put("enableCrypto2", "enableCrypto2"); + super.onSuccess(info); } }); mTestHelper.await(lock00b); From 6f2c73fb276a6fcab50498fc40cc2cc49bf2708a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Oct 2018 18:32:17 +0200 Subject: [PATCH 226/236] Fix compilation issue after merge --- .../java/org/matrix/androidsdk/crypto/CryptoRestTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java index 4a13e1837..8e9aa5b6d 100644 --- a/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java +++ b/matrix-sdk/src/androidTest/java/org/matrix/androidsdk/crypto/CryptoRestTest.java @@ -30,6 +30,7 @@ import org.matrix.androidsdk.common.CommonTestHelper; import org.matrix.androidsdk.common.SessionTestParams; import org.matrix.androidsdk.common.TestApiCallback; +import org.matrix.androidsdk.common.TestConstants; import org.matrix.androidsdk.crypto.data.MXDeviceInfo; import org.matrix.androidsdk.crypto.data.MXKey; import org.matrix.androidsdk.crypto.data.MXUsersDevicesMap; From ec8cc05626aa5b81ff41fb9a8b856c3b25289cce Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Oct 2018 10:56:40 +0200 Subject: [PATCH 227/236] Fix compilation issue after rebase --- .../androidsdk/data/timeline/StateEventRedactionChecker.java | 2 +- .../androidsdk/data/timeline/TimelineLiveEventHandler.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java index a69dd7014..f4a077805 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/StateEventRedactionChecker.java @@ -60,7 +60,7 @@ public void checkStateEventRedaction(@NonNull final Event redactionEvent) { final Room room = mEventTimeline.getRoom(); final MXDataHandler dataHandler = room.getDataHandler(); final String roomId = room.getRoomId(); - final String eventId = redactionEvent.getRedacts(); + final String eventId = redactionEvent.getRedactedEventId(); final RoomState state = mTimelineStateHolder.getState(); Log.d(LOG_TAG, "checkStateEventRedaction of event " + eventId); // check if the state events is locally known diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java index 28926a2e2..1e2a15fc7 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/timeline/TimelineLiveEventHandler.java @@ -206,8 +206,8 @@ private void storeLiveRoomEvent(@NonNull final MXDataHandler dataHandler, String myUserId = dataHandler.getCredentials().userId; if (Event.EVENT_TYPE_REDACTION.equals(event.getType())) { - if (event.getRedacts() != null) { - Event eventToPrune = store.getEvent(event.getRedacts(), event.roomId); + if (event.getRedactedEventId() != null) { + Event eventToPrune = store.getEvent(event.getRedactedEventId(), event.roomId); // when an event is redacted, some fields must be kept. if (eventToPrune != null) { From 174ad1f19650566044f07670243ec9b5ccc18860 Mon Sep 17 00:00:00 2001 From: Giom Foret Date: Tue, 2 Oct 2018 11:12:57 +0200 Subject: [PATCH 228/236] HomeServerConnectionConfig: adopt some preceding cipher suites for Android < 20 to be able to negotiate a TLS session. --- .../androidsdk/HomeServerConnectionConfig.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java index d0ce2805c..fc1396116 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/HomeServerConnectionConfig.java @@ -482,10 +482,10 @@ public Builder withAllowHttpConnection() { * - https://developer.android.com/reference/javax/net/ssl/SSLEngine * * @param tlsLimitations true to use Tls limitations - * @param forceUsageOfTlsVersion set to true for Android < 20 + * @param enableCompatibilityMode set to true for Android < 20 * @return this builder */ - public Builder withTlsLimitations(boolean tlsLimitations, boolean forceUsageOfTlsVersion) { + public Builder withTlsLimitations(boolean tlsLimitations, boolean enableCompatibilityMode) { if (tlsLimitations) { withShouldAcceptTlsExtensions(false); @@ -493,7 +493,7 @@ public Builder withTlsLimitations(boolean tlsLimitations, boolean forceUsageOfTl addAcceptedTlsVersion(TlsVersion.TLS_1_2); addAcceptedTlsVersion(TlsVersion.TLS_1_3); - forceUsageOfTlsVersions(forceUsageOfTlsVersion); + forceUsageOfTlsVersions(enableCompatibilityMode); // Cipher suites addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256); @@ -504,6 +504,13 @@ public Builder withTlsLimitations(boolean tlsLimitations, boolean forceUsageOfTl addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384); addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256); addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256); + + if (enableCompatibilityMode) { + // Adopt some preceding cipher suites for Android < 20 to be able to negotiate + // a TLS session. + addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA); + addAcceptedTlsCipherSuite(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA); + } } return this; From d6421c37f47d9372abc8efcf620e5f2a8c2424bd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Oct 2018 11:22:42 +0200 Subject: [PATCH 229/236] Clean up CreateRoomResponse --- .../androidsdk/rest/model/CreateRoomResponse.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/CreateRoomResponse.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/CreateRoomResponse.java index e71dbf319..9d082dcc7 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/CreateRoomResponse.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/rest/model/CreateRoomResponse.java @@ -1,12 +1,13 @@ -/* +/* * Copyright 2014 OpenMarket Ltd - * + * Copyright 2018 New Vector Ltd + * * 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. @@ -15,7 +16,9 @@ */ package org.matrix.androidsdk.rest.model; +import com.google.gson.annotations.SerializedName; + public class CreateRoomResponse { + @SerializedName("room_id") public String roomId; - public String roomAlias; } From 990ea0e160fbf7bfd739a076526b6333d009eaa5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Oct 2018 14:57:31 +0200 Subject: [PATCH 230/236] Fix bug --- .../src/main/java/org/matrix/androidsdk/data/RoomState.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java index 840ac4c60..30d17eba6 100644 --- a/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java +++ b/matrix-sdk/src/main/java/org/matrix/androidsdk/data/RoomState.java @@ -325,7 +325,7 @@ public void onSuccess(List info) { /** * Tell if all members has been loaded * - * @return true is LazyLoading is Off, or if all members has been loaded + * @return true if LazyLoading is Off, or if all members has been loaded */ private boolean areAllMembersLoaded() { return mDataHandler != null @@ -336,7 +336,7 @@ private boolean areAllMembersLoaded() { * Force a fetch of the loaded members the next time they will be requested */ public void forceMembersRequest() { - mAllMembersAreLoaded = true; + mAllMembersAreLoaded = false; } /** From 984ab1e87cc3d4358f6865cfd6d97a14efa88229 Mon Sep 17 00:00:00 2001 From: Silvano Date: Thu, 20 Sep 2018 22:47:56 +0000 Subject: [PATCH 231/236] Translated using Weblate (Italian) Currently translated at 100.0% (59 of 59 strings) Translation: Riot Android/matrix-android-sdk Translate-URL: https://translate.riot.im/projects/riot-android/matrix-android-sdk/it/ --- matrix-sdk/src/main/res/values-it/strings.xml | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/matrix-sdk/src/main/res/values-it/strings.xml b/matrix-sdk/src/main/res/values-it/strings.xml index 35f0ca146..5348662fe 100644 --- a/matrix-sdk/src/main/res/values-it/strings.xml +++ b/matrix-sdk/src/main/res/values-it/strings.xml @@ -10,16 +10,16 @@ %1$s è entrato %1$s è uscito %1$s ha rifiutato l\'invito - %1$s ha cacciato %2$s - %1$s ha tolto il ban a %2$s + %1$s ha buttato fuori %2$s + %1$s ha tolto il bando a %2$s %1$s ha bandito %2$s %1$s ha revocato l\'invito per %2$s %1$s ha modificato il suo avatar - %1$s ha impostato il suo nome a %2$s - %1$s ha modificato il suo nome da %2$s a %3$s + %1$s hanno cambiato il nome visualizzato con %2$s + %1$s ha cambiato il nome visualizzato da %2$s a %3$s %1$s ha rimosso il nome visibile (%2$s) - %1$s ha modificato l\'argomento in: %2$s - %1$s ha modificato il nome della stanza in: %2$s + %1$s ha cambiato l\'argomento con: %2$s + %1$s ha cambiato il nome della stanza con: %2$s %s ha iniziato una chiamata video. %s ha iniziato una chiamata vocale. %s ha risposto alla chiamata. @@ -30,7 +30,7 @@ tutti i membri della stanza. chiunque. sconosciuto (%s). - %1$s ha attivato la cifratura end-to-end (%2$s) + %1$s ha attivato la crittografia end-to-end (%2$s) %1$s ha richiesto una conferenza VoIP Conferenza VoIP iniziata @@ -42,13 +42,13 @@ " da %1$s" " [motivo: %1$s]" %1$s ha aggiornato il profilo %2$s - %1$s ha mandato un\'invito a %2$s per unirsi alla stanza + %1$s ha mandato un invito a %2$s per unirsi alla stanza %1$s ha accettato l\'invito per %2$s - ** Impossibile decifrare: %s ** + ** Impossibile decriptare: %s ** Il dispositivo del mittente non ci ha inviato le chiavi per questo messaggio. - Impossibile correggere + Impossibile revisionare Impossibile inviare il messaggio Invio dell\'immagine fallito @@ -63,12 +63,12 @@ Indirizzo email Numero di telefono -"corretto %1$s " +"revisionato %1$s " %1$s ha inviato un adesivo. In risposta a - inviato un\'immagine. + inviata un\'immagine. inviato un video. inviato un file audio. inviato un file. From f84e0b32cd0cb7bac8be00d98bfee0dd0076892d Mon Sep 17 00:00:00 2001 From: Milena Brum Date: Tue, 4 Sep 2018 18:58:36 +0000 Subject: [PATCH 232/236] Translated using Weblate (Spanish) Currently translated at 100.0% (59 of 59 strings) Translation: Riot Android/matrix-android-sdk Translate-URL: https://translate.riot.im/projects/riot-android/matrix-android-sdk/es/ --- matrix-sdk/src/main/res/values-es/strings.xml | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/matrix-sdk/src/main/res/values-es/strings.xml b/matrix-sdk/src/main/res/values-es/strings.xml index 91ca7fd11..a6cc2bd70 100644 --- a/matrix-sdk/src/main/res/values-es/strings.xml +++ b/matrix-sdk/src/main/res/values-es/strings.xml @@ -1,6 +1,6 @@ - SDK Matrix Android + SDK de Matrix Android %1$s: %2$s %1$s envió una imagen. @@ -8,56 +8,56 @@ la invitación de %s %1$s invitó a %2$s %1$s te invitó - %1$s entró + %1$s se unió %1$s salió %1$s rechazó la invitación - %1$s ha vetado a %2$s - %1$s ha quitado el veto a %2$s - %1$s ha vetado a %2$s + %1$s expulsó a %2$s + %1$s le quitó el veto a %2$s + %1$s vetó a %2$s %1$s retiró la invitación de %2$s - %1$s cambió su foto de perfil - %1$s estableció %2$s como su nombre visible - %1$s cambió su nombre visible de %2$s a %3$s - %1$s retiró su nombre visible (%2$s) + %1$s cambió su avatar + %1$s estableció %2$s como su nombre público + %1$s cambió su nombre público de %2$s a %3$s + %1$s eliminó su nombre público (%2$s) %1$s cambió el tema a: %2$s %1$s cambió el nombre de la sala a: %2$s - %s comenzó una llamada de video. - %s comenzó una llamada de voz. - %s recibió la llmada. - %s terminó la llamada. - %1$s hizo visible el futuro historial a %2$s - todos los miembros de la sala, desde su invitación. - todos los miembros de la sala, desde cuando entraron. - todos los miembros. - cualquiera. + %s realizó una llamada de vídeo. + %s realizó una llamada de voz. + %s contestó la llamada. + %s finalizó la llamada. + %1$s hizo visible el historial futuro de la sala para %2$s + todos los miembros de la sala, desde el momento en que son invitados. + todos los miembros de la sala, desde el momento en que se unieron. + todos los miembros de la sala. + cualquier persona. desconocido (%s). %1$s activó el cifrado de extremo a extremo (%2$s) - %1$s solicitó una conferencia VoIP - conferencia VoIP iniciada - conferencia VoIP finalizada + %1$s solicitó una conferencia de vozIP + conferencia de vozIP iniciada + conferencia de vozIP finalizada - (foto de perfil también se cambió) - %1$s retiró el nombre de la sala - %1$s retiro el tema de la sala + (el avatar también se cambió) + %1$s eliminó el nombre de la sala + %1$s eliminó el tema de la sala redactado %1$s por %1$s [razón: %1$s] %1$s actualizó su perfil %2$s - %1$s envió una invitación a %2$s para entrar a la sala - %1$s aceptó la invitacion de %2$s + %1$s invitó a %2$s a unirse a la sala + %1$s aceptó la invitación para %2$s - ** No se puede descifrar: %s ** - El dispositivo del emisor no nos ha enviado las claves de este mensaje. + ** No es posible descifrar: %s ** + El dispositivo emisor no nos ha enviado las claves para este mensaje. - No se pudo retractar - No se pudo enviar el mensaje + No se pudo redactar + No es posible enviar el mensaje - La subida de la imagen falló + No se pudo cargar la imagen - Error de la red + Error de red Error de Matrix @@ -67,21 +67,21 @@ - No es posible volver a entrar en una sala vacía. + Actualmente no es posible volver a unirse a una sala vacía. Mensaje cifrado - Correo elecrónico + Dirección de correo electrónico Número telefónico - %1$s envió un sticker. + %1$s envió una pegatina. En respuesta a envió una imagen. - envió un video. - envió un archivo de sonido. + envió un vídeo. + envió un archivo de audio. envió un archivo. From deb8fc6e656574a6e98b2e3d0f762e12e21a7ccf Mon Sep 17 00:00:00 2001 From: Tiffany Thuy Kim Nguyen Date: Fri, 7 Sep 2018 04:23:15 +0000 Subject: [PATCH 233/236] Translated using Weblate (Spanish (Mexico)) Currently translated at 100.0% (59 of 59 strings) Translation: Riot Android/matrix-android-sdk Translate-URL: https://translate.riot.im/projects/riot-android/matrix-android-sdk/es_MX/ --- .../src/main/res/values-es-rMX/strings.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/matrix-sdk/src/main/res/values-es-rMX/strings.xml b/matrix-sdk/src/main/res/values-es-rMX/strings.xml index 6d3f4734b..57fb929b4 100644 --- a/matrix-sdk/src/main/res/values-es-rMX/strings.xml +++ b/matrix-sdk/src/main/res/values-es-rMX/strings.xml @@ -8,19 +8,19 @@ la invitación de %s %1$s invitó a %2$s %1$s te invitó - %1$s entro + %1$s se unió %1$s salió - %1$s rechasó la invitación + %1$s rechazó la invitación %1$s quitó a %2$s %1$s desprohibió a %2$s %1$s prohibió %2$s %1$s retiró la invitación de %2$s %1$s cambio su foto de perfil %1$s estableció %2$s como su nombre visible - %1$s cambio su nombre visible de %2$s a %3$s + %1$s cambió su nombre visible de %2$s a %3$s %1$s retiró su nombre visible (%2$s) %1$s cambio el tema a: %2$s - %1$s cambio el nombre de la sala a: %2$s + %1$s cambió el nombre de la sala a: %2$s %s comenzó una llamada de video. %s comenzó una llamada de voz. %s recibió la llmada. @@ -28,7 +28,7 @@ %1$s dejo que %2$s vea el historial del futuro todos los miembros de la sala, desde su invitación. todos los miembros de la sala, desde cuando entraron. - todos los miembros. + todos los miembros de la sala. todos. desconocido (%s). %1$s encendió el cifrado de extremo a extremo (%2$s) @@ -48,11 +48,11 @@ %1$s aceptó la invitacion de %2$s ** No se puede descifrar: %s ** - El dispositivo del enviador no nos ha enviado las claves de este mensaje. + El dispositivo del remitente no nos ha enviado las claves de este mensaje. No se pudo redactar - No se pudo enviar el mensaje + No se puede enviar el mensaje La subida de la imagen falló @@ -72,7 +72,7 @@ Mensaje cifrado - Correo elecrónico + Correo electrónico Número telefónico %1$s envió una pegatina. From 95ae9c9b992b95ca4702ba82d7b76a21114a6cc8 Mon Sep 17 00:00:00 2001 From: IMIN <2reeseenmin@gmail.com> Date: Tue, 2 Oct 2018 17:59:33 +0000 Subject: [PATCH 234/236] Added translation using Weblate (Korean) --- matrix-sdk/src/main/res/values-ko/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 matrix-sdk/src/main/res/values-ko/strings.xml diff --git a/matrix-sdk/src/main/res/values-ko/strings.xml b/matrix-sdk/src/main/res/values-ko/strings.xml new file mode 100644 index 000000000..a6b3daec9 --- /dev/null +++ b/matrix-sdk/src/main/res/values-ko/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From cf7b2dce2546d124ae62e18085c24e8e259f88ba Mon Sep 17 00:00:00 2001 From: IMIN <2reeseenmin@gmail.com> Date: Tue, 2 Oct 2018 18:10:43 +0000 Subject: [PATCH 235/236] Translated using Weblate (Korean) Currently translated at 5.0% (3 of 59 strings) Translation: Riot Android/matrix-android-sdk Translate-URL: https://translate.riot.im/projects/riot-android/matrix-android-sdk/ko/ --- matrix-sdk/src/main/res/values-ko/strings.xml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/matrix-sdk/src/main/res/values-ko/strings.xml b/matrix-sdk/src/main/res/values-ko/strings.xml index a6b3daec9..7c468208e 100644 --- a/matrix-sdk/src/main/res/values-ko/strings.xml +++ b/matrix-sdk/src/main/res/values-ko/strings.xml @@ -1,2 +1,6 @@ - - \ No newline at end of file + +Matrix 안드로이드 SDK + + %1$s: %2$s + %s\'의 초대 + From 190b65ec09422fcac0a9430de04d0bb7ba9c44da Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 8 Oct 2018 14:56:48 +0200 Subject: [PATCH 236/236] Prepare version --- CHANGES.rst | 11 +---------- matrix-sdk/build.gradle | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index d851bcae6..73e7b043e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,4 +1,4 @@ -Changes to Matrix Android SDK in 0.9.10 (2018-XX-XX) +Changes to Matrix Android SDK in 0.9.10 (2018-10-08) ======================================================= Features: @@ -22,19 +22,10 @@ API Change: - Parameter guestAccess removed from MxSession.createRoom(). It had no effect. - EventTimeline is now exposed as an interface. Use EventTimelineFactory to instantiate it. -Translations: - - - Others: - Boolean deserialization is more permissive: "1" or 1 will be handle as a true value (#358) - MXSession.setUseDataSaveMode(boolean) is now deprecated. Handle filter-id lookup in your app and use MXSession.setSyncFilterOrFilterId(String) -Build: - - - -Test: - - - Changes to Matrix Android SDK in 0.9.9 (2018-08-30) ======================================================= diff --git a/matrix-sdk/build.gradle b/matrix-sdk/build.gradle index df52fb6bd..641a2ee0e 100644 --- a/matrix-sdk/build.gradle +++ b/matrix-sdk/build.gradle @@ -15,7 +15,7 @@ android { minSdkVersion 16 targetSdkVersion 26 versionCode 910 - versionName "0.9.10-dev" + versionName "0.9.10" resValue "string", "flavor_description", "SDKApp" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" }