Skip to content

Commit 7111460

Browse files
committed
Apollo: Release source code for 52.1
1 parent 7bbe9b2 commit 7111460

File tree

67 files changed

+1117
-873
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1117
-873
lines changed

android/CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,27 @@ follow [https://changelog.md/](https://changelog.md/) guidelines.
66

77
## [Unreleased]
88

9+
## [52.1] - 2024-08-02
10+
11+
### ADDED
12+
13+
- Background notification processing reliability improvements
14+
- Wallet delete checks client-side (e.g prevent it wallet not fully empty)
15+
16+
### FIXED
17+
18+
- Handling of missing or deprecated currencies
19+
- Tiny text copy when updating emergency kit
20+
21+
### CHANGED
22+
23+
- Upgraded compiledSdkVersion and targetSdkVersion to 34
24+
- Upgraded go version to 1.21.11
25+
- Enhanced password input for change password flow (consistency with rest of the app)
26+
- Enhanced error metadata for strange secure storage errors
27+
- Removed never used "max fee" button and calculations
28+
- Revamped to UI test suite. Enhancing reliability and coverage.
29+
930
## [52] - 2024-06-14
1031

1132
### ADDED

android/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ FROM --platform=linux/amd64 openjdk:17-jdk-buster@sha256:9217da81dcff19e60861791
33
ENV NDK_VERSION 22.0.7026061
44
ENV ANDROID_PLATFORM_VERSION 28
55
ENV ANDROID_BUILD_TOOLS_VERSION 28.0.3
6-
ENV GO_VERSION 1.18.1
6+
ENV GO_VERSION 1.21.11
77

88
RUN apt-get update \
99
&& apt-get install --yes --no-install-recommends \

android/apollo/build.gradle

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,17 @@ apply from: "${project.rootDir}/linters/pmd/check-android.gradle"
2121
//apply from: "${project.rootDir}/linters/findbugs/check-android.gradle"
2222

2323
android {
24-
compileSdkVersion 31
24+
compileSdk 34
2525

2626
defaultConfig {
27-
minSdkVersion 19
28-
targetSdkVersion 31
29-
versionCode 1
30-
versionName "1.0"
27+
minSdk 19
28+
targetSdk 34
3129

3230
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
3331
}
3432

3533
buildTypes {
3634
minified {
37-
debuggable true
3835
minifyEnabled true
3936
}
4037
}
@@ -48,12 +45,12 @@ android {
4845
jvmTarget = JavaVersion.VERSION_1_8.toString()
4946
}
5047

51-
lintOptions {
48+
lint {
5249
abortOnError true
5350
htmlReport true
5451
textReport true
55-
lintConfig file("${project.rootDir}/linters/android-lint/config.xml")
56-
baseline file("lint-baseline.xml")
52+
lintConfig file("$rootDir/linters/android-lint/config.xml")
53+
baseline file('lint-baseline.xml')
5754
}
5855

5956
testOptions {

android/apollo/src/main/java/io/muun/apollo/data/analytics/AnalyticsProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class AnalyticsProvider @Inject constructor(context: Context) {
5555

5656
// Avoid recursion (Timber.i reports a breadcrumb). TODO proper design and fix this
5757
if (event !is AnalyticsEvent.E_BREADCRUMB) {
58-
Timber.i("AnalyticsProvider", event.toString())
58+
Timber.i("AnalyticsProvider: $event")
5959
}
6060

6161
} catch (t: Throwable) {

android/apollo/src/main/java/io/muun/apollo/data/external/Gen.kt

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -292,23 +292,6 @@ object Gen {
292292
private fun muunAddress() =
293293
MuunAddress(1, "m/1/2/3", address())
294294

295-
/**
296-
* Get a PaymentRequest
297-
*/
298-
fun payReq(
299-
amount: MonetaryAmount = Money.of(0, "USD"),
300-
feeRate: Double = 10.0,
301-
takeFeeFromAmount: Boolean = false,
302-
303-
) = PaymentRequest(
304-
type = PaymentRequest.Type.TO_ADDRESS,
305-
amount = amount,
306-
description = "foo",
307-
address = address(),
308-
feeInSatoshisPerByte = feeRate,
309-
takeFeeFromAmount = takeFeeFromAmount
310-
)
311-
312295
fun submarineSwap(
313296
outputAmountInSatoshis: Long,
314297
sweepFeeInSatoshis: Long = 0,

android/apollo/src/main/java/io/muun/apollo/data/os/BackgroundExecutionMetricsProvider.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import io.muun.apollo.data.net.ConnectivityInfoProvider
1111
import io.muun.apollo.data.net.NetworkInfoProvider
1212
import kotlinx.serialization.Serializable
1313
import java.util.Locale
14-
import java.util.TimeZone
1514
import javax.inject.Inject
1615

1716
private const val UNSUPPORTED = -1
@@ -27,6 +26,7 @@ class BackgroundExecutionMetricsProvider @Inject constructor(
2726
private val activityManagerInfoProvider: ActivityManagerInfoProvider,
2827
private val resourcesInfoProvider: ResourcesInfoProvider,
2928
private val systemCapabilitiesProvider: SystemCapabilitiesProvider,
29+
private val dateTimeZoneProvider: DateTimeZoneProvider,
3030
) {
3131

3232
private val powerManager: PowerManager by lazy {
@@ -54,7 +54,7 @@ class BackgroundExecutionMetricsProvider @Inject constructor(
5454
SystemClock.elapsedRealtime(),
5555
hardwareCapabilitiesProvider.bootCount,
5656
Locale.getDefault().toString(),
57-
TimeZone.getDefault().rawOffset / 1000L,
57+
dateTimeZoneProvider.timeZoneOffsetSeconds,
5858
telephonyInfoProvider.region.orElse(""),
5959
telephonyInfoProvider.simRegion,
6060
appInfoProvider.appDatadir,
@@ -68,7 +68,10 @@ class BackgroundExecutionMetricsProvider @Inject constructor(
6868
systemCapabilitiesProvider.developerEnabled,
6969
connectivityInfoProvider.proxyHttp,
7070
connectivityInfoProvider.proxyHttps,
71-
connectivityInfoProvider.proxySocks
71+
connectivityInfoProvider.proxySocks,
72+
dateTimeZoneProvider.autoDateTime,
73+
dateTimeZoneProvider.autoTimeZone,
74+
dateTimeZoneProvider.timeZoneId
7275
)
7376

7477
@Suppress("ArrayInDataClass")
@@ -108,6 +111,9 @@ class BackgroundExecutionMetricsProvider @Inject constructor(
108111
private val proxyHttp: String,
109112
private val proxyHttps: String,
110113
private val proxySocks: String,
114+
private val autoDateTime: Int,
115+
private val autoTimeZone: Int,
116+
private val timeZoneId: String,
111117
)
112118

113119
/**
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package io.muun.apollo.data.os
2+
3+
import android.content.Context
4+
import android.provider.Settings
5+
import java.util.TimeZone
6+
import javax.inject.Inject
7+
8+
class DateTimeZoneProvider @Inject constructor(private val context: Context) {
9+
10+
val autoTimeZone: Int
11+
get() {
12+
return Settings.Global.getInt(
13+
context.contentResolver,
14+
Settings.Global.AUTO_TIME_ZONE,
15+
-1
16+
)
17+
}
18+
19+
val autoDateTime: Int
20+
get() {
21+
return Settings.Global.getInt(
22+
context.contentResolver,
23+
Settings.Global.AUTO_TIME,
24+
-1
25+
)
26+
}
27+
28+
val timeZoneId: String
29+
get() {
30+
return TimeZone.getDefault().id.take(100)
31+
}
32+
33+
val timeZoneOffsetSeconds: Long
34+
get() {
35+
return TimeZone.getDefault().rawOffset / 1000L
36+
}
37+
}

android/apollo/src/main/java/io/muun/apollo/data/os/secure_storage/SecureStoragePreferences.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public byte[] getAesIv(String key) {
7777
*/
7878
public synchronized byte[] getPersistentSecureRandomBytes(String key, int size) {
7979
if (sharedPreferences.contains(key)) {
80+
Timber.i("getPersistentSecureRandomBytes for " + key + ". Cached.");
8081
final byte[] iv = getBytes(key);
8182

8283
// We've had a few InvalidKeyExceptions that might come from invalid IVs
@@ -90,6 +91,7 @@ public synchronized byte[] getPersistentSecureRandomBytes(String key, int size)
9091
return iv;
9192

9293
} else {
94+
Timber.i("getPersistentSecureRandomBytes for " + key + ". Generate new");
9395
final byte[] bytes = RandomGenerator.getBytes(size);
9496
saveBytes(bytes, key);
9597
return bytes;
@@ -102,7 +104,14 @@ public synchronized byte[] getPersistentSecureRandomBytes(String key, int size)
102104
public void saveBytes(byte[] bytes, String key) {
103105
initSecureStorage();
104106

105-
sharedPreferences.edit().putString(key, SerializationUtils.serializeBytes(bytes)).commit();
107+
final boolean writeSuccess = sharedPreferences.edit()
108+
.putString(key, SerializationUtils.serializeBytes(bytes))
109+
.commit();
110+
111+
Timber.i("SaveBytes for " + key + " success:" + writeSuccess );
112+
if (!writeSuccess) {
113+
Timber.e("Error while committing write to secure storage preferences");
114+
}
106115
}
107116

108117
/**

android/apollo/src/main/java/io/muun/apollo/data/os/secure_storage/SecureStorageProvider.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ public boolean has(String key) {
123123
// our error report infra offers more metadata/insights on this issue
124124
if (hasKeyInPreferences != hasKeyInKeystore) {
125125
final SecureStorageError error = new SecureStorageError(debugSnapshot());
126+
error.addMetadata("key", key);
127+
error.addMetadata("hasKeyInPreferences", hasKeyInPreferences);
128+
error.addMetadata("hasKeyInKeystore", hasKeyInKeystore);
126129
Timber.e(error);
127130
throw error;
128131
}
@@ -196,6 +199,7 @@ private void storeEncrypted(String key, byte[] input) {
196199
preferences.saveBytes(keyStore.encryptData(input, key, preferences.getAesIv(key)), key);
197200
} catch (Throwable e) {
198201
Timber.i("SecureStorageError on WRITE for key: " + key);
202+
Timber.e(e);
199203
final SecureStorageError ssError = new SecureStorageError(e, debugSnapshot());
200204
enhanceError(ssError, key);
201205
throw ssError;

android/apollo/src/main/java/io/muun/apollo/data/preferences/UserRepository.java

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import io.muun.apollo.domain.model.user.UserPhoneNumber;
1313
import io.muun.apollo.domain.model.user.UserProfile;
1414
import io.muun.common.Optional;
15+
import io.muun.common.model.Currency;
1516
import io.muun.common.model.PhoneNumber;
1617
import io.muun.common.utils.Preconditions;
1718

@@ -32,6 +33,7 @@
3233
import javax.annotation.Nullable;
3334
import javax.inject.Inject;
3435
import javax.inject.Singleton;
36+
import javax.money.CurrencyUnit;
3537

3638
@Singleton
3739
public class UserRepository extends BaseRepository {
@@ -487,26 +489,37 @@ public static class StoredUserJson {
487489
// and migrate the preference to a non-minified JSON this class is APPEND-ONLY.
488490

489491
public long hid;
492+
490493
public String email;
494+
491495
public String createdAt;
492496

493497
public String phoneNumber;
498+
494499
public boolean isPhoneNumberVerified;
495500

496501
public String firstName;
502+
497503
public String lastName;
504+
498505
public String profilePictureUrl;
499506

500507
public boolean isEmailVerified;
508+
501509
public boolean hasRecoveryCode;
510+
502511
public boolean hasPassword;
512+
503513
public boolean hasP2PEnabled;
514+
504515
public boolean hasExportedKeys;
505516

506517
public String currency;
507518

508519
public String emergencyKitLastExportedAt;
520+
509521
public Integer emergencyKitVersion;
522+
510523
public String emergencyKitExportMethod;
511524

512525
@NonNull // Not backed by Houston, cached locally
@@ -551,25 +564,27 @@ public StoredUserJson() {
551564
/**
552565
* Manual constructor.
553566
*/
554-
public StoredUserJson(long hid,
555-
String email,
556-
String createdAt,
557-
String phoneNumber,
558-
boolean isPhoneNumberVerified,
559-
String firstName,
560-
String lastName,
561-
String profilePictureUrl,
562-
boolean isEmailVerified,
563-
boolean hasRecoveryCode,
564-
boolean hasPassword,
565-
boolean hasP2PEnabled,
566-
boolean hasExportedKeys,
567-
String currency,
568-
String emergencyKitLastExportedAt,
569-
Integer emergencyKitVersion,
570-
EmergencyKitExport.Method emergencyKitExportMethod,
571-
@NonNull StoredEkVerificationCodes ekVerificationCodes,
572-
@NonNull List<Integer> ekVersions) {
567+
public StoredUserJson(
568+
long hid,
569+
String email,
570+
String createdAt,
571+
String phoneNumber,
572+
boolean isPhoneNumberVerified,
573+
String firstName,
574+
String lastName,
575+
String profilePictureUrl,
576+
boolean isEmailVerified,
577+
boolean hasRecoveryCode,
578+
boolean hasPassword,
579+
boolean hasP2PEnabled,
580+
boolean hasExportedKeys,
581+
String currency,
582+
String emergencyKitLastExportedAt,
583+
Integer emergencyKitVersion,
584+
EmergencyKitExport.Method emergencyKitExportMethod,
585+
@NonNull StoredEkVerificationCodes ekVerificationCodes,
586+
@NonNull List<Integer> ekVersions
587+
) {
573588

574589
this.hid = hid;
575590
this.email = email;
@@ -608,7 +623,7 @@ User toUser() {
608623
? Optional.of(new UserProfile(firstName, lastName, profilePictureUrl))
609624
: Optional.empty(),
610625

611-
SerializationUtils.deserializeCurrencyUnit(currency != null ? currency : "USD"),
626+
loadCurrencyFromStorage(),
612627

613628
hasRecoveryCode,
614629
hasPassword,
@@ -626,6 +641,18 @@ User toUser() {
626641
);
627642
}
628643

644+
private CurrencyUnit loadCurrencyFromStorage() {
645+
try {
646+
final String currencyCode = currency != null ? currency : "USD";
647+
return SerializationUtils.deserializeCurrencyUnit(currencyCode);
648+
649+
} catch (Exception e) {
650+
// This can happen for example if user primary currency is no longer supported
651+
// after an app or OS update.
652+
return Currency.getUnit(Currency.DEFAULT.getCode()).get();
653+
}
654+
}
655+
629656
void initEmergencyKitVersion() {
630657
if (emergencyKitLastExportedAt != null) {
631658
emergencyKitVersion = (int) Libwallet.EKVersionDescriptors;
@@ -683,9 +710,11 @@ public StoredUserJson get(@NonNull String key, @NonNull SharedPreferences prefer
683710
}
684711

685712
@Override
686-
public void set(@NonNull String key,
687-
@NonNull StoredUserJson value,
688-
@NonNull SharedPreferences.Editor editor) {
713+
public void set(
714+
@NonNull String key,
715+
@NonNull StoredUserJson value,
716+
@NonNull SharedPreferences.Editor editor
717+
) {
689718
super.set(key, value, editor);
690719
}
691720
}

0 commit comments

Comments
 (0)