summaryrefslogtreecommitdiffhomepage
path: root/android/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'android/app/src')
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SplitTunnelingCell.kt82
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt14
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/Bitmap.kt7
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/Drawable.kt13
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/PackageManagerExtensions.kt7
6 files changed, 79 insertions, 48 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt
index 8215ccde69..c17cb9079b 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt
@@ -1,6 +1,6 @@
package net.mullvad.mullvadvpn.compose.screen
-import android.graphics.Bitmap
+import android.graphics.drawable.Drawable
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
@@ -39,7 +39,7 @@ class SplitTunnelingScreenTest {
onExcludeAppClick: (packageName: String) -> Unit = {},
onIncludeAppClick: (packageName: String) -> Unit = {},
onBackClick: () -> Unit = {},
- onResolveIcon: (String) -> Bitmap? = { null },
+ onResolveIcon: (String) -> Drawable? = { null },
) {
setContentWithTheme {
SplitTunnelingScreen(
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SplitTunnelingCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SplitTunnelingCell.kt
index 15a83776d4..11904157e9 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SplitTunnelingCell.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SplitTunnelingCell.kt
@@ -1,10 +1,13 @@
package net.mullvad.mullvadvpn.compose.cell
-import android.graphics.Bitmap
+import android.graphics.drawable.Drawable
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Remove
@@ -19,21 +22,21 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.ImageBitmap
-import androidx.compose.ui.graphics.asImageBitmap
-import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
+import com.google.accompanist.drawablepainter.rememberDrawablePainter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.component.SpacedColumn
-import net.mullvad.mullvadvpn.compose.util.isBelowMaxBitmapSize
+import net.mullvad.mullvadvpn.compose.util.isBelowMaxSize
import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.lib.theme.Dimens
+import net.mullvad.mullvadvpn.lib.theme.color.AlphaDisabled
import net.mullvad.mullvadvpn.lib.theme.typeface.listItemText
@Preview
@@ -71,35 +74,23 @@ fun SplitTunnelingCell(
enabled: Boolean,
modifier: Modifier = Modifier,
backgroundColor: Color = MaterialTheme.colorScheme.surfaceContainerHigh,
- onResolveIcon: (String) -> Bitmap?,
+ onResolveIcon: (String) -> Drawable?,
onCellClicked: () -> Unit,
) {
- var icon by remember(packageName) { mutableStateOf<ImageBitmap?>(null) }
+ var icon by remember(packageName) { mutableStateOf<IconState>(IconState.Loading) }
LaunchedEffect(packageName) {
launch(Dispatchers.IO) {
- val bitmap = onResolveIcon(packageName ?: "")
- if (bitmap != null && bitmap.isBelowMaxBitmapSize()) {
- icon = bitmap.asImageBitmap()
- }
+ val drawable = onResolveIcon(packageName ?: "")
+ icon =
+ if (drawable != null && drawable.isBelowMaxSize()) {
+ IconState.Icon(drawable = drawable)
+ } else {
+ IconState.NoIcon
+ }
}
}
BaseCell(
- iconView = {
- Image(
- painter =
- icon?.let { iconImage -> BitmapPainter(iconImage) }
- ?: painterResource(id = R.drawable.ic_icons_missing),
- contentDescription = null,
- modifier =
- Modifier.align(Alignment.CenterVertically).size(size = Dimens.listIconSize),
- colorFilter =
- if (icon == null) {
- ColorFilter.tint(MaterialTheme.colorScheme.onSurface)
- } else {
- null
- },
- )
- },
+ iconView = { Icon(iconState = icon) },
headlineContent = {
Text(
text = title,
@@ -130,3 +121,40 @@ fun SplitTunnelingCell(
isRowEnabled = enabled,
)
}
+
+@Composable
+private fun RowScope.Icon(iconState: IconState) {
+ when (iconState) {
+ IconState.Loading ->
+ Box(
+ modifier =
+ Modifier.align(Alignment.CenterVertically)
+ .size(Dimens.listIconSize)
+ .clip(CircleShape)
+ .background(MaterialTheme.colorScheme.onSurface.copy(alpha = AlphaDisabled))
+ )
+ is IconState.Icon ->
+ Image(
+ painter = rememberDrawablePainter(drawable = iconState.drawable),
+ contentDescription = null,
+ modifier =
+ Modifier.align(Alignment.CenterVertically).size(size = Dimens.listIconSize),
+ )
+ IconState.NoIcon ->
+ Image(
+ painter = painterResource(id = R.drawable.ic_icons_missing),
+ contentDescription = null,
+ modifier =
+ Modifier.align(Alignment.CenterVertically).size(size = Dimens.listIconSize),
+ colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface),
+ )
+ }
+}
+
+private sealed class IconState {
+ object Loading : IconState()
+
+ data class Icon(val drawable: Drawable) : IconState()
+
+ object NoIcon : IconState() // Icon not found or icon too large
+}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt
index 5061655003..bfd209b6ff 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt
@@ -1,6 +1,6 @@
package net.mullvad.mullvadvpn.compose.screen
-import android.graphics.Bitmap
+import android.graphics.drawable.Drawable
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
@@ -49,7 +49,7 @@ import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.lib.theme.Dimens
import net.mullvad.mullvadvpn.lib.theme.color.AlphaDisabled
import net.mullvad.mullvadvpn.lib.theme.color.AlphaVisible
-import net.mullvad.mullvadvpn.util.getApplicationIconBitmapOrNull
+import net.mullvad.mullvadvpn.util.getApplicationIconOrNull
import net.mullvad.mullvadvpn.viewmodel.SplitTunnelingViewModel
import org.koin.androidx.compose.koinViewModel
@@ -77,9 +77,7 @@ fun SplitTunneling(navigator: DestinationsNavigator) {
onExcludeAppClick = viewModel::onExcludeAppClick,
onIncludeAppClick = viewModel::onIncludeAppClick,
onBackClick = dropUnlessResumed { navigator.navigateUp() },
- onResolveIcon = { packageName ->
- packageManager.getApplicationIconBitmapOrNull(packageName)
- },
+ onResolveIcon = { packageName -> packageManager.getApplicationIconOrNull(packageName) },
)
}
@@ -91,7 +89,7 @@ fun SplitTunnelingScreen(
onExcludeAppClick: (packageName: String) -> Unit,
onIncludeAppClick: (packageName: String) -> Unit,
onBackClick: () -> Unit,
- onResolveIcon: (String) -> Bitmap?,
+ onResolveIcon: (String) -> Drawable?,
) {
val focusManager = LocalFocusManager.current
@@ -164,7 +162,7 @@ private fun LazyListScope.appList(
onShowSystemAppsClick: (show: Boolean) -> Unit,
onExcludeAppClick: (packageName: String) -> Unit,
onIncludeAppClick: (packageName: String) -> Unit,
- onResolveIcon: (String) -> Bitmap?,
+ onResolveIcon: (String) -> Drawable?,
) {
if (state.excludedApps.isNotEmpty()) {
headerItem(
@@ -206,7 +204,7 @@ private fun LazyListScope.appItems(
apps: List<AppData>,
focusManager: FocusManager,
onAppClick: (String) -> Unit,
- onResolveIcon: (String) -> Bitmap?,
+ onResolveIcon: (String) -> Drawable?,
enabled: Boolean,
excluded: Boolean,
) {
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/Bitmap.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/Bitmap.kt
deleted file mode 100644
index 9a3d030780..0000000000
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/Bitmap.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package net.mullvad.mullvadvpn.compose.util
-
-import android.graphics.Bitmap
-
-private const val MAX_BITMAP_SIZE_BYTES = 100 * 1024 * 1024
-
-fun Bitmap.isBelowMaxBitmapSize(): Boolean = byteCount < MAX_BITMAP_SIZE_BYTES
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/Drawable.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/Drawable.kt
new file mode 100644
index 0000000000..3985590879
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/Drawable.kt
@@ -0,0 +1,13 @@
+package net.mullvad.mullvadvpn.compose.util
+
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+
+private const val MAX_BITMAP_SIZE_BYTES = 100 * 1024 * 1024 // 100MB
+
+fun Drawable.isBelowMaxSize(): Boolean =
+ if (this is BitmapDrawable) {
+ bitmap.byteCount < MAX_BITMAP_SIZE_BYTES
+ } else {
+ true
+ }
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/PackageManagerExtensions.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/PackageManagerExtensions.kt
index 1e7721710e..fc6acfeb6c 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/PackageManagerExtensions.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/PackageManagerExtensions.kt
@@ -1,12 +1,11 @@
package net.mullvad.mullvadvpn.util
import android.content.pm.PackageManager
-import android.graphics.Bitmap
-import androidx.core.graphics.drawable.toBitmapOrNull
+import android.graphics.drawable.Drawable
-fun PackageManager.getApplicationIconBitmapOrNull(packageName: String): Bitmap? =
+fun PackageManager.getApplicationIconOrNull(packageName: String): Drawable? =
try {
- getApplicationIcon(packageName).toBitmapOrNull()
+ getApplicationIcon(packageName)
} catch (e: PackageManager.NameNotFoundException) {
// Name not found is thrown if the application is not installed
null