Files
Yuvomi-App/legacy/android/tests/LocalNetworkPermissionTest.kt
Yuvomi Mobile Contributors 8c480ddca3 feat(android): replace WebView with tested native Compose API slice
Add real native onboarding/auth/dashboard/tasks/notes/shopping, origin-bound HTTPS and encrypted AndroidKeyStore session persistence. Archive the superseded browser renderer and tests. Verify 10 JVM tests, 6 native API-35 emulator tests, lintDebug/lintRelease and debug/unsigned release APK/AAB builds; the real upstream suite passes 7 tests and exports a nonblank native fixture screenshot. Tink host-tool update removes the old generated-protobuf warning. Full module/visual parity remains explicitly incomplete.
2026-10-21 09:12:47 +02:00

72 lines
3.5 KiB
Kotlin

package community.yuvomi.mobile
import android.Manifest
import android.accessibilityservice.AccessibilityServiceInfo
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.view.accessibility.AccessibilityNodeInfo
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class LocalNetworkPermissionTest {
@Test fun permissionIsOptionalAndHonorsSystemDenialAndGrant() {
val context = ApplicationProvider.getApplicationContext<Context>()
context.getSharedPreferences("server", Context.MODE_PRIVATE).edit().clear().commit()
ActivityScenario.launch(MainActivity::class.java).use {
if (Build.VERSION.SDK_INT < 37 ||
context.checkSelfPermission(Manifest.permission.ACCESS_LOCAL_NETWORK) == PackageManager.PERMISSION_GRANTED
) {
onView(withText("Allow private-network servers")).check(doesNotExist())
return@use
}
val automation = InstrumentationRegistry.getInstrumentation().uiAutomation
automation.serviceInfo = automation.serviceInfo.apply { flags = flags or AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS }
onView(withText("Allow private-network servers")).perform(click())
onView(withText("Cancel")).perform(click())
assertEquals(PackageManager.PERMISSION_DENIED, context.checkSelfPermission(Manifest.permission.ACCESS_LOCAL_NETWORK))
onView(withText("Allow private-network servers")).perform(click())
onView(withText("Continue")).perform(click())
chooseSystemButton("permission_deny_button")
await { context.checkSelfPermission(Manifest.permission.ACCESS_LOCAL_NETWORK) == PackageManager.PERMISSION_DENIED }
onView(withText("Allow private-network servers")).perform(click())
onView(withText("Continue")).perform(click())
chooseSystemButton("permission_allow_button")
await { context.checkSelfPermission(Manifest.permission.ACCESS_LOCAL_NETWORK) == PackageManager.PERMISSION_GRANTED }
}
}
private fun chooseSystemButton(id: String) {
val automation = InstrumentationRegistry.getInstrumentation().uiAutomation
await {
val node = find(automation.rootInActiveWindow, id) ?: return@await false
node.performAction(AccessibilityNodeInfo.ACTION_CLICK)
}
}
private fun find(node: AccessibilityNodeInfo?, id: String): AccessibilityNodeInfo? {
if (node == null) return null
if (node.viewIdResourceName?.endsWith("/$id") == true) return node
for (index in 0 until node.childCount) find(node.getChild(index), id)?.let { return it }
return null
}
private fun await(condition: () -> Boolean) {
val deadline = System.nanoTime() + 10_000_000_000L
while (System.nanoTime() < deadline) {
if (condition()) return
Thread.sleep(100)
}
assertTrue("System permission response timed out", condition())
}
}