Merge branch 'develop' into feature/fix_#498

This commit is contained in:
ganfra 2019-10-30 19:26:11 +01:00 committed by GitHub
commit d47cf7e932
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 217 additions and 405 deletions

View file

@ -3,13 +3,35 @@
# https://github.com/buildkite-plugins/docker-buildkite-plugin/releases # https://github.com/buildkite-plugins/docker-buildkite-plugin/releases
# We propagate the environment to the container (sse https://github.com/buildkite-plugins/docker-buildkite-plugin#propagate-environment-optional-boolean) # We propagate the environment to the container (sse https://github.com/buildkite-plugins/docker-buildkite-plugin#propagate-environment-optional-boolean)
# Build debug version of the RiotX application, from the develop branch and the features branches
steps: steps:
- label: "Assemble GPlay Debug version" - label: "Compile and run Unit tests"
agents: agents:
# We use a medium sized instance instead of the normal small ones because # We use a medium sized instance instead of the normal small ones because
# gradle build is long # gradle build can be memory hungry
queue: "medium"
commands:
- "./gradlew clean test --stacktrace"
plugins:
- docker#v3.1.0:
image: "runmymind/docker-android-sdk"
propagate-environment: true
- label: "Compile Android tests"
agents:
# We use a medium sized instance instead of the normal small ones because
# gradle build can be memory hungry
queue: "medium"
commands:
- "./gradlew clean assembleAndroidTest --stacktrace"
plugins:
- docker#v3.1.0:
image: "runmymind/docker-android-sdk"
propagate-environment: true
- label: "Assemble GPlay Debug version"
agents:
# We use a xlarge sized instance instead of the normal small ones because
# gradle build can be memory hungry
queue: "xlarge" queue: "xlarge"
commands: commands:
- "./gradlew clean lintGplayRelease assembleGplayDebug --stacktrace" - "./gradlew clean lintGplayRelease assembleGplayDebug --stacktrace"
@ -23,8 +45,8 @@ steps:
- label: "Assemble FDroid Debug version" - label: "Assemble FDroid Debug version"
agents: agents:
# We use a medium sized instance instead of the normal small ones because # We use a xlarge sized instance instead of the normal small ones because
# gradle build is long # gradle build can be memory hungry
queue: "xlarge" queue: "xlarge"
commands: commands:
- "./gradlew clean lintFdroidRelease assembleFdroidDebug --stacktrace" - "./gradlew clean lintFdroidRelease assembleFdroidDebug --stacktrace"
@ -38,8 +60,8 @@ steps:
- label: "Build Google Play unsigned APK" - label: "Build Google Play unsigned APK"
agents: agents:
# We use a medium sized instance instead of the normal small ones because # We use a xlarge sized instance instead of the normal small ones because
# gradle build is long # gradle build can be memory hungry
queue: "xlarge" queue: "xlarge"
commands: commands:
- "./gradlew clean assembleGplayRelease --stacktrace" - "./gradlew clean assembleGplayRelease --stacktrace"

View file

@ -12,6 +12,7 @@ Other changes:
Bugfix 🐛: Bugfix 🐛:
- Fix issues with some member events rendering (#498) - Fix issues with some member events rendering (#498)
- Passphrase does not match (Export room keys) (#644)
Translations 🗣: Translations 🗣:
- -

View file

@ -11,6 +11,8 @@ android {
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
// Multidex is useful for tests
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }

View file

@ -1,42 +0,0 @@
/*
* Copyright 2019 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 im.vector.matrix.rx;
import android.content.Context;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("im.vector.matrix.rx.test", appContext.getPackageName());
}
}

View file

@ -1,33 +0,0 @@
/*
* Copyright 2019 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 im.vector.matrix.rx;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

View file

@ -155,7 +155,8 @@ dependencies {
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
testImplementation 'org.robolectric:robolectric:4.3' testImplementation 'org.robolectric:robolectric:4.3'
//testImplementation 'org.robolectric:shadows-support-v4:3.0' //testImplementation 'org.robolectric:shadows-support-v4:3.0'
testImplementation 'io.mockk:mockk:1.9.3.kotlin12' // Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
testImplementation 'io.mockk:mockk:1.9.2.kotlin12'
testImplementation 'org.amshove.kluent:kluent-android:1.44' testImplementation 'org.amshove.kluent:kluent-android:1.44'
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
@ -165,7 +166,8 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
androidTestImplementation 'org.amshove.kluent:kluent-android:1.44' androidTestImplementation 'org.amshove.kluent:kluent-android:1.44'
androidTestImplementation 'io.mockk:mockk-android:1.9.3.kotlin12' // Note: version sticks to 1.9.2 due to https://github.com/mockk/mockk/issues/281
androidTestImplementation 'io.mockk:mockk-android:1.9.2.kotlin12'
androidTestImplementation "androidx.arch.core:core-testing:$lifecycle_version" androidTestImplementation "androidx.arch.core:core-testing:$lifecycle_version"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"

View file

@ -17,12 +17,12 @@
package im.vector.matrix.android package im.vector.matrix.android
import android.content.Context import android.content.Context
import androidx.test.InstrumentationRegistry import androidx.test.core.app.ApplicationProvider
import java.io.File import java.io.File
interface InstrumentedTest { interface InstrumentedTest {
fun context(): Context { fun context(): Context {
return InstrumentationRegistry.getTargetContext() return ApplicationProvider.getApplicationContext()
} }
fun cacheDir(): File { fun cacheDir(): File {

View file

@ -17,8 +17,8 @@
package im.vector.matrix.android.auth package im.vector.matrix.android.auth
import androidx.test.annotation.UiThreadTest import androidx.test.annotation.UiThreadTest
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.GrantPermissionRule import androidx.test.rule.GrantPermissionRule
import androidx.test.runner.AndroidJUnit4
import im.vector.matrix.android.InstrumentedTest import im.vector.matrix.android.InstrumentedTest
import im.vector.matrix.android.OkReplayRuleChainNoActivity import im.vector.matrix.android.OkReplayRuleChainNoActivity
import im.vector.matrix.android.api.auth.Authenticator import im.vector.matrix.android.api.auth.Authenticator

View file

@ -16,7 +16,7 @@
package im.vector.matrix.android.api.session.events.model package im.vector.matrix.android.api.session.events.model
import java.util.* import java.util.UUID
object LocalEcho { object LocalEcho {

View file

@ -66,7 +66,7 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
if (':' in userId) { if (':' in userId) {
try { try {
synchronized(notReadyToRetryHS) { synchronized(notReadyToRetryHS) {
res = !notReadyToRetryHS.contains(userId.substring(userId.lastIndexOf(":") + 1)) res = !notReadyToRetryHS.contains(userId.substringAfterLast(':'))
} }
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "## canRetryKeysDownload() failed") Timber.e(e, "## canRetryKeysDownload() failed")

View file

@ -216,7 +216,7 @@ internal class OutgoingRoomKeyRequestManager @Inject constructor(
sendMessageToDevices(requestMessage, request.recipients, request.requestId, object : MatrixCallback<Unit> { sendMessageToDevices(requestMessage, request.recipients, request.requestId, object : MatrixCallback<Unit> {
private fun onDone(state: OutgoingRoomKeyRequest.RequestState) { private fun onDone(state: OutgoingRoomKeyRequest.RequestState) {
if (request.state !== OutgoingRoomKeyRequest.RequestState.UNSENT) { if (request.state !== OutgoingRoomKeyRequest.RequestState.UNSENT) {
Timber.v("## sendOutgoingRoomKeyRequest() : Cannot update room key request from UNSENT as it was already updated to " + request.state) Timber.v("## sendOutgoingRoomKeyRequest() : Cannot update room key request from UNSENT as it was already updated to ${request.state}")
} else { } else {
request.state = state request.state = state
cryptoStore.updateOutgoingRoomKeyRequest(request) cryptoStore.updateOutgoingRoomKeyRequest(request)

View file

@ -43,6 +43,7 @@ import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import java.lang.Exception
import java.util.UUID import java.util.UUID
import javax.inject.Inject import javax.inject.Inject
import kotlin.collections.HashMap import kotlin.collections.HashMap
@ -166,72 +167,59 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre
return return
} }
// Download device keys prior to everything // Download device keys prior to everything
checkKeysAreDownloaded( if (checkKeysAreDownloaded(otherUserId!!, startReq) != null) {
otherUserId!!, Timber.v("## SAS onStartRequestReceived ${startReq.transactionID!!}")
startReq, val tid = startReq.transactionID!!
success = { val existing = getExistingTransaction(otherUserId, tid)
Timber.v("## SAS onStartRequestReceived ${startReq.transactionID!!}") val existingTxs = getExistingTransactionsForUser(otherUserId)
val tid = startReq.transactionID!! if (existing != null) {
val existing = getExistingTransaction(otherUserId, tid) // should cancel both!
val existingTxs = getExistingTransactionsForUser(otherUserId) Timber.v("## SAS onStartRequestReceived - Request exist with same if ${startReq.transactionID!!}")
if (existing != null) { existing.cancel(CancelCode.UnexpectedMessage)
// should cancel both! cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
Timber.v("## SAS onStartRequestReceived - Request exist with same if ${startReq.transactionID!!}") } else if (existingTxs?.isEmpty() == false) {
existing.cancel(CancelCode.UnexpectedMessage) Timber.v("## SAS onStartRequestReceived - There is already a transaction with this user ${startReq.transactionID!!}")
cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage) // Multiple keyshares between two devices: any two devices may only have at most one key verification in flight at a time.
} else if (existingTxs?.isEmpty() == false) { existingTxs.forEach {
Timber.v("## SAS onStartRequestReceived - There is already a transaction with this user ${startReq.transactionID!!}") it.cancel(CancelCode.UnexpectedMessage)
// Multiple keyshares between two devices: any two devices may only have at most one key verification in flight at a time. }
existingTxs.forEach { cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
it.cancel(CancelCode.UnexpectedMessage) } else {
} // Ok we can create
cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage) if (KeyVerificationStart.VERIF_METHOD_SAS == startReq.method) {
} else { Timber.v("## SAS onStartRequestReceived - request accepted ${startReq.transactionID!!}")
// Ok we can create val tx = IncomingSASVerificationTransaction(
if (KeyVerificationStart.VERIF_METHOD_SAS == startReq.method) { this,
Timber.v("## SAS onStartRequestReceived - request accepted ${startReq.transactionID!!}") setDeviceVerificationAction,
val tx = IncomingSASVerificationTransaction( credentials,
this, cryptoStore,
setDeviceVerificationAction, sendToDeviceTask,
credentials, taskExecutor,
cryptoStore, myDeviceInfoHolder.get().myDevice.fingerprint()!!,
sendToDeviceTask, startReq.transactionID!!,
taskExecutor, otherUserId)
myDeviceInfoHolder.get().myDevice.fingerprint()!!, addTransaction(tx)
startReq.transactionID!!, tx.acceptToDeviceEvent(otherUserId, startReq)
otherUserId) } else {
addTransaction(tx) Timber.e("## SAS onStartRequestReceived - unknown method ${startReq.method}")
tx.acceptToDeviceEvent(otherUserId, startReq) cancelTransaction(tid, otherUserId, startReq.fromDevice
} else { ?: event.getSenderKey()!!, CancelCode.UnknownMethod)
Timber.e("## SAS onStartRequestReceived - unknown method ${startReq.method}") }
cancelTransaction(tid, otherUserId, startReq.fromDevice }
?: event.getSenderKey()!!, CancelCode.UnknownMethod) } else {
} cancelTransaction(startReq.transactionID!!, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
} }
},
error = {
cancelTransaction(startReq.transactionID!!, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
})
} }
private suspend fun checkKeysAreDownloaded(otherUserId: String, private suspend fun checkKeysAreDownloaded(otherUserId: String,
startReq: KeyVerificationStart, startReq: KeyVerificationStart): MXUsersDevicesMap<MXDeviceInfo>? {
success: (MXUsersDevicesMap<MXDeviceInfo>) -> Unit, return try {
error: () -> Unit) { val keys = deviceListManager.downloadKeys(listOf(otherUserId), true)
runCatching { val deviceIds = keys.getUserDeviceIds(otherUserId) ?: return null
deviceListManager.downloadKeys(listOf(otherUserId), true) keys.takeIf { deviceIds.contains(startReq.fromDevice) }
}.fold( } catch (e: Exception) {
{ null
if (it.getUserDeviceIds(otherUserId)?.contains(startReq.fromDevice) == true) { }
success(it)
} else {
error()
}
},
{
error()
}
)
} }
private suspend fun onCancelReceived(event: Event) { private suspend fun onCancelReceived(event: Event) {
@ -342,10 +330,8 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre
private fun addTransaction(tx: VerificationTransaction) { private fun addTransaction(tx: VerificationTransaction) {
tx.otherUserId.let { otherUserId -> tx.otherUserId.let { otherUserId ->
synchronized(txMap) { synchronized(txMap) {
if (txMap[otherUserId] == null) { val txInnerMap = txMap.getOrPut(otherUserId) { HashMap() }
txMap[otherUserId] = HashMap() txInnerMap[tx.transactionId] = tx
}
txMap[otherUserId]?.set(tx.transactionId, tx)
dispatchTxAdded(tx) dispatchTxAdded(tx)
tx.addListener(this) tx.addListener(this)
} }

View file

@ -22,7 +22,7 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.tag.RoomTag import im.vector.matrix.android.api.session.room.model.tag.RoomTag
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
import java.util.* import java.util.UUID
import javax.inject.Inject import javax.inject.Inject
internal class RoomSummaryMapper @Inject constructor( internal class RoomSummaryMapper @Inject constructor(

View file

@ -22,7 +22,7 @@ import com.novoda.merlin.MerlinsBeard
import im.vector.matrix.android.internal.di.MatrixScope import im.vector.matrix.android.internal.di.MatrixScope
import im.vector.matrix.android.internal.util.BackgroundDetectionObserver import im.vector.matrix.android.internal.util.BackgroundDetectionObserver
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.Collections
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.suspendCoroutine

View file

@ -23,7 +23,7 @@ import im.vector.matrix.android.internal.database.query.getOrCreate
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction import im.vector.matrix.android.internal.util.awaitTransaction
import java.util.* import java.util.Date
import javax.inject.Inject import javax.inject.Inject
internal interface GetHomeServerCapabilitiesTask : Task<Unit, Unit> internal interface GetHomeServerCapabilitiesTask : Task<Unit, Unit>

View file

@ -32,7 +32,7 @@ import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.worker.WorkManagerUtil import im.vector.matrix.android.internal.worker.WorkManagerUtil
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
import im.vector.matrix.android.internal.worker.WorkerParamsFactory import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import java.util.* import java.util.UUID
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject

View file

@ -39,7 +39,6 @@ import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
import im.vector.matrix.android.internal.util.StringProvider import im.vector.matrix.android.internal.util.StringProvider
import org.commonmark.parser.Parser import org.commonmark.parser.Parser
import org.commonmark.renderer.html.HtmlRenderer import org.commonmark.renderer.html.HtmlRenderer
import java.util.*
import javax.inject.Inject import javax.inject.Inject
/** /**

View file

@ -52,7 +52,8 @@ import io.realm.RealmQuery
import io.realm.RealmResults import io.realm.RealmResults
import io.realm.Sort import io.realm.Sort
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.Collections
import java.util.UUID
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
import kotlin.collections.ArrayList import kotlin.collections.ArrayList

View file

@ -31,7 +31,7 @@ import java.security.KeyPairGenerator
import java.security.KeyStore import java.security.KeyStore
import java.security.KeyStoreException import java.security.KeyStoreException
import java.security.SecureRandom import java.security.SecureRandom
import java.util.* import java.util.Calendar
import javax.crypto.* import javax.crypto.*
import javax.crypto.spec.GCMParameterSpec import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.IvParameterSpec

View file

@ -36,7 +36,7 @@ import java.security.*
import java.security.cert.CertificateException import java.security.cert.CertificateException
import java.security.spec.AlgorithmParameterSpec import java.security.spec.AlgorithmParameterSpec
import java.security.spec.RSAKeyGenParameterSpec import java.security.spec.RSAKeyGenParameterSpec
import java.util.* import java.util.Calendar
import java.util.zip.GZIPOutputStream import java.util.zip.GZIPOutputStream
import javax.crypto.* import javax.crypto.*
import javax.crypto.spec.GCMParameterSpec import javax.crypto.spec.GCMParameterSpec

View file

@ -18,7 +18,7 @@ package im.vector.matrix.android.internal.util
import im.vector.matrix.android.api.MatrixPatterns import im.vector.matrix.android.api.MatrixPatterns
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.Locale
/** /**
* Convert a string to an UTF8 String * Convert a string to an UTF8 String

View file

@ -18,7 +18,7 @@ package im.vector.matrix.android.api.pushrules
import im.vector.matrix.android.api.pushrules.rest.PushRule import im.vector.matrix.android.api.pushrules.rest.PushRule
import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.di.MoshiProvider
import org.junit.Assert import org.junit.Assert.*
import org.junit.Test import org.junit.Test
class PushRuleActionsTest { class PushRuleActionsTest {
@ -63,22 +63,17 @@ class PushRuleActionsTest {
val pushRule = MoshiProvider.providesMoshi().adapter<PushRule>(PushRule::class.java).fromJson(rawPushRule) val pushRule = MoshiProvider.providesMoshi().adapter<PushRule>(PushRule::class.java).fromJson(rawPushRule)
Assert.assertNotNull("Should have parsed the rule", pushRule) assertNotNull("Should have parsed the rule", pushRule)
Assert.assertNotNull("Failed to parse actions", Action.mapFrom(pushRule!!))
val actions = Action.mapFrom(pushRule) val actions = pushRule!!.getActions()
Assert.assertEquals(3, actions!!.size) assertEquals(3, actions.size)
Assert.assertEquals("First action should be notify", Action.Type.NOTIFY, actions[0].type) assertTrue("First action should be notify", actions[0] is Action.Notify)
Assert.assertEquals("Second action should be tweak", Action.Type.SET_TWEAK, actions[1].type) assertTrue("Second action should be sound", actions[1] is Action.Sound)
Assert.assertEquals("Second action tweak key should be sound", "sound", actions[1].tweak_action) assertEquals("Second action should have default sound", "default", (actions[1] as Action.Sound).sound)
Assert.assertEquals("Second action should have default as stringValue", "default", actions[1].stringValue)
Assert.assertNull("Second action boolValue should be null", actions[1].boolValue)
Assert.assertEquals("Third action should be tweak", Action.Type.SET_TWEAK, actions[2].type) assertTrue("Third action should be highlight", actions[2] is Action.Highlight)
Assert.assertEquals("Third action tweak key should be highlight", "highlight", actions[2].tweak_action) assertEquals("Third action tweak param should be false", false, (actions[2] as Action.Highlight).highlight)
Assert.assertEquals("Third action tweak param should be false", false, actions[2].boolValue)
Assert.assertNull("Third action stringValue should be null", actions[2].stringValue)
} }
} }

View file

@ -199,6 +199,10 @@ class PushrulesConditionTest {
} }
class MockRoom(override val roomId: String, val _numberOfJoinedMembers: Int) : Room { class MockRoom(override val roomId: String, val _numberOfJoinedMembers: Int) : Room {
override fun reportContent(eventId: String, score: Int, reason: String, callback: MatrixCallback<Unit>): Cancelable {
TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
}
override fun getReadMarkerLive(): LiveData<Optional<String>> { override fun getReadMarkerLive(): LiveData<Optional<String>> {
TODO("not implemented") // To change body of created functions use File | Settings | File Templates. TODO("not implemented") // To change body of created functions use File | Settings | File Templates.
} }

View file

@ -1,40 +0,0 @@
/*
* Copyright 2019 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 im.vector.riotx
import androidx.test.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getTargetContext()
assertEquals("im.vector.riotx", appContext.packageName)
}
}

View file

@ -55,7 +55,8 @@ import im.vector.riotx.features.version.VersionProvider
import im.vector.riotx.push.fcm.FcmHelper import im.vector.riotx.push.fcm.FcmHelper
import timber.log.Timber import timber.log.Timber
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.Date
import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.Provider, androidx.work.Configuration.Provider { class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.Provider, androidx.work.Configuration.Provider {

View file

@ -44,15 +44,15 @@ class ExportKeysDialog {
val textWatcher = object : SimpleTextWatcher() { val textWatcher = object : SimpleTextWatcher() {
override fun afterTextChanged(s: Editable) { override fun afterTextChanged(s: Editable) {
when { when {
passPhrase1EditText.text.isNullOrEmpty() -> { passPhrase1EditText.text.isNullOrEmpty() -> {
exportButton.isEnabled = false exportButton.isEnabled = false
passPhrase2Til.error = null passPhrase2Til.error = null
} }
passPhrase1EditText.text == passPhrase2EditText.text -> { passPhrase1EditText.text.toString() == passPhrase2EditText.text.toString() -> {
exportButton.isEnabled = true exportButton.isEnabled = true
passPhrase2Til.error = null passPhrase2Til.error = null
} }
else -> { else -> {
exportButton.isEnabled = false exportButton.isEnabled = false
passPhrase2Til.error = activity.getString(R.string.passphrase_passphrase_does_not_match) passPhrase2Til.error = activity.getString(R.string.passphrase_passphrase_does_not_match)
} }

View file

@ -30,15 +30,10 @@ import java.io.File
*/ */
@WorkerThread @WorkerThread
fun writeToFile(str: String, file: File): Try<Unit> { fun writeToFile(str: String, file: File): Try<Unit> {
return Try { return Try<Unit> {
val sink = file.sink() file.sink().buffer().use {
it.writeString(str, Charsets.UTF_8)
val bufferedSink = sink.buffer() }
bufferedSink.writeString(str, Charsets.UTF_8)
bufferedSink.close()
sink.close()
} }
} }
@ -47,15 +42,10 @@ fun writeToFile(str: String, file: File): Try<Unit> {
*/ */
@WorkerThread @WorkerThread
fun writeToFile(data: ByteArray, file: File): Try<Unit> { fun writeToFile(data: ByteArray, file: File): Try<Unit> {
return Try { return Try<Unit> {
val sink = file.sink() file.sink().buffer().use {
it.write(data)
val bufferedSink = sink.buffer() }
bufferedSink.write(data)
bufferedSink.close()
sink.close()
} }
} }

View file

@ -17,7 +17,6 @@
package im.vector.riotx.core.images package im.vector.riotx.core.images
import android.content.Context import android.content.Context
import android.database.Cursor
import android.net.Uri import android.net.Uri
import android.provider.MediaStore import android.provider.MediaStore
import androidx.exifinterface.media.ExifInterface import androidx.exifinterface.media.ExifInterface
@ -37,26 +36,24 @@ class ImageTools @Inject constructor(private val context: Context) {
if (uri.scheme == "content") { if (uri.scheme == "content") {
val proj = arrayOf(MediaStore.Images.Media.DATA) val proj = arrayOf(MediaStore.Images.Media.DATA)
var cursor: Cursor? = null
try { try {
cursor = context.contentResolver.query(uri, proj, null, null, null) val cursor = context.contentResolver.query(uri, proj, null, null, null)
if (cursor != null && cursor.count > 0) { cursor?.use {
cursor.moveToFirst() if (it.moveToFirst()) {
val idxData = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) val idxData = it.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
val path = cursor.getString(idxData) val path = it.getString(idxData)
if (path.isNullOrBlank()) { if (path.isNullOrBlank()) {
Timber.w("Cannot find path in media db for uri $uri") Timber.w("Cannot find path in media db for uri $uri")
return orientation return orientation
}
val exif = ExifInterface(path)
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)
} }
val exif = ExifInterface(path)
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)
} }
} catch (e: Exception) { } catch (e: Exception) {
// eg SecurityException from com.google.android.apps.photos.content.GooglePhotosImageProvider URIs // eg SecurityException from com.google.android.apps.photos.content.GooglePhotosImageProvider URIs
// eg IOException from trying to parse the returned path as a file when it is an http uri. // eg IOException from trying to parse the returned path as a file when it is an http uri.
Timber.e(e, "Cannot get orientation for bitmap") Timber.e(e, "Cannot get orientation for bitmap")
} finally {
cursor?.close()
} }
} else if (uri.scheme == "file") { } else if (uri.scheme == "file") {
try { try {

View file

@ -17,28 +17,17 @@
package im.vector.riotx.core.intent package im.vector.riotx.core.intent
import android.content.Context import android.content.Context
import android.database.Cursor
import android.net.Uri import android.net.Uri
import android.provider.OpenableColumns import android.provider.OpenableColumns
fun getFilenameFromUri(context: Context?, uri: Uri): String? { fun getFilenameFromUri(context: Context?, uri: Uri): String? {
var result: String? = null
if (context != null && uri.scheme == "content") { if (context != null && uri.scheme == "content") {
val cursor: Cursor? = context.contentResolver.query(uri, null, null, null, null) val cursor = context.contentResolver.query(uri, null, null, null, null)
try { cursor?.use {
if (cursor != null && cursor.moveToFirst()) { if (it.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)) return it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
} }
} finally {
cursor?.close()
} }
} }
if (result == null) { return uri.path?.substringAfterLast('/')
result = uri.path
val cut = result?.lastIndexOf('/') ?: -1
if (cut != -1) {
result = result?.substring(cut + 1)
}
}
return result
} }

View file

@ -15,8 +15,6 @@
*/ */
package im.vector.riotx.core.linkify package im.vector.riotx.core.linkify
import java.util.regex.Pattern
/** /**
* Better support for geo URi * Better support for geo URi
*/ */
@ -26,7 +24,7 @@ object VectorAutoLinkPatterns {
private const val LAT_OR_LONG_OR_ALT_NUMBER = "-?\\d+(?:\\.\\d+)?" private const val LAT_OR_LONG_OR_ALT_NUMBER = "-?\\d+(?:\\.\\d+)?"
private const val COORDINATE_SYSTEM = ";crs=[\\w-]+" private const val COORDINATE_SYSTEM = ";crs=[\\w-]+"
val GEO_URI: Pattern = Pattern.compile("(?:geo:)?" + val GEO_URI: Regex = Regex("(?:geo:)?" +
"(" + LAT_OR_LONG_OR_ALT_NUMBER + ")" + "(" + LAT_OR_LONG_OR_ALT_NUMBER + ")" +
"," + "," +
"(" + LAT_OR_LONG_OR_ALT_NUMBER + ")" + "(" + LAT_OR_LONG_OR_ALT_NUMBER + ")" +
@ -35,5 +33,5 @@ object VectorAutoLinkPatterns {
"(?:" + ";u=\\d+(?:\\.\\d+)?" + ")?" + // uncertainty in meters "(?:" + ";u=\\d+(?:\\.\\d+)?" + ")?" + // uncertainty in meters
"(?:" + "(?:" +
";[\\w-]+=(?:[\\w-_.!~*'()]|%[\\da-f][\\da-f])+" + // dafuk ";[\\w-]+=(?:[\\w-_.!~*'()]|%[\\da-f][\\da-f])+" + // dafuk
")*", Pattern.CASE_INSENSITIVE) ")*", RegexOption.IGNORE_CASE)
} }

View file

@ -19,7 +19,6 @@ import android.text.Spannable
import android.text.style.URLSpan import android.text.style.URLSpan
import android.text.util.Linkify import android.text.util.Linkify
import androidx.core.text.util.LinkifyCompat import androidx.core.text.util.LinkifyCompat
import java.util.*
object VectorLinkify { object VectorLinkify {
/** /**
@ -95,7 +94,7 @@ object VectorLinkify {
createdSpans.add(LinkSpec(URLSpan(urlSpan.url), start, end)) createdSpans.add(LinkSpec(URLSpan(urlSpan.url), start, end))
} }
LinkifyCompat.addLinks(spannable, VectorAutoLinkPatterns.GEO_URI, "geo:", arrayOf("geo:"), geoMatchFilter, null) LinkifyCompat.addLinks(spannable, VectorAutoLinkPatterns.GEO_URI.toPattern(), "geo:", arrayOf("geo:"), geoMatchFilter, null)
spannable.forEachSpanIndexed { _, urlSpan, start, end -> spannable.forEachSpanIndexed { _, urlSpan, start, end ->
spannable.removeSpan(urlSpan) spannable.removeSpan(urlSpan)
createdSpans.add(LinkSpec(URLSpan(urlSpan.url), start, end)) createdSpans.add(LinkSpec(URLSpan(urlSpan.url), start, end))
@ -108,7 +107,7 @@ object VectorLinkify {
} }
private fun pruneOverlaps(links: ArrayList<LinkSpec>) { private fun pruneOverlaps(links: ArrayList<LinkSpec>) {
Collections.sort(links, COMPARATOR) links.sortWith(COMPARATOR)
var len = links.size var len = links.size
var i = 0 var i = 0
while (i < len - 1) { while (i < len - 1) {

View file

@ -30,7 +30,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import im.vector.riotx.core.di.DaggerScreenComponent import im.vector.riotx.core.di.DaggerScreenComponent
import im.vector.riotx.core.di.ScreenComponent import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.utils.DimensionConverter import im.vector.riotx.core.utils.DimensionConverter
import java.util.* import java.util.UUID
/** /**
* Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment) * Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment)

View file

@ -22,8 +22,9 @@ import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.resources.AppNameProvider import im.vector.riotx.core.resources.AppNameProvider
import im.vector.riotx.core.resources.LocaleProvider import im.vector.riotx.core.resources.LocaleProvider
import im.vector.riotx.core.resources.StringProvider import im.vector.riotx.core.resources.StringProvider
import java.util.* import java.util.UUID
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs
private const val DEFAULT_PUSHER_FILE_TAG = "mobile" private const val DEFAULT_PUSHER_FILE_TAG = "mobile"
@ -36,7 +37,7 @@ class PushersManager @Inject constructor(
fun registerPusherWithFcmKey(pushKey: String): UUID { fun registerPusherWithFcmKey(pushKey: String): UUID {
val currentSession = activeSessionHolder.getActiveSession() val currentSession = activeSessionHolder.getActiveSession()
var profileTag = DEFAULT_PUSHER_FILE_TAG + "_" + Math.abs(currentSession.myUserId.hashCode()) val profileTag = DEFAULT_PUSHER_FILE_TAG + "_" + abs(currentSession.myUserId.hashCode())
return currentSession.addHttpPusher( return currentSession.addHttpPusher(
pushKey, pushKey,

View file

@ -18,7 +18,7 @@ package im.vector.riotx.core.resources
import android.content.res.Resources import android.content.res.Resources
import androidx.core.os.ConfigurationCompat import androidx.core.os.ConfigurationCompat
import java.util.* import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
class LocaleProvider @Inject constructor(private val resources: Resources) { class LocaleProvider @Inject constructor(private val resources: Resources) {

View file

@ -16,7 +16,7 @@
package im.vector.riotx.core.utils package im.vector.riotx.core.utils
import android.view.View import android.view.View
import java.util.* import java.util.WeakHashMap
/** /**
* Simple Debounced OnClickListener * Simple Debounced OnClickListener

View file

@ -59,9 +59,10 @@ fun initKnownEmojiHashSet(context: Context, done: (() -> Unit)? = null) {
val jsonAdapter = moshi.adapter(EmojiDataSource.EmojiData::class.java) val jsonAdapter = moshi.adapter(EmojiDataSource.EmojiData::class.java)
val inputAsString = input.bufferedReader().use { it.readText() } val inputAsString = input.bufferedReader().use { it.readText() }
val source = jsonAdapter.fromJson(inputAsString) val source = jsonAdapter.fromJson(inputAsString)
knownEmojiSet = HashSet<String>() knownEmojiSet = HashSet<String>().also {
source?.emojis?.values?.forEach { source?.emojis?.mapTo(it) { (_, value) ->
knownEmojiSet?.add(it.emojiString()) value.emojiString()
}
} }
done?.invoke() done?.invoke()
} }

View file

@ -32,7 +32,8 @@ import im.vector.riotx.R
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.Date
import java.util.Locale
/** /**
* Open a url in the internet browser of the system * Open a url in the internet browser of the system

View file

@ -31,7 +31,7 @@ import im.vector.riotx.R
import im.vector.riotx.features.notifications.NotificationUtils import im.vector.riotx.features.notifications.NotificationUtils
import im.vector.riotx.features.settings.VectorLocale import im.vector.riotx.features.settings.VectorLocale
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.Locale
/** /**
* Tells if the application ignores battery optimizations. * Tells if the application ignores battery optimizations.

View file

@ -19,7 +19,7 @@ package im.vector.riotx.core.utils
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import android.text.format.Formatter import android.text.format.Formatter
import java.util.* import java.util.TreeMap
object TextUtils { object TextUtils {

View file

@ -24,7 +24,7 @@ import im.vector.riotx.features.settings.FontScale
import im.vector.riotx.features.settings.VectorLocale import im.vector.riotx.features.settings.VectorLocale
import im.vector.riotx.features.themes.ThemeUtils import im.vector.riotx.features.themes.ThemeUtils
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
/** /**

View file

@ -18,10 +18,10 @@ package im.vector.riotx.features.crypto.keys
import android.content.Context import android.content.Context
import android.os.Environment import android.os.Environment
import arrow.core.Try
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.internal.extensions.foldToCallback import im.vector.matrix.android.internal.extensions.foldToCallback
import im.vector.matrix.android.internal.util.awaitCallback
import im.vector.riotx.core.files.addEntryToDownloadManager import im.vector.riotx.core.files.addEntryToDownloadManager
import im.vector.riotx.core.files.writeToFile import im.vector.riotx.core.files.writeToFile
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -36,28 +36,20 @@ class KeysExporter(private val session: Session) {
* Export keys and return the file path with the callback * Export keys and return the file path with the callback
*/ */
fun export(context: Context, password: String, callback: MatrixCallback<String>) { fun export(context: Context, password: String, callback: MatrixCallback<String>) {
session.exportRoomKeys(password, object : MatrixCallback<ByteArray> { GlobalScope.launch(Dispatchers.Main) {
override fun onSuccess(data: ByteArray) { runCatching {
GlobalScope.launch(Dispatchers.Main) { val data = awaitCallback<ByteArray> { session.exportRoomKeys(password, it) }
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
Try { val parentDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val parentDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) val file = File(parentDir, "riotx-keys-" + System.currentTimeMillis() + ".txt")
val file = File(parentDir, "riotx-keys-" + System.currentTimeMillis() + ".txt")
writeToFile(data, file) writeToFile(data, file)
addEntryToDownloadManager(context, file, "text/plain") addEntryToDownloadManager(context, file, "text/plain")
file.absolutePath file.absolutePath
}
}
.foldToCallback(callback)
} }
} }.foldToCallback(callback)
}
override fun onFailure(failure: Throwable) {
callback.onFailure(failure)
}
})
} }
} }

View file

@ -18,10 +18,11 @@ package im.vector.riotx.features.crypto.keys
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import arrow.core.Try
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult
import im.vector.matrix.android.internal.extensions.foldToCallback
import im.vector.matrix.android.internal.util.awaitCallback
import im.vector.riotx.core.intent.getMimeTypeFromUri import im.vector.riotx.core.intent.getMimeTypeFromUri
import im.vector.riotx.core.resources.openResource import im.vector.riotx.core.resources.openResource
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -41,8 +42,8 @@ class KeysImporter(private val session: Session) {
password: String, password: String,
callback: MatrixCallback<ImportRoomKeysResult>) { callback: MatrixCallback<ImportRoomKeysResult>) {
GlobalScope.launch(Dispatchers.Main) { GlobalScope.launch(Dispatchers.Main) {
withContext(Dispatchers.IO) { runCatching {
Try { withContext(Dispatchers.IO) {
val resource = openResource(context, uri, mimetype ?: getMimeTypeFromUri(context, uri)) val resource = openResource(context, uri, mimetype ?: getMimeTypeFromUri(context, uri))
if (resource?.mContentStream == null) { if (resource?.mContentStream == null) {
@ -51,33 +52,17 @@ class KeysImporter(private val session: Session) {
val data: ByteArray val data: ByteArray
try { try {
data = ByteArray(resource.mContentStream!!.available()) data = resource.mContentStream!!.use { it.readBytes() }
resource.mContentStream!!.read(data)
resource.mContentStream!!.close()
data
} catch (e: Exception) { } catch (e: Exception) {
try { Timber.e(e, "## importKeys()")
resource.mContentStream!!.close()
} catch (e2: Exception) {
Timber.e(e2, "## importKeys()")
}
throw e throw e
} }
awaitCallback<ImportRoomKeysResult> {
session.importRoomKeys(data, password, null, it)
}
} }
} }.foldToCallback(callback)
.fold(
{
callback.onFailure(it)
},
{ byteArray ->
session.importRoomKeys(byteArray,
password,
null,
callback)
}
)
} }
} }
} }

View file

@ -31,7 +31,7 @@ import im.vector.riotx.core.epoxy.loadingItem
import im.vector.riotx.core.resources.StringProvider import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.ui.list.GenericItem import im.vector.riotx.core.ui.list.GenericItem
import im.vector.riotx.core.ui.list.genericItem import im.vector.riotx.core.ui.list.genericItem
import java.util.* import java.util.UUID
import javax.inject.Inject import javax.inject.Inject
class KeysBackupSettingsRecyclerViewController @Inject constructor(private val stringProvider: StringProvider, class KeysBackupSettingsRecyclerViewController @Inject constructor(private val stringProvider: StringProvider,

View file

@ -170,8 +170,8 @@ class KeysBackupSetupStep3Fragment : VectorBaseFragment() {
private fun exportRecoveryKeyToFile(data: String) { private fun exportRecoveryKeyToFile(data: String) {
GlobalScope.launch(Dispatchers.Main) { GlobalScope.launch(Dispatchers.Main) {
withContext(Dispatchers.IO) { Try {
Try { withContext(Dispatchers.IO) {
val parentDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) val parentDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val file = File(parentDir, "recovery-key-" + System.currentTimeMillis() + ".txt") val file = File(parentDir, "recovery-key-" + System.currentTimeMillis() + ".txt")

View file

@ -42,7 +42,8 @@ import im.vector.riotx.features.home.room.detail.timeline.format.NoticeEventForm
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
import im.vector.riotx.features.html.EventHtmlRenderer import im.vector.riotx.features.html.EventHtmlRenderer
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.Date
import java.util.Locale
/** /**
* Quick reactions state * Quick reactions state

View file

@ -38,7 +38,7 @@ import im.vector.riotx.features.html.EventHtmlRenderer
import me.gujun.android.span.span import me.gujun.android.span.span
import name.fraser.neil.plaintext.diff_match_patch import name.fraser.neil.plaintext.diff_match_patch
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.Calendar
/** /**
* Epoxy controller for edit history list * Epoxy controller for edit history list
@ -94,7 +94,7 @@ class ViewEditHistoryEpoxyController(private val context: Context,
val body = cContent.second?.let { eventHtmlRenderer.render(it) } val body = cContent.second?.let { eventHtmlRenderer.render(it) }
?: cContent.first ?: cContent.first
val nextEvent = if (index + 1 <= sourceEvents.lastIndex) sourceEvents[index + 1] else null val nextEvent = sourceEvents.getOrNull(index + 1)
var spannedDiff: Spannable? = null var spannedDiff: Spannable? = null
if (nextEvent != null && cContent.second == null /*No diff for html*/) { if (nextEvent != null && cContent.second == null /*No diff for html*/) {

View file

@ -30,7 +30,7 @@ import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.date.VectorDateFormatter import im.vector.riotx.core.date.VectorDateFormatter
import im.vector.riotx.features.home.room.detail.timeline.action.TimelineEventFragmentArgs import im.vector.riotx.features.home.room.detail.timeline.action.TimelineEventFragmentArgs
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.UUID
data class ViewEditHistoryViewState( data class ViewEditHistoryViewState(
val eventId: String, val eventId: String,

View file

@ -33,7 +33,7 @@ import im.vector.riotx.R
import im.vector.riotx.core.resources.StringProvider import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.home.room.detail.timeline.format.NoticeEventFormatter import im.vector.riotx.features.home.room.detail.timeline.format.NoticeEventFormatter
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.UUID
import javax.inject.Inject import javax.inject.Inject
/** /**

View file

@ -27,7 +27,7 @@ import im.vector.riotx.R
import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.extensions.vectorComponent import im.vector.riotx.core.extensions.vectorComponent
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.UUID
import javax.inject.Inject import javax.inject.Inject
/** /**

View file

@ -45,9 +45,9 @@ import im.vector.riotx.features.home.room.detail.RoomDetailActivity
import im.vector.riotx.features.home.room.detail.RoomDetailArgs import im.vector.riotx.features.home.room.detail.RoomDetailArgs
import im.vector.riotx.features.settings.VectorPreferences import im.vector.riotx.features.settings.VectorPreferences
import timber.log.Timber import timber.log.Timber
import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.random.Random
/** /**
* Util class for creating notifications. * Util class for creating notifications.
@ -299,7 +299,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
// use a generator for the private requestCode. // use a generator for the private requestCode.
// When using 0, the intent is not created/launched when the user taps on the notification. // When using 0, the intent is not created/launched when the user taps on the notification.
// //
val pendingIntent = stackBuilder.getPendingIntent(Random().nextInt(1000), PendingIntent.FLAG_UPDATE_CURRENT) val pendingIntent = stackBuilder.getPendingIntent(Random.nextInt(1000), PendingIntent.FLAG_UPDATE_CURRENT)
builder.setContentIntent(pendingIntent) builder.setContentIntent(pendingIntent)
@ -599,7 +599,7 @@ class NotificationUtils @Inject constructor(private val context: Context,
val intent = HomeActivity.newIntent(context, clearNotification = true) val intent = HomeActivity.newIntent(context, clearNotification = true)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.data = Uri.parse("foobar://tapSummary") intent.data = Uri.parse("foobar://tapSummary")
return PendingIntent.getActivity(context, Random().nextInt(1000), intent, PendingIntent.FLAG_UPDATE_CURRENT) return PendingIntent.getActivity(context, Random.nextInt(1000), intent, PendingIntent.FLAG_UPDATE_CURRENT)
} }
/* /*

View file

@ -46,7 +46,7 @@ import org.json.JSONObject
import timber.log.Timber import timber.log.Timber
import java.io.* import java.io.*
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.util.* import java.util.Locale
import java.util.zip.GZIPOutputStream import java.util.zip.GZIPOutputStream
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton

View file

@ -24,7 +24,9 @@ import java.io.File
import java.io.PrintWriter import java.io.PrintWriter
import java.io.StringWriter import java.io.StringWriter
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.Date
import java.util.Locale
import java.util.TimeZone
import java.util.logging.* import java.util.logging.*
import java.util.logging.Formatter import java.util.logging.Formatter
import javax.inject.Inject import javax.inject.Inject

View file

@ -51,7 +51,6 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.util.*
class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() { class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {

View file

@ -56,7 +56,8 @@ import im.vector.riotx.features.crypto.keysbackup.settings.KeysBackupManageActiv
import timber.log.Timber import timber.log.Timber
import java.text.DateFormat import java.text.DateFormat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.Date
import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
class VectorSettingsSecurityPrivacyFragment : VectorSettingsBaseFragment() { class VectorSettingsSecurityPrivacyFragment : VectorSettingsBaseFragment() {

View file

@ -28,7 +28,6 @@ import androidx.core.graphics.drawable.DrawableCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import im.vector.riotx.R import im.vector.riotx.R
import timber.log.Timber import timber.log.Timber
import java.util.*
/** /**
* Util class for managing themes. * Util class for managing themes.
@ -131,24 +130,16 @@ object ThemeUtils {
*/ */
@ColorInt @ColorInt
fun getColor(c: Context, @AttrRes colorAttribute: Int): Int { fun getColor(c: Context, @AttrRes colorAttribute: Int): Int {
if (mColorByAttr.containsKey(colorAttribute)) { return mColorByAttr.getOrPut(colorAttribute) {
return mColorByAttr[colorAttribute] as Int try {
val color = TypedValue()
c.theme.resolveAttribute(colorAttribute, color, true)
color.data
} catch (e: Exception) {
Timber.e(e, "Unable to get color")
ContextCompat.getColor(c, android.R.color.holo_red_dark)
}
} }
var matchedColor: Int
try {
val color = TypedValue()
c.theme.resolveAttribute(colorAttribute, color, true)
matchedColor = color.data
} catch (e: Exception) {
Timber.e(e, "Unable to get color")
matchedColor = ContextCompat.getColor(c, android.R.color.holo_red_dark)
}
mColorByAttr[colorAttribute] = matchedColor
return matchedColor
} }
fun getAttribute(c: Context, @AttrRes attribute: Int): TypedValue? { fun getAttribute(c: Context, @AttrRes attribute: Int): TypedValue? {

View file

@ -1,33 +0,0 @@
/*
* Copyright 2019 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 im.vector.riotx
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}