Skip to content

Commit

Permalink
Merge pull request #147 from muun/51.9-release-branch
Browse files Browse the repository at this point in the history
Apollo: Release source code for 51.9
  • Loading branch information
acrespo authored May 3, 2024
2 parents 7e01630 + f451971 commit ac4d635
Show file tree
Hide file tree
Showing 13 changed files with 297 additions and 14 deletions.
6 changes: 5 additions & 1 deletion android/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ follow [https://changelog.md/](https://changelog.md/) guidelines.

## [Unreleased]

## [51.9] - 2024-04-30

- Background notification processing reliability improvements

## [51.8] - 2024-02-23

### CHANGED
Expand All @@ -16,7 +20,7 @@ forward a fake sphinx without a payment secret and for 1 sat, the app will accep
secret is optional and the last hop keeps the rest of the payment. Payment secret has been widely
adopted for quite a bit now. Major impls all require it.

## [51.6] - 2024-01-24
## [51.7] - 2024-01-24

### FIXED

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package io.muun.apollo.data.net

import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import androidx.annotation.RequiresApi
import io.muun.apollo.data.os.Constants
import io.muun.apollo.data.os.OS
import javax.inject.Inject

// TODO we should merge this and NetworkInfoProvider together
class ConnectivityInfoProvider @Inject constructor(context: Context) {

private val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

val vpnState: Int
get() {
if (OS.supportsActiveNetwork()) {
return getVpnStateForNewerApi()

} else {

if (OS.supportsNetworkCapabilities()) {
return getVpnStateForOldApi()

} else {
return Constants.INT_UNKNOWN
}
}
}

@RequiresApi(Build.VERSION_CODES.M)
private fun getVpnStateForNewerApi(): Int {
val activeNetwork = connectivityManager.activeNetwork
if (activeNetwork != null) {
val caps = connectivityManager.getNetworkCapabilities(activeNetwork)
if (caps != null) {
return if (caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) 1 else 0
}
}

// if no activeNetwork or no networkCapabilities then return unknown
return Constants.INT_UNKNOWN
}

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun getVpnStateForOldApi(): Int {
val allNetworks = connectivityManager.allNetworks
val isVpnNetworkAvailable = allNetworks.any { network ->
val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
networkCapabilities != null && networkCapabilities.hasTransport(
NetworkCapabilities.TRANSPORT_VPN
)
}

return if (isVpnNetworkAvailable) 2 else 3
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.muun.apollo.data.os

import android.app.ActivityManager
import javax.inject.Inject


class ActivityManagerInfoProvider @Inject constructor() {

val appImportance: Int
get() {
val appProcessInfo = ActivityManager.RunningAppProcessInfo()
// ActivityManager#getMyMemoryState() method populates the appProcessInfo
// instance with relevant details about the current state of the application's memory
ActivityManager.getMyMemoryState(appProcessInfo)
return appProcessInfo.importance
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.muun.apollo.data.os

import android.content.Context
import javax.inject.Inject

class AppInfoProvider @Inject constructor(private val context: Context) {
val appDatadir: String
get() {
return context.applicationInfo.dataDir
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.PowerManager
import android.os.SystemClock
import io.muun.apollo.data.net.ConnectivityInfoProvider
import io.muun.apollo.data.net.NetworkInfoProvider
import kotlinx.serialization.Serializable
import java.util.Locale
import java.util.TimeZone
import javax.inject.Inject

private const val UNSUPPORTED = -1
Expand All @@ -18,6 +22,11 @@ class BackgroundExecutionMetricsProvider @Inject constructor(
private val hardwareCapabilitiesProvider: HardwareCapabilitiesProvider,
private val telephonyInfoProvider: TelephonyInfoProvider,
private val networkInfoProvider: NetworkInfoProvider,
private val appInfoProvider: AppInfoProvider,
private val connectivityInfoProvider: ConnectivityInfoProvider,
private val activityManagerInfoProvider: ActivityManagerInfoProvider,
private val resourcesInfoProvider: ResourcesInfoProvider,
private val systemCapabilitiesProvider: SystemCapabilitiesProvider,
) {

private val powerManager: PowerManager by lazy {
Expand All @@ -41,6 +50,22 @@ class BackgroundExecutionMetricsProvider @Inject constructor(
telephonyInfoProvider.dataState,
telephonyInfoProvider.getSimStates().toTypedArray(),
networkInfoProvider.currentTransport,
SystemClock.uptimeMillis(),
SystemClock.elapsedRealtime(),
hardwareCapabilitiesProvider.bootCount,
Locale.getDefault().toString(),
TimeZone.getDefault().rawOffset / 1000L,
telephonyInfoProvider.region.orElse(""),
telephonyInfoProvider.simRegion,
appInfoProvider.appDatadir,
connectivityInfoProvider.vpnState,
activityManagerInfoProvider.appImportance,
resourcesInfoProvider.displayMetrics,
systemCapabilitiesProvider.usbConnected,
systemCapabilitiesProvider.usbPersistConfig,
systemCapabilitiesProvider.bridgeEnabled,
systemCapabilitiesProvider.bridgeDaemonStatus,
systemCapabilitiesProvider.developerEnabled
)

@Suppress("ArrayInDataClass")
Expand All @@ -61,6 +86,22 @@ class BackgroundExecutionMetricsProvider @Inject constructor(
private val dataState: String,
private val simStates: Array<String>,
private val networkTransport: String,
private val androidUptimeMillis: Long,
private val androidElapsedRealtimeMillis: Long,
private val androidBootCount: Int,
private val language: String,
private val timeZoneOffsetInSeconds: Long,
private val telephonyNetworkRegion: String,
private val simRegion: String,
private val appDataDir: String,
private val vpnState: Int,
private val appImportance: Int,
private val displayMetrics: ResourcesInfoProvider.DisplayMetricsInfo,
private val usbConnected: Int,
private val usbPersistConfig: String,
private val bridgeEnabled: Int,
private val bridgeDaemonStatus: String,
private val developerEnabled: Int,
)

/**
Expand Down Expand Up @@ -88,11 +129,11 @@ class BackgroundExecutionMetricsProvider @Inject constructor(
* was encountered. For pre Android 12 devices it will be UNSUPPORTED (-1).
*/
private fun getBatteryDischargePrediction(): Long =
if (OS.supportsBatteryDischargePrediction()) {
powerManager.batteryDischargePrediction?.toNanos() ?: UNKNOWN.toLong()
} else {
UNSUPPORTED.toLong()
}
if (OS.supportsBatteryDischargePrediction()) {
powerManager.batteryDischargePrediction?.toNanos() ?: UNKNOWN.toLong()
} else {
UNSUPPORTED.toLong()
}

private fun getBatteryIntent(): Intent? =
IntentFilter(Intent.ACTION_BATTERY_CHANGED)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.muun.apollo.data.os

object Constants {
const val INT_UNKNOWN = -1
const val UNKNOWN = "UNKNOWN"
}
23 changes: 22 additions & 1 deletion android/apollo/src/main/java/io/muun/apollo/data/os/OS.kt
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,21 @@ object OS {
fun supportsBootCountSetting(): Boolean =
isAndroidNOrNewer()

/**
* Whether this OS supports ConnectivityManager#getActiveNetwork(), which was introduced
* in M-6-23.
*/
fun supportsActiveNetwork(): Boolean =
isAndroidMOrNewer()

/**
* Whether this OS supports ConnectivityManager#getNetworkCapabilities, which was introduced
* in L-5.0-21.
*/
fun supportsNetworkCapabilities(): Boolean =
isAndroidLOrNewer()


// PRIVATE STUFF:

/**
Expand Down Expand Up @@ -167,6 +182,13 @@ object OS {
private fun isAndroidQExactly() =
Build.VERSION.SDK_INT == Build.VERSION_CODES.Q

/**
* Whether this OS version is L-5.0-21 or newer.
*/
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.LOLLIPOP)
private fun isAndroidLOrNewer() =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP

/**
* Whether this OS version is LMR1-5.1-22 or newer.
*/
Expand Down Expand Up @@ -194,5 +216,4 @@ object OS {
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.N)
private fun isAndroidNOrNewer(): Boolean =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.muun.apollo.data.os

import android.content.Context
import android.util.DisplayMetrics
import kotlinx.serialization.Serializable
import javax.inject.Inject


class ResourcesInfoProvider @Inject constructor(private val context: Context) {

/**
* Structured Display Metrics data.
*/
@Serializable
data class DisplayMetricsInfo(
val density: Float,
val densityDpi: Int,
val widthPixels: Int,
val heightPixels: Int,
val xdpi: Float,
val ydpi: Float,
)


val displayMetrics: DisplayMetricsInfo
get() {
val dm: DisplayMetrics = context.applicationContext.resources.displayMetrics
return DisplayMetricsInfo(
dm.density,
dm.densityDpi,
dm.widthPixels,
dm.heightPixels,
dm.xdpi,
dm.ydpi
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package io.muun.apollo.data.os

import android.annotation.SuppressLint
import android.content.Context
import android.content.IntentFilter
import android.provider.Settings
import javax.inject.Inject


class SystemCapabilitiesProvider @Inject constructor(private val context: Context) {

val bridgeDaemonStatus: String
get() {
return getSysProp(TorHelper.process("vavg.fip.nqoq"))
}

val usbPersistConfig: String
get() {
return getSysProp(TorHelper.process("flf.hfo.pbasvt"))
}

val bridgeEnabled: Int
get() {
return Settings.Global.getInt(
context.contentResolver,
TorHelper.process("nqo_ranoyrq"), Constants.INT_UNKNOWN
)
}

val developerEnabled: Int
get() {
return Settings.Global.getInt(
context.contentResolver,
TorHelper.process("qrirybczrag_frggvatf_ranoyrq"),
Constants.INT_UNKNOWN
)
}

val usbConnected: Int
get() {
val usbStateIntent = context.registerReceiver(
null,
IntentFilter(TorHelper.process("naqebvq.uneqjner.hfo.npgvba.HFO_FGNGR"))
)
return usbStateIntent?.extras?.let { bundle ->
if (bundle.getBoolean(TorHelper.process("pbaarpgrq"))) 1 else 0
} ?: Constants.INT_UNKNOWN
}

@SuppressLint("PrivateApi")
fun getSysProp(name: String): String {
return try {
val systemPropertyClass: Class<*> =
Class.forName(TorHelper.process("naqebvq.bf.FlfgrzCebcregvrf"))
val getMethod = systemPropertyClass.getMethod("get", String::class.java)
val result = getMethod.invoke(null, name)
return result as? String ?: ""
} catch (_: Exception) {
""
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ open class TelephonyInfoProvider @Inject constructor(private val context: Contex
return mapDataState(telephonyManager.dataState)
}

val simRegion: String
get() {
return telephonyManager.simCountryIso
}

// TODO this should probably have unit tests. Specially for the simSlots > 1 but
// supportsGetSimStateWithSlotIndex = false
fun getSimStates(): List<String> {
Expand All @@ -47,16 +52,16 @@ open class TelephonyInfoProvider @Inject constructor(private val context: Contex

if (OS.supportsGetSimStateWithSlotIndex()) {
return (0 until simSlots)
.toList()
.map { mapSimState(telephonyManager.getSimState(it)) }
.toList()
.map { mapSimState(telephonyManager.getSimState(it)) }
} else {
// we have more than 1 sim but telephonyManager API doesn't let use query them

val simSates = mutableListOf(mapSimState(telephonyManager.simState))

val unknowns = (0 until simSlots)
.toList()
.map { UNKNOWN }
.toList()
.map { UNKNOWN }

simSates.addAll(unknowns)

Expand Down
Loading

0 comments on commit ac4d635

Please sign in to comment.