diff --git a/.github/workflows/pr-check.yaml b/.github/workflows/pr-check.yaml
index 0f1fa44..fe976de 100644
--- a/.github/workflows/pr-check.yaml
+++ b/.github/workflows/pr-check.yaml
@@ -37,7 +37,7 @@ jobs:
uses: actions/setup-java@v3
with:
distribution: 'temurin'
- java-version: '17'
+ java-version: '21'
cache: 'gradle'
- name: Build the app
@@ -93,7 +93,7 @@ jobs:
uses: actions/setup-java@v3
with:
distribution: 'temurin'
- java-version: '17'
+ java-version: '21'
cache: 'gradle'
# - name: Run detekt
@@ -109,7 +109,7 @@ jobs:
target: ${{ matrix.target }}
arch: ${{ matrix.api-level > 27 && 'x86_64' || 'x86' }}
profile: pixel_3a
- script: ./gradlew :android:connectedDebugAndroidTest --stacktrace
+ script: ./gradlew connectedCheck
- name: Upload Reports
uses: actions/upload-artifact@v4
diff --git a/.idea/misc.xml b/.idea/misc.xml
index d514100..0aecc4c 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -19,6 +19,7 @@
+
diff --git a/android/build.gradle b/android/build.gradle
index 7ef58be..a09fec4 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -71,7 +71,7 @@ android {
dependencies {
def lifecycle_version = '2.8.3'
- def dagger_version = '2.56'
+ def dagger_version = '2.57.2'
def coroutines_version = "1.3.9"
def ktor_version = "3.1.1"
@@ -86,7 +86,7 @@ dependencies {
implementation 'io.rownd:telemetry:1.0.1'
- implementation 'androidx.datastore:datastore-preferences:1.1.3'
+ implementation 'androidx.datastore:datastore-preferences:1.1.7'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
@@ -131,25 +131,22 @@ dependencies {
implementation 'com.auth0.android:jwtdecode:2.0.2'
implementation 'com.lyft.kronos:kronos-android:0.0.1-alpha11'
- implementation "com.goterl:lazysodium-android:5.0.2@aar"
- implementation "net.java.dev.jna:jna:5.8.0@aar"
- implementation "androidx.security:security-crypto:1.0.0"
-
// Passkeys & Google sign-in
implementation "androidx.credentials:credentials:1.5.0"
implementation "androidx.credentials:credentials-play-services-auth:1.5.0"
implementation 'com.google.android.libraries.identity.googleid:googleid:1.1.1'
- implementation 'com.google.android.gms:play-services-auth:21.3.0'
+ implementation 'com.google.android.gms:play-services-auth:21.4.0'
// Dependency injection via Dagger
implementation "com.google.dagger:dagger:$dagger_version"
kapt "com.google.dagger:dagger-compiler:$dagger_version"
// For instrumentation tests
- androidTestImplementation 'androidx.test.ext:junit-ktx:1.2.1'
+ androidTestImplementation 'androidx.test.ext:junit-ktx:1.3.0'
testImplementation("io.ktor:ktor-client-mock:$ktor_version")
androidTestImplementation("io.ktor:ktor-client-mock:$ktor_version")
- androidTestImplementation 'com.nimbusds:nimbus-jose-jwt:7.8.1'
+ androidTestImplementation 'com.nimbusds:nimbus-jose-jwt:10.6'
+ androidTestImplementation 'com.google.crypto.tink:tink-android:1.19.0'
androidTestImplementation "com.google.dagger:dagger:$dagger_version"
kaptAndroidTest "com.google.dagger:dagger-compiler:$dagger_version"
diff --git a/android/src/androidTest/java/io/rownd/android/EncryptionInstrumentedTest.kt b/android/src/androidTest/java/io/rownd/android/EncryptionInstrumentedTest.kt
deleted file mode 100644
index bbd46ce..0000000
--- a/android/src/androidTest/java/io/rownd/android/EncryptionInstrumentedTest.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package io.rownd.android
-
-import android.app.Application
-import android.app.Instrumentation
-import android.content.Context
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import com.goterl.lazysodium.utils.Key
-import io.rownd.android.util.Encryption
-import io.rownd.android.util.asBase64String
-import org.junit.After
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotNull
-import org.junit.Assert.assertNull
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import java.util.UUID
-
-class RowndTest : Application()
-
-@RunWith(AndroidJUnit4::class)
-class EncryptionInstrumentedTest {
-
- private val KEY_ID = "test-key"
-
- lateinit var instrumentationContext: Context
-
- @Before
- fun setup() {
- val instrumentation = InstrumentationRegistry.getInstrumentation()
- instrumentationContext = instrumentation.context
-
- val app = Instrumentation.newApplication(Application::class.java, instrumentationContext)
- Rownd.config.stateFileName = "test_datastore_${UUID.randomUUID()}.json"
- Rownd.configure(app, "")
- }
-
- @After
- fun teardown() {
- // Clean up old keys
- Encryption.deleteKey(KEY_ID)
- }
-
- @Test
- fun key_generate() {
- val key = Encryption.generateKey()
- println(key.asBase64String)
- assertNotNull(key)
- }
-
- @Test
- fun encrypt_data() {
- val key = Key.fromBase64String("4f4a6IInDuSga0wyQQQpMSrDHIZ/ryoc9w6s5xVF/VQ=")
-
- val plainText = "This super secret string will never be known."
- val cipherText = Encryption.encrypt(plainText, key)
-
- println(cipherText)
-
- assertNotNull(cipherText)
- }
-
- @Test
- fun decrypt_data() {
- val key = Key.fromBase64String("4f4a6IInDuSga0wyQQQpMSrDHIZ/ryoc9w6s5xVF/VQ=")
- val expectedPlainText = "This super secret string will never be known."
- val cipherText = "Di0IyYbC141WIPKzFnlsQc0BIi1AWKSpLf6Th9TcDDJiidPfkVazXtFibnsqJyKFaQf7SaF68yihnqJXidodfKqKzjM2MnbHbh+O8wpxFO3gO6OhVg=="
-
- val computedPlainText = Encryption.decrypt(cipherText, key)
-
- assertEquals(computedPlainText, expectedPlainText)
- }
-
- @Test
- fun encrypt_then_decrypt() {
- val key = Encryption.generateKey()
-
- val plainText = "This super secret string will never be known."
- val cipherText = Encryption.encrypt(plainText, key)
-
- println(cipherText)
-
- val computedPlainText = Encryption.decrypt(cipherText, key)
-
- assertEquals(computedPlainText, plainText)
- }
-
- @Test
- fun store_encryption_key() {
- val key = Encryption.generateKey()
- Encryption.storeKey(key, KEY_ID)
-
- assert(true) // key stored successfully
- }
-
- @Test
- fun load_encryption_key() {
- val key = Encryption.generateKey()
- Encryption.storeKey(key, KEY_ID)
-
- val storedKey = Encryption.loadKey(KEY_ID)
-
- assertEquals(key.asBase64String, storedKey?.asBase64String)
- }
-
- @Test
- fun load_nonexistant_key() {
- val storedKey = Encryption.loadKey(KEY_ID)
-
- assertNull(storedKey)
- }
-}
\ No newline at end of file
diff --git a/android/src/main/java/io/rownd/android/Rownd.kt b/android/src/main/java/io/rownd/android/Rownd.kt
index bc330e9..b8b381a 100644
--- a/android/src/main/java/io/rownd/android/Rownd.kt
+++ b/android/src/main/java/io/rownd/android/Rownd.kt
@@ -370,10 +370,6 @@ class RowndClient(
}
}
- fun isEncryptionPossible(): Boolean {
- return userRepo.isEncryptionPossible()
- }
-
// Internal stuff
internal fun displayHub(
targetPage: HubPageSelector,
diff --git a/android/src/main/java/io/rownd/android/models/domain/User.kt b/android/src/main/java/io/rownd/android/models/domain/User.kt
index 20f083d..a21a542 100644
--- a/android/src/main/java/io/rownd/android/models/domain/User.kt
+++ b/android/src/main/java/io/rownd/android/models/domain/User.kt
@@ -1,11 +1,9 @@
package io.rownd.android.models.domain
-import android.util.Log
import io.rownd.android.models.repos.StateRepo
import io.rownd.android.models.repos.UserRepo
import io.rownd.android.util.AnyValueSerializer
import io.rownd.android.util.AuthLevel
-import io.rownd.android.util.Encryption
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import io.rownd.android.models.network.User as NetworkUser
@@ -21,34 +19,10 @@ data class User(
) {
fun asNetworkModel(stateRepo: StateRepo, userRepo: UserRepo): NetworkUser {
return NetworkUser(
- data = dataAsEncrypted(stateRepo, userRepo),
+ data = data,
redacted = redacted,
state = state,
authLevel = authLevel,
)
}
-
- internal fun dataAsEncrypted(stateRepo: StateRepo, userRepo: UserRepo): Map {
- val encKeyId = userRepo.ensureEncryptionKey(this) ?: return data
-
- val data = data.toMutableMap()
-
- // Encrypt user fields
- for (entry in data.entries) {
- val (key, _) = entry
- if (stateRepo.state.value.appConfig.schema[key]?.encryption?.state == AppSchemaEncryptionState.Enabled && entry.value is String) {
- val value = entry.value as String
- try {
- val encrypted: String = Encryption.encrypt(value, encKeyId)
- data[key] = encrypted
- } catch (error: Exception) {
- Log.d(
- "RowndUserNetwork",
- "Failed to encrypt user data value. Error: ${error.message}"
- )
- }
- }
- }
- return data
- }
}
\ No newline at end of file
diff --git a/android/src/main/java/io/rownd/android/models/network/SignInLink.kt b/android/src/main/java/io/rownd/android/models/network/SignInLink.kt
index e0a6c8e..cb6c30b 100644
--- a/android/src/main/java/io/rownd/android/models/network/SignInLink.kt
+++ b/android/src/main/java/io/rownd/android/models/network/SignInLink.kt
@@ -21,7 +21,6 @@ import io.rownd.android.models.domain.AuthState
import io.rownd.android.models.repos.StateAction
import io.rownd.android.models.repos.UserRepo
import io.rownd.android.util.AuthenticatedApiClient
-import io.rownd.android.util.Encryption
import io.rownd.android.util.KtorApiClient
import io.rownd.android.util.RowndContext
import io.rownd.android.util.RowndEvent
@@ -79,10 +78,8 @@ class SignInLinkApi @Inject constructor() {
internal suspend fun signInWithLink(url: String) {
var signInUrl = url
val urlObj = url.toUri()
- var encKey: String? = null
if (urlObj.fragment != null) {
- encKey = urlObj.fragment
signInUrl = signInUrl.replace("#${urlObj.fragment}", "")
}
@@ -93,11 +90,6 @@ class SignInLinkApi @Inject constructor() {
try {
val authBody = authenticateWithSignInLink(signInUrl)
- if (encKey != null) {
- Encryption.deleteKey(authBody.appUserId)
- Encryption.storeKey(encKey, authBody.appUserId)
- }
-
Rownd.store.dispatch(
StateAction.SetAuth(
AuthState(
diff --git a/android/src/main/java/io/rownd/android/models/network/User.kt b/android/src/main/java/io/rownd/android/models/network/User.kt
index 3b90b47..a951ed9 100644
--- a/android/src/main/java/io/rownd/android/models/network/User.kt
+++ b/android/src/main/java/io/rownd/android/models/network/User.kt
@@ -1,12 +1,9 @@
package io.rownd.android.models.network
-import android.util.Log
-import io.rownd.android.models.domain.AppSchemaEncryptionState
import io.rownd.android.models.repos.StateRepo
import io.rownd.android.models.repos.UserRepo
import io.rownd.android.util.AnyValueSerializer
import io.rownd.android.util.AuthLevel
-import io.rownd.android.util.Encryption
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import io.rownd.android.models.domain.User as DomainUser
@@ -21,34 +18,10 @@ data class User(
) {
fun asDomainModel(stateRepo: StateRepo, userRepo: UserRepo): DomainUser {
return DomainUser(
- data = dataAsDecrypted(stateRepo, userRepo),
+ data = data,
redacted = redacted.toMutableList(),
state = state,
authLevel = authLevel
)
}
-
- internal fun dataAsDecrypted(stateRepo: StateRepo, userRepo: UserRepo): Map {
- val encKeyId = userRepo.ensureEncryptionKey(DomainUser(data = data)) ?: return data
-
- val data = data.toMutableMap()
-
- // Decrypt user fields
- for (entry in data.entries) {
- val (key, _) = entry
- if (stateRepo.state.value.appConfig.schema[key]?.encryption?.state == AppSchemaEncryptionState.Enabled && entry.value is String) {
- val value = entry.value as String
- try {
- val decrypted: String = Encryption.decrypt(value, encKeyId)
- data[key] = decrypted
- } catch (error: Exception) {
- Log.d(
- "RowndUserNetwork",
- "Failed to decrypt user data value. Error: ${error.message} ${error.stackTraceToString()}"
- )
- }
- }
- }
- return data
- }
}
diff --git a/android/src/main/java/io/rownd/android/models/repos/UserRepo.kt b/android/src/main/java/io/rownd/android/models/repos/UserRepo.kt
index 4eb561a..93f9e7d 100644
--- a/android/src/main/java/io/rownd/android/models/repos/UserRepo.kt
+++ b/android/src/main/java/io/rownd/android/models/repos/UserRepo.kt
@@ -9,8 +9,6 @@ import io.ktor.client.request.setBody
import io.ktor.http.HttpStatusCode
import io.rownd.android.models.domain.User
import io.rownd.android.util.AuthenticatedApiClient
-import io.rownd.android.util.Encryption
-import io.rownd.android.util.EncryptionException
import io.rownd.android.util.RowndContext
import io.rownd.android.util.RowndException
import kotlinx.coroutines.CoroutineScope
@@ -19,7 +17,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import javax.inject.Inject
import javax.inject.Singleton
-import kotlin.collections.set
import io.rownd.android.models.network.User as NetworkUser
@Singleton
@@ -122,41 +119,4 @@ class UserRepo @Inject constructor() {
return saveUserAsync(updatedUser)
}
- fun getKeyId(user: User): String {
- return get("user_id")
- ?: throw EncryptionException("An encryption key was requested, but the user has not been loaded yet. Are you signed in?")
- }
-
- internal fun ensureEncryptionKey(user: User): String? {
- try {
- val keyId = getKeyId(user)
-
- var key = Encryption.loadKey(keyId)
-
- if (key == null) {
- key = Encryption.generateKey()
- Encryption.storeKey(key, keyId)
- return keyId
- }
-
- return keyId
- } catch (error: Exception) {
- Log.e(
- "RowndUser",
- "Failed to ensure that an encryption key exists: ${error.message}"
- )
- return null
- }
- }
-
- fun isEncryptionPossible(): Boolean {
- try {
- val key = Encryption.loadKey(getKeyId(stateRepo.state.value.user)) ?: return false
-
- return true
- } catch (error: Exception) {
- return false
- }
- }
-
}
\ No newline at end of file
diff --git a/android/src/main/java/io/rownd/android/util/Base64.kt b/android/src/main/java/io/rownd/android/util/Base64.kt
new file mode 100644
index 0000000..2f03687
--- /dev/null
+++ b/android/src/main/java/io/rownd/android/util/Base64.kt
@@ -0,0 +1,5 @@
+package io.rownd.android.util
+
+import java.util.Base64
+
+fun ByteArray.toBase64(): String = String(Base64.getEncoder().encode(this))
\ No newline at end of file
diff --git a/android/src/main/java/io/rownd/android/util/Encryption.kt b/android/src/main/java/io/rownd/android/util/Encryption.kt
deleted file mode 100644
index 3400a82..0000000
--- a/android/src/main/java/io/rownd/android/util/Encryption.kt
+++ /dev/null
@@ -1,128 +0,0 @@
-package io.rownd.android.util
-
-import android.content.Context
-import android.util.Log
-import androidx.security.crypto.EncryptedFile
-import androidx.security.crypto.MasterKeys
-import com.goterl.lazysodium.LazySodiumAndroid
-import com.goterl.lazysodium.SodiumAndroid
-import com.goterl.lazysodium.exceptions.SodiumException
-import com.goterl.lazysodium.interfaces.SecretBox
-import com.goterl.lazysodium.utils.Base64MessageEncoder
-import com.goterl.lazysodium.utils.Key
-import io.rownd.android.Rownd
-import java.io.ByteArrayOutputStream
-import java.io.File
-import java.io.IOException
-import java.util.*
-
-
-object Encryption {
- private val messageEncoder = Base64MessageEncoder()
- private val ls: LazySodiumAndroid = LazySodiumAndroid(SodiumAndroid(), messageEncoder)
- private val context: Context
- get() = Rownd.appHandleWrapper?.app?.get()?.applicationContext ?: throw EncryptionException("No context available. Did you call Rownd.configure()?")
-
- private fun keyName(keyId: String?): String {
- return "io.rownd.key.${keyId ?: "default"}"
- }
-
- private fun getKeyFile(keyId: String): EncryptedFile {
- val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
- val mainKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)
- return EncryptedFile.Builder(
- File(context.filesDir, keyId),
- context,
- mainKeyAlias,
- EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
- ).build()
- }
-
- fun doesKeyExist(keyId: String): Boolean {
- val keyFile = File(context.filesDir, keyName(keyId))
-
- return keyFile.exists()
- }
-
- fun storeKey(key: Key, keyId: String) {
- val keyFile = getKeyFile(keyName(keyId))
-
- keyFile.openFileOutput().apply {
- write(key.asBytes)
- flush()
- close()
- }
- }
-
- fun storeKey(key: String, keyId: String) {
- storeKey(Key.fromBase64String(key), keyId)
- }
-
- fun loadKey(keyId: String): Key? {
- val keyFile = getKeyFile(keyName(keyId))
-
- try {
- val inputStream = keyFile.openFileInput()
- val byteArrayOutputStream = ByteArrayOutputStream()
-
- val buffer = ByteArray(1024)
- var bytesRead: Int
- while (inputStream.read(buffer).also { bytesRead = it } != -1) {
- byteArrayOutputStream.write(buffer, 0, bytesRead)
- }
-
- val keyBytes = byteArrayOutputStream.toByteArray()
-
- return Key.fromBytes(keyBytes)
- } catch (error: IOException) {
- return null
- } catch (error: Exception) {
- Log.e("Rownd", "Failed to load encryption key: ${error.message}")
- return null
- }
- }
-
- fun deleteKey(keyId: String) {
- val keyFile = File(context.filesDir, keyName(keyId))
- keyFile.delete()
- }
-
- fun generateKey(): Key {
- return ls.cryptoSecretBoxKeygen()
- }
-
- @Throws(SodiumException::class)
- fun encrypt(plaintext: String, withKey: Key): String {
- val nonce = ls.randomBytesBuf(SecretBox.NONCEBYTES)
- val ciphertext = ls.cryptoSecretBoxEasy(plaintext, nonce, withKey)
-
- return messageEncoder.encode(nonce + messageEncoder.decode(ciphertext))
- }
-
- @Throws(SodiumException::class)
- fun encrypt(plaintext: String, keyId: String): String {
- val key = loadKey(keyId) ?: throw EncryptionException("The requested key '$keyId' could not be found")
- return encrypt(plaintext, key)
- }
-
- @Throws(SodiumException::class)
- fun decrypt(ciphertext: String, withKey: Key): String {
- val noncedCipherByteArray = messageEncoder.decode(ciphertext)
- val nonce = noncedCipherByteArray.copyOfRange(0, SecretBox.NONCEBYTES)
- val cipherTextBytes = noncedCipherByteArray.copyOfRange(SecretBox.NONCEBYTES, noncedCipherByteArray.size)
- return ls.cryptoSecretBoxOpenEasy(messageEncoder.encode(cipherTextBytes), nonce, withKey)
- }
-
- @Throws(SodiumException::class)
- fun decrypt(ciphertext: String, keyId: String): String {
- val key = loadKey(keyId) ?: throw EncryptionException("The requested key '$keyId' could not be found")
- return decrypt(ciphertext, key)
- }
-}
-
-fun ByteArray.toBase64(): String = String(Base64.getEncoder().encode(this))
-
-val Key.asBase64String: String
- get() = this.asBytes.toBase64()
-
-class EncryptionException(message: String) : Exception(message)
\ No newline at end of file
diff --git a/app/src/androidTest/java/io/rownd/rowndtestsandbox/ExampleInstrumentedTest.kt b/app/src/androidTest/java/io/rownd/rowndtestsandbox/ExampleInstrumentedTest.kt
index 5ed3c94..4312132 100644
--- a/app/src/androidTest/java/io/rownd/rowndtestsandbox/ExampleInstrumentedTest.kt
+++ b/app/src/androidTest/java/io/rownd/rowndtestsandbox/ExampleInstrumentedTest.kt
@@ -1,13 +1,11 @@
package io.rownd.rowndtestsandbox
-import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
-
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.Assert.*
-
/**
* Instrumented test, which will execute on an Android device.
*
@@ -19,6 +17,6 @@ class ExampleInstrumentedTest {
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("io.rownd.rowndtestsandbox", appContext.packageName)
+ assertEquals("io.rownd.rowndtestsandbox.app", appContext.packageName)
}
}
\ No newline at end of file
diff --git a/app_full/src/androidTest/java/io/rownd/rowndtestsandbox/app_instant/ExampleInstrumentedTest.kt b/app_full/src/androidTest/java/io/rownd/rowndtestsandbox/app_instant/ExampleInstrumentedTest.kt
index 08d14d3..d31ec50 100644
--- a/app_full/src/androidTest/java/io/rownd/rowndtestsandbox/app_instant/ExampleInstrumentedTest.kt
+++ b/app_full/src/androidTest/java/io/rownd/rowndtestsandbox/app_instant/ExampleInstrumentedTest.kt
@@ -1,13 +1,11 @@
package io.rownd.rowndtestsandbox.app_instant
-import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
-
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.Assert.*
-
/**
* Instrumented test, which will execute on an Android device.
*
@@ -19,6 +17,6 @@ class ExampleInstrumentedTest {
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("io.rownd.rowndtestsandbox.app_full", appContext.packageName)
+ assertEquals("io.rownd.rowndtestsandbox", appContext.packageName)
}
}
\ No newline at end of file
diff --git a/app_instant/src/androidTest/java/io/rownd/rowndtestsandbox/app_instant/ExampleInstrumentedTest.kt b/app_instant/src/androidTest/java/io/rownd/rowndtestsandbox/app_instant/ExampleInstrumentedTest.kt
index ef246d3..d31ec50 100644
--- a/app_instant/src/androidTest/java/io/rownd/rowndtestsandbox/app_instant/ExampleInstrumentedTest.kt
+++ b/app_instant/src/androidTest/java/io/rownd/rowndtestsandbox/app_instant/ExampleInstrumentedTest.kt
@@ -1,13 +1,11 @@
package io.rownd.rowndtestsandbox.app_instant
-import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
-
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.Assert.*
-
/**
* Instrumented test, which will execute on an Android device.
*
@@ -19,6 +17,6 @@ class ExampleInstrumentedTest {
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("io.rownd.rowndtestsandbox.app_instant", appContext.packageName)
+ assertEquals("io.rownd.rowndtestsandbox", appContext.packageName)
}
}
\ No newline at end of file