diff --git a/vector/src/main/java/im/vector/app/AppBuildConfig.kt b/vector/src/main/java/im/vector/app/AppBuildConfig.kt new file mode 100644 index 0000000000..54eb4f87ea --- /dev/null +++ b/vector/src/main/java/im/vector/app/AppBuildConfig.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 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.app + +import android.os.Build + +object AppBuildConfig { + + fun getModel(): String { + return Build.MODEL + } +} diff --git a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt index ac932bee72..67e7868df7 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt @@ -16,6 +16,7 @@ package im.vector.app.core.pushers +import im.vector.app.AppBuildConfig import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.resources.AppNameProvider @@ -26,7 +27,7 @@ import java.util.UUID import javax.inject.Inject import kotlin.math.abs -private const val DEFAULT_PUSHER_FILE_TAG = "mobile" +internal const val DEFAULT_PUSHER_FILE_TAG = "mobile" class PushersManager @Inject constructor( private val unifiedPushHelper: UnifiedPushHelper, @@ -64,11 +65,11 @@ class PushersManager @Inject constructor( gateway: String ) = HttpPusher( pushKey, - stringProvider.getString(R.string.pusher_app_id), + appId = stringProvider.getString(R.string.pusher_app_id), profileTag = DEFAULT_PUSHER_FILE_TAG + "_" + abs(activeSessionHolder.getActiveSession().myUserId.hashCode()), lang = localeProvider.current().language, appDisplayName = appNameProvider.getAppName(), - deviceDisplayName = android.os.Build.MODEL, + deviceDisplayName = AppBuildConfig.getModel(), url = gateway, enabled = true, deviceId = activeSessionHolder.getActiveSession().sessionParams.deviceId ?: "MOBILE", diff --git a/vector/src/main/java/im/vector/app/core/resources/AppNameProvider.kt b/vector/src/main/java/im/vector/app/core/resources/AppNameProvider.kt index 3b6a8b595c..a25862f3a8 100644 --- a/vector/src/main/java/im/vector/app/core/resources/AppNameProvider.kt +++ b/vector/src/main/java/im/vector/app/core/resources/AppNameProvider.kt @@ -21,9 +21,14 @@ import im.vector.app.core.utils.getApplicationLabel import timber.log.Timber import javax.inject.Inject -class AppNameProvider @Inject constructor(private val context: Context) { +interface AppNameProvider { - fun getAppName(): String { + fun getAppName(): String +} + +class DefaultAppNameProvider @Inject constructor(private val context: Context) : AppNameProvider { + + override fun getAppName(): String { return try { val appPackageName = context.applicationContext.packageName var appName = context.getApplicationLabel(appPackageName) diff --git a/vector/src/main/java/im/vector/app/core/resources/LocaleProvider.kt b/vector/src/main/java/im/vector/app/core/resources/LocaleProvider.kt index d91a09e6df..3bdbc64eb4 100644 --- a/vector/src/main/java/im/vector/app/core/resources/LocaleProvider.kt +++ b/vector/src/main/java/im/vector/app/core/resources/LocaleProvider.kt @@ -23,9 +23,14 @@ import androidx.core.os.ConfigurationCompat import java.util.Locale import javax.inject.Inject -class LocaleProvider @Inject constructor(private val resources: Resources) { +interface LocaleProvider { - fun current(): Locale { + fun current(): Locale +} + +class DefaultLocaleProvider @Inject constructor(private val resources: Resources) : LocaleProvider { + + override fun current(): Locale { return ConfigurationCompat.getLocales(resources.configuration).get(0) ?: Locale.getDefault() } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/view/MessageBubbleContentLayout.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/view/MessageBubbleContentLayout.kt index f11b1c6951..6d8fd87a52 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/view/MessageBubbleContentLayout.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/view/MessageBubbleContentLayout.kt @@ -27,7 +27,7 @@ import androidx.core.view.marginEnd import androidx.core.view.marginStart import androidx.core.view.marginTop import im.vector.app.R -import im.vector.app.core.resources.LocaleProvider +import im.vector.app.core.resources.DefaultLocaleProvider import im.vector.app.core.resources.getLayoutDirectionFromCurrentLocale class MessageBubbleContentLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : @@ -53,7 +53,7 @@ class MessageBubbleContentLayout @JvmOverloads constructor(context: Context, att textViewStub.setOnInflateListener(null) messageTextView = inflated.findViewById(R.id.messageTextView) } - localeLayoutDirection = LocaleProvider(resources).getLayoutDirectionFromCurrentLocale() + localeLayoutDirection = DefaultLocaleProvider(resources).getLayoutDirectionFromCurrentLocale() } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/view/MessageBubbleView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/view/MessageBubbleView.kt index c9665a9125..6ac787b719 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/view/MessageBubbleView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/view/MessageBubbleView.kt @@ -33,7 +33,7 @@ import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import com.google.android.material.shape.MaterialShapeDrawable import im.vector.app.R -import im.vector.app.core.resources.LocaleProvider +import im.vector.app.core.resources.DefaultLocaleProvider import im.vector.app.core.resources.getLayoutDirectionFromCurrentLocale import im.vector.app.core.utils.DimensionConverter import im.vector.app.databinding.ViewMessageBubbleBinding @@ -67,7 +67,7 @@ class MessageBubbleView @JvmOverloads constructor( override fun onFinishInflate() { super.onFinishInflate() views = ViewMessageBubbleBinding.bind(this) - val currentLayoutDirection = LocaleProvider(resources).getLayoutDirectionFromCurrentLocale() + val currentLayoutDirection = DefaultLocaleProvider(resources).getLayoutDirectionFromCurrentLocale() val layoutDirectionToSet = if (isIncoming) { currentLayoutDirection } else { diff --git a/vector/src/test/java/im/vector/app/core/pushers/PushersManagerTest.kt b/vector/src/test/java/im/vector/app/core/pushers/PushersManagerTest.kt new file mode 100644 index 0000000000..e42f995ef6 --- /dev/null +++ b/vector/src/test/java/im/vector/app/core/pushers/PushersManagerTest.kt @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2022 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.app.core.pushers + +import im.vector.app.AppBuildConfig +import im.vector.app.R +import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakeAppNameProvider +import im.vector.app.test.fakes.FakeLocaleProvider +import im.vector.app.test.fakes.FakePushersService +import im.vector.app.test.fakes.FakeSession +import im.vector.app.test.fakes.FakeStringProvider +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkObject +import org.amshove.kluent.shouldBeEqualTo +import org.junit.Before +import org.junit.Test +import java.util.Locale +import kotlin.math.abs + +class PushersManagerTest { + + private val pushersService = FakePushersService() + private val session = FakeSession(fakePushersService = pushersService) + private val activeSessionHolder = FakeActiveSessionHolder(session) + private val stringProvider = FakeStringProvider() + private val localeProvider = FakeLocaleProvider() + private val appNameProvider = FakeAppNameProvider() + + private val pushersManager = PushersManager( + mockk(), + activeSessionHolder.instance, + localeProvider, + stringProvider.instance, + appNameProvider, + ) + + @Before + fun setUp() { + mockkObject(AppBuildConfig) + } + + @Test + fun `when enqueueRegisterPusher, then HttpPusher created and enqueued`() { + val pushKey = "abc" + val gateway = "123" + val pusherAppId = "app-id" + val appName = "element" + val deviceDisplayName = "iPhone Lollipop" + stringProvider.given(R.string.pusher_app_id, pusherAppId) + localeProvider.givenCurrent(Locale.UK) + appNameProvider.givenAppName(appName) + every { AppBuildConfig.getModel() } returns deviceDisplayName + + pushersManager.enqueueRegisterPusher(pushKey, gateway) + + val httpPusher = pushersService.verifyEnqueueAddHttpPusher() + httpPusher.pushkey shouldBeEqualTo pushKey + httpPusher.appId shouldBeEqualTo pusherAppId + httpPusher.profileTag shouldBeEqualTo DEFAULT_PUSHER_FILE_TAG + "_" + abs(session.myUserId.hashCode()) + httpPusher.lang shouldBeEqualTo Locale.UK.language + httpPusher.appDisplayName shouldBeEqualTo appName + httpPusher.deviceDisplayName shouldBeEqualTo deviceDisplayName + httpPusher.enabled shouldBeEqualTo true + httpPusher.deviceId shouldBeEqualTo session.sessionParams.deviceId + httpPusher.append shouldBeEqualTo false + httpPusher.withEventIdOnly shouldBeEqualTo true + httpPusher.url shouldBeEqualTo gateway + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeAppNameProvider.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeAppNameProvider.kt new file mode 100644 index 0000000000..2e60a78853 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeAppNameProvider.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 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.app.test.fakes + +import im.vector.app.core.resources.AppNameProvider +import io.mockk.every +import io.mockk.mockk + +class FakeAppNameProvider : AppNameProvider by mockk() { + + fun givenAppName(appName: String) { + every { getAppName() } returns appName + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeLocaleProvider.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeLocaleProvider.kt new file mode 100644 index 0000000000..4d4e2b5bcb --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeLocaleProvider.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022 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.app.test.fakes + +import im.vector.app.core.resources.LocaleProvider +import io.mockk.every +import io.mockk.mockk +import java.util.Locale + +class FakeLocaleProvider : LocaleProvider by mockk() { + + fun givenCurrent(locale: Locale) { + every { current() } returns locale + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakePushersService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakePushersService.kt new file mode 100644 index 0000000000..9e11b86871 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakePushersService.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022 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.app.test.fakes + +import io.mockk.mockk +import io.mockk.slot +import io.mockk.verify +import org.matrix.android.sdk.api.session.pushers.HttpPusher +import org.matrix.android.sdk.api.session.pushers.PushersService + +class FakePushersService : PushersService by mockk(relaxed = true) { + + fun verifyEnqueueAddHttpPusher(): HttpPusher { + val httpPusherSlot = slot() + verify { enqueueAddHttpPusher(capture(httpPusherSlot)) } + return httpPusherSlot.captured + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt index 35d23e35e8..3a253c96ea 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt @@ -41,6 +41,7 @@ class FakeSession( val fakeHomeServerCapabilitiesService: FakeHomeServerCapabilitiesService = FakeHomeServerCapabilitiesService(), val fakeSharedSecretStorageService: FakeSharedSecretStorageService = FakeSharedSecretStorageService(), val fakeRoomService: FakeRoomService = FakeRoomService(), + val fakePushersService: FakePushersService = FakePushersService(), private val fakeEventService: FakeEventService = FakeEventService(), ) : Session by mockk(relaxed = true) { @@ -58,6 +59,7 @@ class FakeSession( override fun sharedSecretStorageService() = fakeSharedSecretStorageService override fun roomService() = fakeRoomService override fun eventService() = fakeEventService + override fun pushersService() = fakePushersService fun givenVectorStore(vectorSessionStore: VectorSessionStore) { coEvery {