diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md index 7f384e08..d613f88e 100644 --- a/android/CHANGELOG.md +++ b/android/CHANGELOG.md @@ -6,6 +6,13 @@ follow [https://changelog.md/](https://changelog.md/) guidelines. ## [Unreleased] +## [51.6] - 2024-01-24 + +### FIXED + +- A crash when trying to change password using Recovery Code +- A probable source of crashes regarding handling of MuunHeader + ## [51.6] - 2024-01-17 ### FIXED diff --git a/android/apollo/src/main/java/io/muun/apollo/domain/BackgroundTimesService.kt b/android/apollo/src/main/java/io/muun/apollo/domain/BackgroundTimesService.kt index c5bae59b..4d5388ee 100644 --- a/android/apollo/src/main/java/io/muun/apollo/domain/BackgroundTimesService.kt +++ b/android/apollo/src/main/java/io/muun/apollo/domain/BackgroundTimesService.kt @@ -1,5 +1,6 @@ package io.muun.apollo.domain +import androidx.annotation.VisibleForTesting import io.muun.apollo.data.preferences.BackgroundTimesRepository import javax.inject.Inject @@ -7,7 +8,10 @@ class BackgroundTimesService @Inject constructor( private val backgroundTimesRepository: BackgroundTimesRepository, ) { - private val MAX_BKG_TIMES_ARRAY_SIZE: Int = 100 + companion object { + @VisibleForTesting + val MAX_BKG_TIMES_ARRAY_SIZE: Int = 100 + } fun enterBackground() { backgroundTimesRepository.recordEnterBackground() diff --git a/android/apolloui/build.gradle b/android/apolloui/build.gradle index 5f216e76..c266134c 100644 --- a/android/apolloui/build.gradle +++ b/android/apolloui/build.gradle @@ -91,8 +91,8 @@ android { applicationId "io.muun.apollo" minSdkVersion 19 targetSdkVersion 33 - versionCode 1106 - versionName "51.6" + versionCode 1107 + versionName "51.7" // Needed to make sure these classes are available in the main DEX file for API 19 // See: https://spin.atomicobject.com/2018/07/16/support-kitkat-multidex/ diff --git a/android/apolloui/src/androidTest/java/io/muun/apollo/domain/BackgroundTimesServiceTest.kt b/android/apolloui/src/androidTest/java/io/muun/apollo/domain/BackgroundTimesServiceTest.kt new file mode 100644 index 00000000..e4774017 --- /dev/null +++ b/android/apolloui/src/androidTest/java/io/muun/apollo/domain/BackgroundTimesServiceTest.kt @@ -0,0 +1,82 @@ +package io.muun.apollo.domain + +import android.content.Context +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.runner.AndroidJUnit4 +import io.muun.apollo.data.preferences.BackgroundTimesRepository +import io.muun.apollo.data.preferences.RepositoryRegistry +import org.assertj.core.api.Assertions.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * @see [Testing documentation](http://d.android.com/tools/testing) + */ +@RunWith(AndroidJUnit4::class) +class BackgroundTimesServiceTest { + + private lateinit var context: Context + private lateinit var backgroundTimesService: BackgroundTimesService + private lateinit var backgroundTimesRepository: BackgroundTimesRepository + + @Before + fun setUp() { + context = InstrumentationRegistry.getInstrumentation().targetContext + backgroundTimesRepository = BackgroundTimesRepository(context, RepositoryRegistry()) + backgroundTimesService = BackgroundTimesService( + backgroundTimesRepository + ) + + backgroundTimesRepository.clear() + } + + @After + fun cleanUp() { + backgroundTimesRepository.clear() + } + + @Test + fun saveSingleBackgroundEventWorks() { + backgroundTimesService.enterBackground() + backgroundTimesService.enterForeground() + + val bkgTimes = backgroundTimesRepository.getBackgroundTimes() + assertThat(bkgTimes).isNotEmpty + assertThat(bkgTimes.size).isEqualTo(1) + } + + @Test + fun recordForegroundBeforeGoingToBackgroundDoesntStoreAnything() { + // E.g on first open we record enterForeground but since we didn't record enterBackground + // we can't calculation bkgEvent duration so we ignore it. + + backgroundTimesService.enterForeground() + + val bkgTimes = backgroundTimesRepository.getBackgroundTimes() + assertThat(bkgTimes).isEmpty() + assertThat(bkgTimes.size).isEqualTo(0) + + saveSingleBackgroundEventWorks() + } + + @Test + fun pruneEventListUponReachingCapLimit() { + + val capLimit = BackgroundTimesService.MAX_BKG_TIMES_ARRAY_SIZE + + for (i in 1..capLimit + 20) { + backgroundTimesService.enterBackground() + backgroundTimesService.enterForeground() + } + + val bkgTimes = backgroundTimesRepository.getBackgroundTimes() + assertThat(bkgTimes).isNotEmpty + // Due to an impl detail we're actually always keeping capLimit + 1 items (hehe) + assertThat(bkgTimes.size).isEqualTo(capLimit + 1) + } + +} \ No newline at end of file diff --git a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/base/SingleFragmentActivity.java b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/base/SingleFragmentActivity.java index f7c0268c..ef1ba458 100644 --- a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/base/SingleFragmentActivity.java +++ b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/base/SingleFragmentActivity.java @@ -87,7 +87,10 @@ private boolean hasFragments() { * - Fragment#onAttach (so fragment is attached to activity, getActivity returns non null). */ final void attachHeader() { - getHeader().attachToActivity(this); + final MuunHeader header = getHeader(); + if (header != null) { // MuunHeader's optional for SingleFragment (see SingleActionFragment) + header.attachToActivity(this); + } } @Override diff --git a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/settings/RecoveryCodeFragment.kt b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/settings/RecoveryCodeFragment.kt index b8215424..e746dca0 100644 --- a/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/settings/RecoveryCodeFragment.kt +++ b/android/apolloui/src/main/java/io/muun/apollo/presentation/ui/settings/RecoveryCodeFragment.kt @@ -61,7 +61,7 @@ class RecoveryCodeFragment : SingleFragment(), RecoveryCo presenter.submitRecoveryCode(recoveryCodeBox.segmentInputsContent) } - override fun setRecoveryCodeError(error: UserFacingError) { + override fun setRecoveryCodeError(error: UserFacingError?) { recoveryCodeBox.setError(error) }