Implement CameraX GPG QR transfer on Android (#106)
This commit is contained in:
1 parent
6669b77f4e
commit
d466b170ab
33 files changed
+1530
-76
No files matched your search
@@ -8,6 +8,8 @@ UniFFI API. Local-first and HTTPS onboarding is described in
|
|||||||
revision-checked [adaptive navigation](../docs/android/password-navigation.md);
|
revision-checked [adaptive navigation](../docs/android/password-navigation.md);
|
||||||
Home renders Rust-owned [Git activity and HTTPS synchronization](../docs/android/home-sync.md).
|
Home renders Rust-owned [Git activity and HTTPS synchronization](../docs/android/home-sync.md).
|
||||||
Passwords and Preferences share [Rust-owned biometric authentication](../docs/android/authentication.md).
|
Passwords and Preferences share [Rust-owned biometric authentication](../docs/android/authentication.md).
|
||||||
|
CameraX GPG scanning and QR export are described in
|
||||||
|
[key transfer](../docs/android/key-transfer.md).
|
||||||
Remaining feature screens retain their milestone issues. The full [CI and emulator workflow](../docs/android/ci.md) documents the
|
Remaining feature screens retain their milestone issues. The full [CI and emulator workflow](../docs/android/ci.md) documents the
|
||||||
ARM-only runner/toolchain policy and artifact audits.
|
ARM-only runner/toolchain policy and artifact audits.
|
||||||
|
|
||||||
|
|||||||
+29
-13
@@ -16,6 +16,14 @@ androidx.arch.core:core-common:2.2.0=benchmarkCompileClasspath,benchmarkLintChec
|
|||||||
androidx.arch.core:core-runtime:2.2.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.arch.core:core-runtime:2.2.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.autofill:autofill:1.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.autofill:autofill:1.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.biometric:biometric:1.1.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.biometric:biometric:1.1.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera.featurecombinationquery:featurecombinationquery:1.6.2=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera.viewfinder:viewfinder-core:1.5.1=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera:camera-camera2-pipe:1.6.2=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera:camera-camera2:1.6.2=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera:camera-core:1.6.2=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera:camera-lifecycle:1.6.2=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera:camera-video:1.6.2=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera:camera-view:1.6.2=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.cardview:cardview:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.cardview:cardview:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
androidx.collection:collection-jvm:1.5.0=benchmarkCompileClasspath,debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,profileCompileClasspath,releaseCompileClasspath
|
androidx.collection:collection-jvm:1.5.0=benchmarkCompileClasspath,debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,profileCompileClasspath,releaseCompileClasspath
|
||||||
androidx.collection:collection-jvm:1.6.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.collection:collection-jvm:1.6.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -67,10 +75,12 @@ androidx.compose.ui:ui-util-android:1.12.1=benchmarkCompileClasspath,benchmarkLi
|
|||||||
androidx.compose.ui:ui-util:1.12.1=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.compose.ui:ui-util:1.12.1=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.compose.ui:ui:1.12.1=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.compose.ui:ui:1.12.1=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.compose:compose-bom:2026.09.00=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.compose:compose-bom:2026.09.00=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.concurrent:concurrent-futures-ktx:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.concurrent:concurrent-futures-ktx:1.1.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.concurrent:concurrent-futures-ktx:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath
|
||||||
androidx.concurrent:concurrent-futures:1.1.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.concurrent:concurrent-futures:1.1.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.concurrent:concurrent-futures:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath
|
androidx.concurrent:concurrent-futures:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath
|
||||||
androidx.coordinatorlayout:coordinatorlayout:1.1.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.coordinatorlayout:coordinatorlayout:1.1.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.core:core-backported-fixes:1.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.core:core-ktx:1.18.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.core:core-ktx:1.18.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.core:core-viewtree:1.0.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.core:core-viewtree:1.0.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.core:core:1.18.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.core:core:1.18.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -79,6 +89,7 @@ androidx.customview:customview-poolingcontainer:1.0.0=benchmarkLintChecksClasspa
|
|||||||
androidx.customview:customview:1.0.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.customview:customview:1.0.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.drawerlayout:drawerlayout:1.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.drawerlayout:drawerlayout:1.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.emoji2:emoji2:1.4.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.emoji2:emoji2:1.4.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.exifinterface:exifinterface:1.4.2=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.fragment:fragment:1.9.1=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.fragment:fragment:1.9.1=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.graphics:graphics-path:1.0.1=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.graphics:graphics-path:1.0.1=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.interpolator:interpolator:1.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.interpolator:interpolator:1.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -103,6 +114,9 @@ androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.11.0=benchmarkCompil
|
|||||||
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.11.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.11.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.lifecycle:lifecycle-viewmodel:2.11.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.lifecycle:lifecycle-viewmodel:2.11.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.loader:loader:1.0.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.loader:loader:1.0.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.media3:media3-common:1.9.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.media3:media3-container:1.9.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.media3:media3-muxer:1.9.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.navigation3:navigation3-runtime-android:1.2.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.navigation3:navigation3-runtime-android:1.2.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.navigation3:navigation3-runtime:1.2.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.navigation3:navigation3-runtime:1.2.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.navigation3:navigation3-ui-android:1.2.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.navigation3:navigation3-ui-android:1.2.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -128,6 +142,7 @@ androidx.test:monitor:1.8.0=debugAndroidTestCompileClasspath,debugAndroidTestLin
|
|||||||
androidx.test:rules:1.4.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.test:rules:1.4.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
androidx.test:runner:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.test:runner:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
androidx.tracing:tracing-android:2.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.tracing:tracing-android:2.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.tracing:tracing-ktx:2.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.tracing:tracing:1.1.0=debugAndroidTestCompileClasspath
|
androidx.tracing:tracing:1.1.0=debugAndroidTestCompileClasspath
|
||||||
androidx.tracing:tracing:2.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.tracing:tracing:2.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.transition:transition:1.2.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.transition:transition:1.2.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
@@ -174,6 +189,7 @@ com.github.ajalt.clikt:clikt-jvm:5.0.3=ktlint
|
|||||||
com.github.ajalt.clikt:clikt:5.0.3=ktlint
|
com.github.ajalt.clikt:clikt:5.0.3=ktlint
|
||||||
com.google.android.apps.common.testing.accessibility.framework:accessibility-test-framework:4.1.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
com.google.android.apps.common.testing.accessibility.framework:accessibility-test-framework:4.1.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
com.google.android.material:material:1.2.0-rc01=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
com.google.android.material:material:1.2.0-rc01=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
com.google.auto.value:auto-value-annotations:1.6.3=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
com.google.code.findbugs:jsr305:3.0.2=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,androidLintTool,benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
com.google.code.findbugs:jsr305:3.0.2=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,androidLintTool,benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
com.google.code.gson:gson:2.11.0=androidLintTool
|
com.google.code.gson:gson:2.11.0=androidLintTool
|
||||||
com.google.dagger:dagger-compiler:2.60.1=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
com.google.dagger:dagger-compiler:2.60.1=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
@@ -185,20 +201,19 @@ com.google.dagger:hilt-compiler:2.60.1=_agp_internal_benchmark_kspClasspath,_agp
|
|||||||
com.google.dagger:hilt-core:2.60.1=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
com.google.dagger:hilt-core:2.60.1=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
com.google.devtools.ksp:symbol-processing-api:2.3.12=kotlinCompilerPluginClasspathBenchmark,kotlinCompilerPluginClasspathDebug,kotlinCompilerPluginClasspathDebugAndroidTest,kotlinCompilerPluginClasspathDebugUnitTest,kotlinCompilerPluginClasspathProfile,kotlinCompilerPluginClasspathRelease,kspPluginClasspath,kspPluginClasspathNonEmbeddable
|
com.google.devtools.ksp:symbol-processing-api:2.3.12=kotlinCompilerPluginClasspathBenchmark,kotlinCompilerPluginClasspathDebug,kotlinCompilerPluginClasspathDebugAndroidTest,kotlinCompilerPluginClasspathDebugUnitTest,kotlinCompilerPluginClasspathProfile,kotlinCompilerPluginClasspathRelease,kspPluginClasspath,kspPluginClasspathNonEmbeddable
|
||||||
com.google.devtools.ksp:symbol-processing-api:2.3.7=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
com.google.devtools.ksp:symbol-processing-api:2.3.7=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
com.google.errorprone:error_prone_annotations:2.30.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
com.google.errorprone:error_prone_annotations:2.28.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
com.google.errorprone:error_prone_annotations:2.30.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath
|
||||||
com.google.errorprone:error_prone_annotations:2.36.0=androidLintTool
|
com.google.errorprone:error_prone_annotations:2.36.0=androidLintTool
|
||||||
com.google.errorprone:error_prone_annotations:2.47.0=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
com.google.errorprone:error_prone_annotations:2.47.0=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
com.google.googlejavaformat:google-java-format:1.33.0=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
com.google.googlejavaformat:google-java-format:1.33.0=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
com.google.guava:failureaccess:1.0.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
com.google.guava:failureaccess:1.0.2=androidLintTool,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
com.google.guava:failureaccess:1.0.2=androidLintTool
|
|
||||||
com.google.guava:failureaccess:1.0.3=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
com.google.guava:failureaccess:1.0.3=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
com.google.guava:guava:31.0.1-android=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
com.google.guava:guava:33.3.1-android=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
com.google.guava:guava:33.4.0-jre=androidLintTool
|
com.google.guava:guava:33.4.0-jre=androidLintTool
|
||||||
com.google.guava:guava:33.6.0-jre=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
com.google.guava:guava:33.6.0-jre=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
com.google.guava:listenablefuture:1.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
com.google.guava:listenablefuture:1.0=benchmarkCompileClasspath,debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,profileCompileClasspath,releaseCompileClasspath
|
||||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,androidLintTool,debugAndroidTestLintChecksClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,androidLintTool,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
com.google.j2objc:j2objc-annotations:1.3=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
com.google.j2objc:j2objc-annotations:3.0.0=androidLintTool,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
com.google.j2objc:j2objc-annotations:3.0.0=androidLintTool
|
|
||||||
com.google.j2objc:j2objc-annotations:3.1=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
com.google.j2objc:j2objc-annotations:3.1=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
com.google.jimfs:jimfs:1.1=androidLintTool
|
com.google.jimfs:jimfs:1.1=androidLintTool
|
||||||
com.google.protobuf:protobuf-java:3.25.5=androidLintTool,unified-test-platform-gradle-work-action
|
com.google.protobuf:protobuf-java:3.25.5=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
@@ -252,15 +267,14 @@ org.bouncycastle:bcpkix-jdk18on:1.80.2=androidLintTool
|
|||||||
org.bouncycastle:bcprov-jdk18on:1.80.2=androidLintTool
|
org.bouncycastle:bcprov-jdk18on:1.80.2=androidLintTool
|
||||||
org.bouncycastle:bcutil-jdk18on:1.80.2=androidLintTool
|
org.bouncycastle:bcutil-jdk18on:1.80.2=androidLintTool
|
||||||
org.checkerframework:checker-compat-qual:2.5.3=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
org.checkerframework:checker-compat-qual:2.5.3=_agp_internal_benchmark_kspClasspath,_agp_internal_debug_kspClasspath,_agp_internal_profile_kspClasspath,_agp_internal_release_kspClasspath,hiltAnnotationProcessorBenchmark,hiltAnnotationProcessorDebug,hiltAnnotationProcessorDebugAndroidTest,hiltAnnotationProcessorDebugUnitTest,hiltAnnotationProcessorProfile,hiltAnnotationProcessorRelease,kspBenchmarkKotlinProcessorClasspath,kspDebugKotlinProcessorClasspath,kspProfileKotlinProcessorClasspath,kspReleaseKotlinProcessorClasspath
|
||||||
org.checkerframework:checker-compat-qual:2.5.5=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
org.checkerframework:checker-qual:3.43.0=androidLintTool,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.checkerframework:checker-qual:3.22.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
|
||||||
org.checkerframework:checker-qual:3.43.0=androidLintTool
|
|
||||||
org.ec4j.core:ec4j-core:1.1.1=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.ec4j.core:ec4j-core:1.1.1=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
||||||
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
||||||
org.hamcrest:hamcrest-core:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
org.hamcrest:hamcrest-core:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
org.hamcrest:hamcrest-library:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
org.hamcrest:hamcrest-library:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
org.jetbrains.kotlin:compose-group-mapping:2.4.21=composeMappingProducerClasspath
|
org.jetbrains.kotlin:compose-group-mapping:2.4.21=composeMappingProducerClasspath
|
||||||
|
org.jetbrains.kotlin:kotlin-bom:1.8.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
@@ -298,6 +312,8 @@ org.jetbrains.kotlin:kotlin-stdlib:2.3.21=_agp_internal_benchmark_kspClasspath,_
|
|||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.21=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.21=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-tooling-core:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-tooling-core:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
|
org.jetbrains.kotlinx:atomicfu-jvm:0.28.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.jetbrains.kotlinx:atomicfu:0.28.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
@@ -333,4 +349,4 @@ org.ow2.asm:asm:9.9=androidLintTool
|
|||||||
org.ow2.asm:asm:9.9.1=composeMappingProducerClasspath
|
org.ow2.asm:asm:9.9.1=composeMappingProducerClasspath
|
||||||
org.slf4j:slf4j-api:2.0.7=ktlint
|
org.slf4j:slf4j-api:2.0.7=ktlint
|
||||||
rustls:rustls-platform-verifier:0.1.1=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
rustls:rustls-platform-verifier:0.1.1=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,profileLintChecksClasspath,profileRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
empty=_agp_internal_debugAndroidTest_kspClasspath,_agp_internal_debugUnitTest_kspClasspath,androidApis,androidJdkImage,androidTestUtil,benchmarkAnnotationProcessorClasspath,benchmarkImplementationDependenciesMetadata,benchmarkReverseMetadataValues,coreLibraryDesugaring,debugAndroidTestAnnotationProcessorClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAnnotationProcessorClasspath,debugImplementationDependenciesMetadata,debugReverseMetadataValues,debugUnitTestAnnotationProcessorClasspath,debugUnitTestImplementationDependenciesMetadata,hiltCompileOnlyBenchmark,hiltCompileOnlyDebug,hiltCompileOnlyDebugAndroidTest,hiltCompileOnlyDebugUnitTest,hiltCompileOnlyProfile,hiltCompileOnlyRelease,kotlinCompilerPluginClasspath,kspDebugAndroidTestKotlinProcessorClasspath,kspDebugUnitTestKotlinProcessorClasspath,lintChecks,lintPublish,profileAnnotationProcessorClasspath,profileReverseMetadataValues,releaseAnnotationProcessorClasspath,releaseImplementationDependenciesMetadata,releaseReverseMetadataValues
|
empty=_agp_internal_debugAndroidTest_kspClasspath,_agp_internal_debugUnitTest_kspClasspath,androidApis,androidJdkImage,androidTestUtil,benchmarkAnnotationProcessorClasspath,benchmarkImplementationDependenciesMetadata,benchmarkReverseMetadataValues,coreLibraryDesugaring,debugAndroidTestAnnotationProcessorClasspath,debugAndroidTestImplementationDependenciesMetadata,debugAnnotationProcessorClasspath,debugImplementationDependenciesMetadata,debugReverseMetadataValues,debugUnitTestAnnotationProcessorClasspath,debugUnitTestImplementationDependenciesMetadata,hiltCompileOnlyBenchmark,hiltCompileOnlyDebug,hiltCompileOnlyDebugAndroidTest,hiltCompileOnlyDebugUnitTest,hiltCompileOnlyProfile,hiltCompileOnlyRelease,kotlinCompilerPluginClasspath,kspDebugAndroidTestKotlinProcessorClasspath,kspDebugUnitTestKotlinProcessorClasspath,lintChecks,lintPublish,profileAnnotationProcessorClasspath,profileImplementationDependenciesMetadata,profileReverseMetadataValues,releaseAnnotationProcessorClasspath,releaseImplementationDependenciesMetadata,releaseReverseMetadataValues
|
||||||
@@ -8,11 +8,13 @@ import androidx.compose.ui.test.onNodeWithText
|
|||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
import androidx.compose.ui.test.performScrollTo
|
import androidx.compose.ui.test.performScrollTo
|
||||||
import androidx.compose.ui.test.performTextInput
|
import androidx.compose.ui.test.performTextInput
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import de.rfc1437.ironstorage.core.OnboardingRepository
|
import de.rfc1437.ironstorage.core.OnboardingRepository
|
||||||
import de.rfc1437.ironstorage.core.SetupKey
|
import de.rfc1437.ironstorage.core.SetupKey
|
||||||
import de.rfc1437.ironstorage.core.SetupStatus
|
import de.rfc1437.ironstorage.core.SetupStatus
|
||||||
import de.rfc1437.ironstorage.features.OnboardingScreen
|
import de.rfc1437.ironstorage.features.OnboardingScreen
|
||||||
import de.rfc1437.ironstorage.features.SetupFormViewModel
|
import de.rfc1437.ironstorage.features.SetupFormViewModel
|
||||||
|
import de.rfc1437.ironstorage.features.ShellViewModel
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
@@ -32,7 +34,16 @@ class OnboardingScreenTest {
|
|||||||
val secrets = SetupFormViewModel()
|
val secrets = SetupFormViewModel()
|
||||||
compose.activity.runOnUiThread {
|
compose.activity.runOnUiThread {
|
||||||
compose.activity.setProtectedTestContent {
|
compose.activity.setProtectedTestContent {
|
||||||
MaterialTheme { OnboardingScreen(repository, secrets) }
|
MaterialTheme {
|
||||||
|
OnboardingScreen(
|
||||||
|
repository,
|
||||||
|
secrets,
|
||||||
|
SettingsScreenTest.Fixture(),
|
||||||
|
androidx.lifecycle.ViewModelProvider(
|
||||||
|
compose.activity
|
||||||
|
)[de.rfc1437.ironstorage.features.ShellViewModel::class.java].authentication
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compose.waitForIdle()
|
compose.waitForIdle()
|
||||||
@@ -60,6 +71,45 @@ class OnboardingScreenTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun closingQrReviewReloadsPreparedOnboardingKeysWithoutCreatingAStore() {
|
||||||
|
val original = FixtureRepository()
|
||||||
|
val settings = SettingsScreenTest.Fixture()
|
||||||
|
val secrets = SetupFormViewModel()
|
||||||
|
var staged = false
|
||||||
|
val repository = object : OnboardingRepository by original {
|
||||||
|
override fun refresh() {
|
||||||
|
if (staged) {
|
||||||
|
original.setup.value = original.setup.value.copy(
|
||||||
|
keys = listOf(
|
||||||
|
SetupKey("SCANNED-SETUP-KEY", listOf("Scanned setup fixture"))
|
||||||
|
),
|
||||||
|
selectedKey = "SCANNED-SETUP-KEY"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val model = ViewModelProvider(compose.activity)[ShellViewModel::class.java]
|
||||||
|
val authentication = model.authentication
|
||||||
|
compose.activity.runOnUiThread {
|
||||||
|
compose.activity.setProtectedTestContent {
|
||||||
|
MaterialTheme {
|
||||||
|
OnboardingScreen(repository, secrets, settings, authentication)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compose.onNodeWithText("Create local store").performClick()
|
||||||
|
compose.onNodeWithText("Import private GPG key").performScrollTo().performClick()
|
||||||
|
compose.onNodeWithText("Scan GPG QR codes").performScrollTo().performClick()
|
||||||
|
compose.runOnIdle { staged = true }
|
||||||
|
compose.onNodeWithText("Done").performClick()
|
||||||
|
compose.runOnIdle { assertEquals("SCANNED-SETUP-KEY", original.setup.value.selectedKey) }
|
||||||
|
compose.onNodeWithText("Back to setup choices").performScrollTo().performClick()
|
||||||
|
compose.onNodeWithText("Create local store").performClick()
|
||||||
|
compose.onNodeWithText("SCANNED-SETUP-KEY").performScrollTo().assertIsDisplayed()
|
||||||
|
assertTrue(!original.setup.value.configured)
|
||||||
|
assertTrue(original.calls.isEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
private class FixtureRepository : OnboardingRepository {
|
private class FixtureRepository : OnboardingRepository {
|
||||||
override val setup = MutableStateFlow(SetupStatus())
|
override val setup = MutableStateFlow(SetupStatus())
|
||||||
val calls = mutableListOf<String>()
|
val calls = mutableListOf<String>()
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import androidx.compose.runtime.CompositionLocalProvider
|
|||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.test.assertHeightIsAtLeast
|
import androidx.compose.ui.test.assertHeightIsAtLeast
|
||||||
import androidx.compose.ui.test.assertIsDisplayed
|
import androidx.compose.ui.test.assertIsDisplayed
|
||||||
|
import androidx.compose.ui.test.assertIsEnabled
|
||||||
|
import androidx.compose.ui.test.assertIsNotEnabled
|
||||||
import androidx.compose.ui.test.assertTextContains
|
import androidx.compose.ui.test.assertTextContains
|
||||||
import androidx.compose.ui.test.assertWidthIsAtLeast
|
import androidx.compose.ui.test.assertWidthIsAtLeast
|
||||||
import androidx.compose.ui.test.hasText
|
import androidx.compose.ui.test.hasText
|
||||||
@@ -24,6 +26,7 @@ import androidx.lifecycle.ViewModelProvider
|
|||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import de.rfc1437.ironstorage.core.AuthenticationRepository
|
import de.rfc1437.ironstorage.core.AuthenticationRepository
|
||||||
import de.rfc1437.ironstorage.core.AuthenticationState
|
import de.rfc1437.ironstorage.core.AuthenticationState
|
||||||
|
import de.rfc1437.ironstorage.core.CameraPreview
|
||||||
import de.rfc1437.ironstorage.core.KeyTransferState
|
import de.rfc1437.ironstorage.core.KeyTransferState
|
||||||
import de.rfc1437.ironstorage.core.ProtectedPresentation
|
import de.rfc1437.ironstorage.core.ProtectedPresentation
|
||||||
import de.rfc1437.ironstorage.core.ProviderStatus
|
import de.rfc1437.ironstorage.core.ProviderStatus
|
||||||
@@ -31,7 +34,9 @@ import de.rfc1437.ironstorage.core.SettingsPage
|
|||||||
import de.rfc1437.ironstorage.core.SettingsRepository
|
import de.rfc1437.ironstorage.core.SettingsRepository
|
||||||
import de.rfc1437.ironstorage.core.SettingsState
|
import de.rfc1437.ironstorage.core.SettingsState
|
||||||
import de.rfc1437.ironstorage.core.TransferFrame
|
import de.rfc1437.ironstorage.core.TransferFrame
|
||||||
|
import de.rfc1437.ironstorage.core.TransferKey
|
||||||
import de.rfc1437.ironstorage.features.ApplicationTheme
|
import de.rfc1437.ironstorage.features.ApplicationTheme
|
||||||
|
import de.rfc1437.ironstorage.features.R as FeatureR
|
||||||
import de.rfc1437.ironstorage.features.SettingsScreen
|
import de.rfc1437.ironstorage.features.SettingsScreen
|
||||||
import de.rfc1437.ironstorage.features.SetupFormViewModel
|
import de.rfc1437.ironstorage.features.SetupFormViewModel
|
||||||
import de.rfc1437.ironstorage.features.ShellViewModel
|
import de.rfc1437.ironstorage.features.ShellViewModel
|
||||||
@@ -164,6 +169,69 @@ class SettingsScreenTest {
|
|||||||
authentication.presentation.clear()
|
authentication.presentation.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test fun privateQrActionsRequireFingerprintConfirmationAndExplicitClosing() {
|
||||||
|
val original = ViewModelProvider(compose.activity)[ShellViewModel::class.java]
|
||||||
|
val repository = Fixture()
|
||||||
|
val authentication = object : AuthenticationRepository by original.authentication {
|
||||||
|
override val presentation = ProtectedPresentation()
|
||||||
|
}
|
||||||
|
compose.activity.runOnUiThread {
|
||||||
|
compose.activity.setProtectedTestContent(authentication.presentation) {
|
||||||
|
ApplicationTheme(authentication) {
|
||||||
|
de.rfc1437.ironstorage.features.SettingsScreen(
|
||||||
|
repository,
|
||||||
|
authentication,
|
||||||
|
original.onboarding,
|
||||||
|
ViewModelProvider(compose.activity)[SetupFormViewModel::class.java]
|
||||||
|
) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compose.onNodeWithTag(
|
||||||
|
"settings-list"
|
||||||
|
).performScrollToNode(hasText("Import or export GPG QR codes"))
|
||||||
|
compose.onNodeWithText("Import or export GPG QR codes").performClick()
|
||||||
|
compose.onNodeWithText("Export private key").performScrollTo().performClick()
|
||||||
|
compose.onNodeWithText(
|
||||||
|
"Confirm and export selected key"
|
||||||
|
).performScrollTo().assertIsNotEnabled()
|
||||||
|
compose.onNodeWithText(
|
||||||
|
"I checked this fingerprint and authorize displaying its private QR codes."
|
||||||
|
)
|
||||||
|
.performScrollTo().performClick()
|
||||||
|
compose.onNodeWithText(
|
||||||
|
"Confirm and export selected key"
|
||||||
|
).performScrollTo().assertIsEnabled().performClick()
|
||||||
|
assertEquals(1, repository.exports)
|
||||||
|
compose.runOnIdle {
|
||||||
|
repository.state.value = repository.state.value.copy(
|
||||||
|
transfer = repository.state.value.transfer.copy(
|
||||||
|
ready = TransferKey(
|
||||||
|
"SCANNED-FINGERPRINT",
|
||||||
|
"Scanned fixture",
|
||||||
|
true
|
||||||
|
),
|
||||||
|
received = 2u,
|
||||||
|
total = 2u
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
compose.onNodeWithText(
|
||||||
|
"Confirm and import reconstructed key"
|
||||||
|
).performScrollTo().assertIsNotEnabled()
|
||||||
|
compose.onNodeWithText("SCANNED-FINGERPRINT").performScrollTo().assertIsDisplayed()
|
||||||
|
compose.onNodeWithText(
|
||||||
|
"I checked this fingerprint and authorize importing its private key material."
|
||||||
|
)
|
||||||
|
.performScrollTo().performClick()
|
||||||
|
compose.onNodeWithText(
|
||||||
|
"Confirm and import reconstructed key"
|
||||||
|
).performScrollTo().assertIsEnabled().performClick()
|
||||||
|
assertEquals(1, repository.imports)
|
||||||
|
compose.onNodeWithText("Done").performClick()
|
||||||
|
assertFalse(repository.state.value.transfer.open)
|
||||||
|
}
|
||||||
internal class Fixture : SettingsRepository {
|
internal class Fixture : SettingsRepository {
|
||||||
override val state = MutableStateFlow(
|
override val state = MutableStateFlow(
|
||||||
SettingsState(
|
SettingsState(
|
||||||
@@ -193,6 +261,8 @@ class SettingsScreenTest {
|
|||||||
var removals = 0
|
var removals = 0
|
||||||
var reloads = 0
|
var reloads = 0
|
||||||
var choseImages = false
|
var choseImages = false
|
||||||
|
var exports = 0
|
||||||
|
var imports = 0
|
||||||
override fun reload() {
|
override fun reload() {
|
||||||
reloads += 1
|
reloads += 1
|
||||||
}
|
}
|
||||||
@@ -211,15 +281,41 @@ class SettingsScreenTest {
|
|||||||
override fun openCredentials() = Unit
|
override fun openCredentials() = Unit
|
||||||
override fun beginTransfer() {
|
override fun beginTransfer() {
|
||||||
state.value =
|
state.value =
|
||||||
state.value.copy(error = null, transfer = KeyTransferState(open = true))
|
state.value.copy(
|
||||||
|
error = null,
|
||||||
|
transfer = KeyTransferState(
|
||||||
|
open = true,
|
||||||
|
keys = listOf(
|
||||||
|
TransferKey(
|
||||||
|
"PUBLIC-FINGERPRINT",
|
||||||
|
"Fixture GPG key",
|
||||||
|
true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
override fun beginSetupTransfer() {
|
||||||
|
beginTransfer()
|
||||||
|
state.value =
|
||||||
|
state.value.copy(
|
||||||
|
transfer = state.value.transfer.copy(setup = true, keys = emptyList())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
override fun cameraPreview(): CameraPreview? = null
|
||||||
|
override fun exportKey(fingerprint: String, privateKey: Boolean, passphrase: String) {
|
||||||
|
exports +=
|
||||||
|
1
|
||||||
}
|
}
|
||||||
override fun exportKey(fingerprint: String, privateKey: Boolean, passphrase: String) = Unit
|
|
||||||
override fun chooseQrImages() {
|
override fun chooseQrImages() {
|
||||||
choseImages = true
|
choseImages = true
|
||||||
}
|
}
|
||||||
override fun addQrImages(uris: List<String>) = Unit
|
override fun addQrImages(uris: List<String>) = Unit
|
||||||
override fun addQrPayload(payload: String) = Unit
|
override fun addQrPayload(payload: String) = Unit
|
||||||
override fun importKey(passphrase: String, makeDefault: Boolean, overwrite: Boolean) = Unit
|
override fun importKey(passphrase: String, makeDefault: Boolean, overwrite: Boolean) {
|
||||||
|
imports +=
|
||||||
|
1
|
||||||
|
}
|
||||||
override fun closeTransfer() {
|
override fun closeTransfer() {
|
||||||
state.value = state.value.copy(transfer = KeyTransferState())
|
state.value = state.value.copy(transfer = KeyTransferState())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" tools:node="remove" />
|
||||||
|
<uses-feature android:name="android.hardware.camera.any" android:required="false" />
|
||||||
<application
|
<application
|
||||||
android:name=".IronStorageApplication"
|
android:name=".IronStorageApplication"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
|
|||||||
+25
-1
@@ -438,6 +438,7 @@ class NativeEntryViewerTest {
|
|||||||
keystore: MemoryKeystore
|
keystore: MemoryKeystore
|
||||||
) {
|
) {
|
||||||
var image = ByteArray(0)
|
var image = ByteArray(0)
|
||||||
|
var cameraReceiver: ((CameraFrame) -> Unit)? = null
|
||||||
val platform = object : SettingsPlatform {
|
val platform = object : SettingsPlatform {
|
||||||
override fun autofill() = ProviderStatus(true, false, false)
|
override fun autofill() = ProviderStatus(true, false, false)
|
||||||
override fun credentials() =
|
override fun credentials() =
|
||||||
@@ -446,6 +447,13 @@ class NativeEntryViewerTest {
|
|||||||
override fun version() = "native-settings-fixture"
|
override fun version() = "native-settings-fixture"
|
||||||
override fun openAutofill() = true
|
override fun openAutofill() = true
|
||||||
override fun openCredentials() = true
|
override fun openCredentials() = true
|
||||||
|
override fun cameraPreview(
|
||||||
|
frame: (CameraFrame) -> Unit,
|
||||||
|
failure: () -> Unit
|
||||||
|
): CameraPreview? {
|
||||||
|
cameraReceiver = frame
|
||||||
|
return null
|
||||||
|
}
|
||||||
override fun chooseQrImages() = true
|
override fun chooseQrImages() = true
|
||||||
override suspend fun readQrImage(uri: String) = image.copyOf()
|
override suspend fun readQrImage(uri: String) = image.copyOf()
|
||||||
}
|
}
|
||||||
@@ -533,6 +541,18 @@ class NativeEntryViewerTest {
|
|||||||
image = output.toByteArray()
|
image = output.toByteArray()
|
||||||
request { settings.closeTransfer() }
|
request { settings.closeTransfer() }
|
||||||
assertTrue(frame.modules.all { it.toInt() == 0 })
|
assertTrue(frame.modules.all { it.toInt() == 0 })
|
||||||
|
assertNull(request { settings.beginTransfer() }.error)
|
||||||
|
withContext(Dispatchers.Main.immediate) { settings.cameraPreview() }
|
||||||
|
val luminance = ByteArray(size * size) { index ->
|
||||||
|
if (pixels[index] == android.graphics.Color.BLACK) 0 else 255.toByte()
|
||||||
|
}
|
||||||
|
requireNotNull(
|
||||||
|
cameraReceiver
|
||||||
|
)(CameraFrame(luminance, size.toUInt(), size.toUInt(), size.toUInt(), 1u, 90u))
|
||||||
|
withTimeout(30000) { settings.state.first { it.transfer.ready != null } }
|
||||||
|
assertEquals(fingerprint, settings.state.value.transfer.ready!!.fingerprint)
|
||||||
|
assertTrue(luminance.all { it.toInt() == 0 })
|
||||||
|
request { settings.closeTransfer() }
|
||||||
val qrStart = android.os.SystemClock.elapsedRealtime()
|
val qrStart = android.os.SystemClock.elapsedRealtime()
|
||||||
assertNull(request { settings.addQrImages(listOf("content://public-fixture/qr")) }.error)
|
assertNull(request { settings.addQrImages(listOf("content://public-fixture/qr")) }.error)
|
||||||
val qrMs = android.os.SystemClock.elapsedRealtime() - qrStart
|
val qrMs = android.os.SystemClock.elapsedRealtime() - qrStart
|
||||||
@@ -559,10 +579,14 @@ class NativeEntryViewerTest {
|
|||||||
assertNotNull(request { settings.setDefaultKey(bob.fingerprint) }.error)
|
assertNotNull(request { settings.setDefaultKey(bob.fingerprint) }.error)
|
||||||
assertEquals(fingerprint, settings.state.value.page!!.defaultKeyFingerprint)
|
assertEquals(fingerprint, settings.state.value.page!!.defaultKeyFingerprint)
|
||||||
assertNull(request { settings.beginTransfer() }.error)
|
assertNull(request { settings.beginTransfer() }.error)
|
||||||
assertNull(request { settings.exportKey(fingerprint, false, "") }.error)
|
assertNull(request { settings.exportKey(fingerprint, true, passphrase) }.error)
|
||||||
|
assertTrue(settings.state.value.transfer.exportedKey!!.privateKey)
|
||||||
|
val privateFrames = settings.state.value.transfer.frames
|
||||||
|
assertTrue(privateFrames.isNotEmpty())
|
||||||
withContext(Dispatchers.Main.immediate) { authentication.presentation.clear() }
|
withContext(Dispatchers.Main.immediate) { authentication.presentation.clear() }
|
||||||
assertFalse(settings.state.value.transfer.open)
|
assertFalse(settings.state.value.transfer.open)
|
||||||
assertTrue(settings.state.value.transfer.frames.isEmpty())
|
assertTrue(settings.state.value.transfer.frames.isEmpty())
|
||||||
|
assertTrue(privateFrames.all { frame -> frame.modules.all { it.toInt() == 0 } })
|
||||||
assertNull(request { settings.setDefaultKey(fingerprint) }.error)
|
assertNull(request { settings.setDefaultKey(fingerprint) }.error)
|
||||||
assertFalse(authentication.state.value.unlocked)
|
assertFalse(authentication.state.value.unlocked)
|
||||||
assertEquals(fingerprint, settings.state.value.page!!.defaultKeyFingerprint)
|
assertEquals(fingerprint, settings.state.value.page!!.defaultKeyFingerprint)
|
||||||
|
|||||||
+115
-3
@@ -2,6 +2,7 @@ package de.rfc1437.ironstorage.core
|
|||||||
|
|
||||||
import de.rfc1437.ironstorage.bridge.NativeBridgeException
|
import de.rfc1437.ironstorage.bridge.NativeBridgeException
|
||||||
import de.rfc1437.ironstorage.bridge.generated.MobileAuthenticationFfiException
|
import de.rfc1437.ironstorage.bridge.generated.MobileAuthenticationFfiException
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileCameraFrame
|
||||||
import de.rfc1437.ironstorage.bridge.generated.MobileKeyTransfer
|
import de.rfc1437.ironstorage.bridge.generated.MobileKeyTransfer
|
||||||
import de.rfc1437.ironstorage.bridge.generated.MobileKeyTransferFfiException
|
import de.rfc1437.ironstorage.bridge.generated.MobileKeyTransferFfiException
|
||||||
import de.rfc1437.ironstorage.bridge.generated.MobileKeyTransferImport
|
import de.rfc1437.ironstorage.bridge.generated.MobileKeyTransferImport
|
||||||
@@ -10,7 +11,9 @@ import de.rfc1437.ironstorage.bridge.generated.MobileKeyTransferProgress
|
|||||||
import de.rfc1437.ironstorage.bridge.generated.MobilePrivateStorageFfiException
|
import de.rfc1437.ironstorage.bridge.generated.MobilePrivateStorageFfiException
|
||||||
import de.rfc1437.ironstorage.bridge.generated.MobileTotpOperation
|
import de.rfc1437.ironstorage.bridge.generated.MobileTotpOperation
|
||||||
import de.rfc1437.ironstorage.bridge.generated.mobileKeyTransfer
|
import de.rfc1437.ironstorage.bridge.generated.mobileKeyTransfer
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.mobileLocalKeyTransferImporter
|
||||||
import de.rfc1437.ironstorage.bridge.generated.mobileTotpOperation
|
import de.rfc1437.ironstorage.bridge.generated.mobileTotpOperation
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
@@ -31,10 +34,12 @@ class NativeSettingsRepository(
|
|||||||
private val mutable = MutableStateFlow(SettingsState())
|
private val mutable = MutableStateFlow(SettingsState())
|
||||||
override val state: StateFlow<SettingsState> = mutable
|
override val state: StateFlow<SettingsState> = mutable
|
||||||
private val operation = Mutex()
|
private val operation = Mutex()
|
||||||
|
private val cameraBusy = AtomicBoolean()
|
||||||
|
|
||||||
@Volatile private var epoch = 0L
|
@Volatile private var epoch = 0L
|
||||||
|
|
||||||
@Volatile private var discovery: MobileTotpOperation? = null
|
@Volatile private var discovery: MobileTotpOperation? = null
|
||||||
|
private var visibility: Job? = null
|
||||||
private var transfer: MobileKeyTransfer? = null
|
private var transfer: MobileKeyTransfer? = null
|
||||||
private var importer: MobileKeyTransferImport? = null
|
private var importer: MobileKeyTransferImport? = null
|
||||||
init {
|
init {
|
||||||
@@ -126,19 +131,27 @@ class NativeSettingsRepository(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override fun beginTransfer() = run { ticket ->
|
override fun beginTransfer() = begin(false)
|
||||||
|
override fun beginSetupTransfer() = begin(true)
|
||||||
|
private fun begin(setup: Boolean) = run { ticket ->
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
session.storage()
|
session.storage()
|
||||||
|
releaseTransfer()
|
||||||
|
if (setup) {
|
||||||
|
importer = mobileLocalKeyTransferImporter()
|
||||||
|
} else {
|
||||||
transfer = mobileKeyTransfer()
|
transfer = mobileKeyTransfer()
|
||||||
importer = requireNotNull(transfer).importer()
|
importer = requireNotNull(transfer).importer()
|
||||||
}
|
}
|
||||||
val keys = withContext(Dispatchers.IO) { requireNotNull(transfer).keys() }
|
}
|
||||||
|
val keys = withContext(Dispatchers.IO) { transfer?.keys().orEmpty() }
|
||||||
if (ticket ==
|
if (ticket ==
|
||||||
epoch
|
epoch
|
||||||
) {
|
) {
|
||||||
mutable.value = mutable.value.copy(
|
mutable.value = mutable.value.copy(
|
||||||
transfer = KeyTransferState(
|
transfer = KeyTransferState(
|
||||||
open = true,
|
open = true,
|
||||||
|
setup = setup,
|
||||||
keys = keys.map {
|
keys = keys.map {
|
||||||
TransferKey(
|
TransferKey(
|
||||||
it.fingerprint,
|
it.fingerprint,
|
||||||
@@ -152,6 +165,12 @@ class NativeSettingsRepository(
|
|||||||
}
|
}
|
||||||
override fun exportKey(fingerprint: String, privateKey: Boolean, passphrase: String) =
|
override fun exportKey(fingerprint: String, privateKey: Boolean, passphrase: String) =
|
||||||
run { ticket ->
|
run { ticket ->
|
||||||
|
visibility?.cancel()
|
||||||
|
mutable.value.transfer.frames.forEach { it.modules.fill(0) }
|
||||||
|
mutable.value =
|
||||||
|
mutable.value.copy(
|
||||||
|
transfer = mutable.value.transfer.copy(frames = emptyList(), exportedKey = null)
|
||||||
|
)
|
||||||
val result = withContext(Dispatchers.IO) {
|
val result = withContext(Dispatchers.IO) {
|
||||||
requireNotNull(transfer).export(
|
requireNotNull(transfer).export(
|
||||||
fingerprint,
|
fingerprint,
|
||||||
@@ -165,11 +184,28 @@ class NativeSettingsRepository(
|
|||||||
mutable.value.transfer.frames.forEach { it.modules.fill(0) }
|
mutable.value.transfer.frames.forEach { it.modules.fill(0) }
|
||||||
mutable.value = mutable.value.copy(
|
mutable.value = mutable.value.copy(
|
||||||
transfer = mutable.value.transfer.copy(
|
transfer = mutable.value.transfer.copy(
|
||||||
|
exportedKey = TransferKey(
|
||||||
|
result.key.fingerprint,
|
||||||
|
result.key.title,
|
||||||
|
result.key.kind == MobileKeyTransferKind.PRIVATE
|
||||||
|
),
|
||||||
frames = result.frames.map {
|
frames = result.frames.map {
|
||||||
TransferFrame(it.sequence, it.total, it.width, it.modules)
|
TransferFrame(it.sequence, it.total, it.width, it.modules)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
visibility = scope.launch {
|
||||||
|
while (ticket == epoch) {
|
||||||
|
kotlinx.coroutines.delay(250)
|
||||||
|
val visible = operation.withLock {
|
||||||
|
withContext(Dispatchers.IO) { transfer?.exportVisible() == true }
|
||||||
|
}
|
||||||
|
if (ticket == epoch && !visible) {
|
||||||
|
closeTransfer()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
result.frames.forEach { it.modules.fill(0) }
|
result.frames.forEach { it.modules.fill(0) }
|
||||||
}
|
}
|
||||||
@@ -177,9 +213,11 @@ class NativeSettingsRepository(
|
|||||||
private fun progress(ticket: Long, progress: MobileKeyTransferProgress) {
|
private fun progress(ticket: Long, progress: MobileKeyTransferProgress) {
|
||||||
if (ticket != epoch) return
|
if (ticket != epoch) return
|
||||||
mutable.value = mutable.value.copy(
|
mutable.value = mutable.value.copy(
|
||||||
|
error = null,
|
||||||
transfer = mutable.value.transfer.copy(
|
transfer = mutable.value.transfer.copy(
|
||||||
received = progress.received,
|
received = progress.received,
|
||||||
total = progress.total,
|
total = progress.total,
|
||||||
|
duplicate = progress.duplicate,
|
||||||
ready = progress.key?.let {
|
ready = progress.key?.let {
|
||||||
TransferKey(
|
TransferKey(
|
||||||
it.fingerprint,
|
it.fingerprint,
|
||||||
@@ -190,6 +228,65 @@ class NativeSettingsRepository(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
override fun cameraPreview(): CameraPreview? {
|
||||||
|
val ticket = epoch
|
||||||
|
return platform.cameraPreview({ frame ->
|
||||||
|
if (!cameraBusy.compareAndSet(false, true)) {
|
||||||
|
frame.pixels.fill(0)
|
||||||
|
} else {
|
||||||
|
scope.launch {
|
||||||
|
try {
|
||||||
|
operation.withLock {
|
||||||
|
if (ticket != epoch || !mutable.value.transfer.open ||
|
||||||
|
mutable.value.transfer.ready != null || mutable.value.busy
|
||||||
|
) {
|
||||||
|
return@withLock
|
||||||
|
}
|
||||||
|
val result = withContext(Dispatchers.IO) {
|
||||||
|
requireNotNull(importer).addCamera(
|
||||||
|
MobileCameraFrame(
|
||||||
|
frame.width,
|
||||||
|
frame.height,
|
||||||
|
frame.rowStride,
|
||||||
|
frame.pixelStride,
|
||||||
|
frame.pixels
|
||||||
|
),
|
||||||
|
frame.rotationDegrees
|
||||||
|
)
|
||||||
|
}
|
||||||
|
frame.pixels.fill(0)
|
||||||
|
if (result != null) progress(ticket, result)
|
||||||
|
}
|
||||||
|
} catch (error: MobileKeyTransferFfiException.Failed) {
|
||||||
|
if (ticket ==
|
||||||
|
epoch
|
||||||
|
) {
|
||||||
|
mutable.value = mutable.value.copy(error = error.rustMessage)
|
||||||
|
}
|
||||||
|
} catch (_: NativeBridgeException) {
|
||||||
|
if (ticket ==
|
||||||
|
epoch
|
||||||
|
) {
|
||||||
|
mutable.value =
|
||||||
|
mutable.value.copy(error = session.text(R.string.core_update_retry))
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
frame.pixels.fill(0)
|
||||||
|
cameraBusy.set(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
scope.launch {
|
||||||
|
if (ticket ==
|
||||||
|
epoch
|
||||||
|
) {
|
||||||
|
mutable.value =
|
||||||
|
mutable.value.copy(error = session.text(R.string.core_camera_unavailable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
override fun chooseQrImages() {
|
override fun chooseQrImages() {
|
||||||
if (!platform.chooseQrImages()) {
|
if (!platform.chooseQrImages()) {
|
||||||
mutable.value =
|
mutable.value =
|
||||||
@@ -246,6 +343,15 @@ class NativeSettingsRepository(
|
|||||||
progress(ticket, withContext(Dispatchers.IO) { requireNotNull(importer).addFrame(payload) })
|
progress(ticket, withContext(Dispatchers.IO) { requireNotNull(importer).addFrame(payload) })
|
||||||
}
|
}
|
||||||
override fun importKey(passphrase: String, makeDefault: Boolean, overwrite: Boolean) = run {
|
override fun importKey(passphrase: String, makeDefault: Boolean, overwrite: Boolean) = run {
|
||||||
|
if (mutable.value.transfer.setup) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
session.storage().androidOnboarding(session.backend()).use {
|
||||||
|
it.importScanned(requireNotNull(importer), passphrase.ifEmpty { null })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closeTransfer()
|
||||||
|
return@run
|
||||||
|
}
|
||||||
val result = withContext(Dispatchers.IO) {
|
val result = withContext(Dispatchers.IO) {
|
||||||
requireNotNull(importer).import(passphrase.ifEmpty { null }, makeDefault, overwrite)
|
requireNotNull(importer).import(passphrase.ifEmpty { null }, makeDefault, overwrite)
|
||||||
}
|
}
|
||||||
@@ -264,6 +370,8 @@ class NativeSettingsRepository(
|
|||||||
transfer = null
|
transfer = null
|
||||||
}
|
}
|
||||||
override fun closeTransfer() {
|
override fun closeTransfer() {
|
||||||
|
visibility?.cancel()
|
||||||
|
visibility = null
|
||||||
epoch += 1
|
epoch += 1
|
||||||
mutable.value.transfer.frames.forEach { it.modules.fill(0) }
|
mutable.value.transfer.frames.forEach { it.modules.fill(0) }
|
||||||
mutable.value = mutable.value.copy(transfer = KeyTransferState(), busy = false)
|
mutable.value = mutable.value.copy(transfer = KeyTransferState(), busy = false)
|
||||||
@@ -295,7 +403,11 @@ class NativeSettingsRepository(
|
|||||||
mutable.value.copy(error = error.title + "\n" + error.detail)
|
mutable.value.copy(error = error.title + "\n" + error.detail)
|
||||||
}
|
}
|
||||||
} catch (error: MobileKeyTransferFfiException.Failed) {
|
} catch (error: MobileKeyTransferFfiException.Failed) {
|
||||||
if (ticket == epoch) mutable.value = mutable.value.copy(error = error.message)
|
if (ticket ==
|
||||||
|
epoch
|
||||||
|
) {
|
||||||
|
mutable.value = mutable.value.copy(error = error.rustMessage)
|
||||||
|
}
|
||||||
} catch (_: MobilePrivateStorageFfiException) {
|
} catch (_: MobilePrivateStorageFfiException) {
|
||||||
if (ticket ==
|
if (ticket ==
|
||||||
epoch
|
epoch
|
||||||
|
|||||||
@@ -12,6 +12,20 @@ interface SettingsPlatform {
|
|||||||
fun openCredentials(): Boolean
|
fun openCredentials(): Boolean
|
||||||
fun chooseQrImages(): Boolean
|
fun chooseQrImages(): Boolean
|
||||||
suspend fun readQrImage(uri: String): ByteArray
|
suspend fun readQrImage(uri: String): ByteArray
|
||||||
|
fun cameraPreview(frame: (CameraFrame) -> Unit, failure: () -> Unit): CameraPreview?
|
||||||
|
}
|
||||||
|
data class CameraFrame(
|
||||||
|
val pixels: ByteArray,
|
||||||
|
val width: UInt,
|
||||||
|
val height: UInt,
|
||||||
|
val rowStride: UInt,
|
||||||
|
val pixelStride: UInt,
|
||||||
|
val rotationDegrees: UInt
|
||||||
|
) {
|
||||||
|
override fun toString() = "CameraFrame([REDACTED])"
|
||||||
|
}
|
||||||
|
interface CameraPreview : AutoCloseable {
|
||||||
|
val view: android.view.View
|
||||||
}
|
}
|
||||||
data class SettingsPage(
|
data class SettingsPage(
|
||||||
val repositoryTitle: String,
|
val repositoryTitle: String,
|
||||||
@@ -45,7 +59,10 @@ data class KeyTransferState(
|
|||||||
val frames: List<TransferFrame> = emptyList(),
|
val frames: List<TransferFrame> = emptyList(),
|
||||||
val received: UInt = 0u,
|
val received: UInt = 0u,
|
||||||
val total: UInt = 0u,
|
val total: UInt = 0u,
|
||||||
val ready: TransferKey? = null
|
val ready: TransferKey? = null,
|
||||||
|
val duplicate: Boolean = false,
|
||||||
|
val setup: Boolean = false,
|
||||||
|
val exportedKey: TransferKey? = null
|
||||||
) {
|
) {
|
||||||
override fun toString() = "KeyTransferState([REDACTED])"
|
override fun toString() = "KeyTransferState([REDACTED])"
|
||||||
}
|
}
|
||||||
@@ -69,6 +86,8 @@ interface SettingsRepository {
|
|||||||
fun openAutofill()
|
fun openAutofill()
|
||||||
fun openCredentials()
|
fun openCredentials()
|
||||||
fun beginTransfer()
|
fun beginTransfer()
|
||||||
|
fun beginSetupTransfer()
|
||||||
|
fun cameraPreview(): CameraPreview?
|
||||||
fun exportKey(fingerprint: String, privateKey: Boolean, passphrase: String)
|
fun exportKey(fingerprint: String, privateKey: Boolean, passphrase: String)
|
||||||
fun chooseQrImages()
|
fun chooseQrImages()
|
||||||
fun addQrImages(uris: List<String>)
|
fun addQrImages(uris: List<String>)
|
||||||
|
|||||||
@@ -38,4 +38,5 @@
|
|||||||
<string name="core_copied">Copied. The clipboard will be cleared automatically.</string>
|
<string name="core_copied">Copied. The clipboard will be cleared automatically.</string>
|
||||||
<string name="core_password_recovery">Unlock the device or recover the private store and refresh.</string>
|
<string name="core_password_recovery">Unlock the device or recover the private store and refresh.</string>
|
||||||
<string name="core_password_storage">Private storage is unavailable. Unlock the device and refresh.</string>
|
<string name="core_password_storage">Private storage is unavailable. Unlock the device and refresh.</string>
|
||||||
|
<string name="core_camera_unavailable">The camera is unavailable. Pause scanning and retry, or choose QR images.</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -176,7 +176,31 @@
|
|||||||
"org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0": "Apache-2.0",
|
"org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0": "Apache-2.0",
|
||||||
"org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0": "Apache-2.0",
|
"org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0": "Apache-2.0",
|
||||||
"org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0": "Apache-2.0",
|
"org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0": "Apache-2.0",
|
||||||
"org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0": "Apache-2.0"
|
"org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0": "Apache-2.0",
|
||||||
|
"androidx.camera.featurecombinationquery:featurecombinationquery:1.6.2": "Apache-2.0",
|
||||||
|
"androidx.camera.viewfinder:viewfinder-core:1.5.1": "Apache-2.0",
|
||||||
|
"androidx.camera:camera-camera2-pipe:1.6.2": "Apache-2.0",
|
||||||
|
"androidx.camera:camera-camera2:1.6.2": "Apache-2.0",
|
||||||
|
"androidx.camera:camera-core:1.6.2": "Apache-2.0 AND BSD-3-Clause",
|
||||||
|
"androidx.camera:camera-lifecycle:1.6.2": "Apache-2.0",
|
||||||
|
"androidx.camera:camera-video:1.6.2": "Apache-2.0",
|
||||||
|
"androidx.camera:camera-view:1.6.2": "Apache-2.0",
|
||||||
|
"androidx.concurrent:concurrent-futures-ktx:1.1.0": "Apache-2.0",
|
||||||
|
"androidx.core:core-backported-fixes:1.0.0": "Apache-2.0",
|
||||||
|
"androidx.exifinterface:exifinterface:1.4.2": "Apache-2.0",
|
||||||
|
"androidx.media3:media3-common:1.9.0": "Apache-2.0",
|
||||||
|
"androidx.media3:media3-container:1.9.0": "Apache-2.0",
|
||||||
|
"androidx.media3:media3-muxer:1.9.0": "Apache-2.0",
|
||||||
|
"androidx.tracing:tracing-ktx:2.0.0": "Apache-2.0",
|
||||||
|
"com.google.auto.value:auto-value-annotations:1.6.3": "Apache-2.0",
|
||||||
|
"com.google.dagger:dagger:2.59": "Apache-2.0",
|
||||||
|
"com.google.errorprone:error_prone_annotations:2.28.0": "Apache-2.0",
|
||||||
|
"com.google.guava:failureaccess:1.0.2": "Apache-2.0",
|
||||||
|
"com.google.guava:guava:33.3.1-android": "Apache-2.0",
|
||||||
|
"com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava": "Apache-2.0",
|
||||||
|
"com.google.j2objc:j2objc-annotations:3.0.0": "Apache-2.0",
|
||||||
|
"org.checkerframework:checker-qual:3.43.0": "MIT",
|
||||||
|
"org.jetbrains.kotlinx:atomicfu-jvm:0.28.0": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"rust_licenses": [
|
"rust_licenses": [
|
||||||
"(Apache-2.0 OR MIT) AND BSD-3-Clause",
|
"(Apache-2.0 OR MIT) AND BSD-3-Clause",
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import androidx.compose.material3.RadioButton
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
@@ -54,9 +55,17 @@ class SetupFormViewModel @Inject constructor() : ViewModel() {
|
|||||||
fun OnboardingScreen(
|
fun OnboardingScreen(
|
||||||
repository: OnboardingRepository,
|
repository: OnboardingRepository,
|
||||||
secrets: SetupFormViewModel,
|
secrets: SetupFormViewModel,
|
||||||
|
settings: de.rfc1437.ironstorage.core.SettingsRepository,
|
||||||
|
authentication: de.rfc1437.ironstorage.core.AuthenticationRepository,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
scroll: Boolean = true
|
scroll: Boolean = true
|
||||||
) {
|
) {
|
||||||
|
val transfer by settings.state.collectAsStateWithLifecycle()
|
||||||
|
DisposableEffect(transfer.transfer.open) {
|
||||||
|
val wasOpen = transfer.transfer.open
|
||||||
|
onDispose { if (wasOpen) repository.refresh() }
|
||||||
|
}
|
||||||
|
if (transfer.transfer.open) KeyTransferDialog(settings, authentication)
|
||||||
ProtectedInputSurface()
|
ProtectedInputSurface()
|
||||||
val state by repository.setup.collectAsStateWithLifecycle()
|
val state by repository.setup.collectAsStateWithLifecycle()
|
||||||
var step by rememberSaveable { mutableStateOf("choice") }
|
var step by rememberSaveable { mutableStateOf("choice") }
|
||||||
@@ -183,6 +192,9 @@ fun OnboardingScreen(
|
|||||||
}
|
}
|
||||||
"import" -> {
|
"import" -> {
|
||||||
Text(stringResource(R.string.setup_import_help))
|
Text(stringResource(R.string.setup_import_help))
|
||||||
|
TextButton(onClick = settings::beginSetupTransfer) {
|
||||||
|
Text(stringResource(R.string.qr_scan))
|
||||||
|
}
|
||||||
SecretField(
|
SecretField(
|
||||||
stringResource(R.string.setup_armor),
|
stringResource(R.string.setup_armor),
|
||||||
secrets.armor,
|
secrets.armor,
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package de.rfc1437.ironstorage.features
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.provider.Settings
|
||||||
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clipToBounds
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.compose.LifecycleEventEffect
|
||||||
|
import de.rfc1437.ironstorage.core.SettingsRepository
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun QrCameraPane(repository: SettingsRepository) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
fun allowed() = ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) ==
|
||||||
|
PackageManager.PERMISSION_GRANTED
|
||||||
|
var permitted by remember { mutableStateOf(allowed()) }
|
||||||
|
var scanning by remember { mutableStateOf(false) }
|
||||||
|
val permission =
|
||||||
|
rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) {
|
||||||
|
permitted = it
|
||||||
|
scanning = it
|
||||||
|
}
|
||||||
|
LifecycleEventEffect(Lifecycle.Event.ON_RESUME) { permitted = allowed() }
|
||||||
|
if (permitted && scanning) {
|
||||||
|
val camera = remember(repository) { repository.cameraPreview() }
|
||||||
|
DisposableEffect(camera) { onDispose { camera?.close() } }
|
||||||
|
if (camera == null) {
|
||||||
|
Text(stringResource(R.string.qr_camera_missing))
|
||||||
|
} else {
|
||||||
|
AndroidView(factory = {
|
||||||
|
camera.view
|
||||||
|
}, modifier = Modifier.fillMaxWidth().height(280.dp).clipToBounds())
|
||||||
|
}
|
||||||
|
TextButton(onClick = { scanning = false }) { Text(stringResource(R.string.qr_pause)) }
|
||||||
|
} else {
|
||||||
|
TextButton(onClick = {
|
||||||
|
if (permitted) {
|
||||||
|
scanning = true
|
||||||
|
} else {
|
||||||
|
permission.launch(Manifest.permission.CAMERA)
|
||||||
|
}
|
||||||
|
}) { Text(stringResource(if (permitted) R.string.qr_resume else R.string.qr_scan)) }
|
||||||
|
if (!permitted) {
|
||||||
|
Text(stringResource(R.string.qr_camera_denied))
|
||||||
|
TextButton(onClick = {
|
||||||
|
context.startActivity(
|
||||||
|
Intent(
|
||||||
|
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
|
||||||
|
"package:${context.packageName}".toUri()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}) { Text(stringResource(R.string.qr_camera_settings)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun QrDisplayWindow() {
|
||||||
|
val view = androidx.compose.ui.platform.LocalView.current
|
||||||
|
val window = (view.parent as? androidx.compose.ui.window.DialogWindowProvider)?.window
|
||||||
|
DisposableEffect(window, view) {
|
||||||
|
val brightness = window?.attributes?.screenBrightness
|
||||||
|
val keep = view.keepScreenOn
|
||||||
|
view.keepScreenOn = true
|
||||||
|
window?.let { it.attributes = it.attributes.apply { screenBrightness = 1f } }
|
||||||
|
onDispose {
|
||||||
|
view.keepScreenOn = keep
|
||||||
|
if (brightness !=
|
||||||
|
null
|
||||||
|
) {
|
||||||
|
window.attributes = window.attributes.apply { screenBrightness = brightness }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -169,6 +169,8 @@ fun SettingsScreen(
|
|||||||
OnboardingScreen(
|
OnboardingScreen(
|
||||||
onboarding,
|
onboarding,
|
||||||
setup,
|
setup,
|
||||||
|
repository,
|
||||||
|
authentication,
|
||||||
scroll = false
|
scroll = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -290,7 +292,7 @@ fun SettingsScreen(
|
|||||||
SettingsEditDialog(repository, authentication, action) { edit = null }
|
SettingsEditDialog(repository, authentication, action) { edit = null }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state.transfer.open) KeyTransferDialog(repository, authentication)
|
if (state.transfer.open && !showSetup) KeyTransferDialog(repository, authentication)
|
||||||
if (licenses) {
|
if (licenses) {
|
||||||
val resources = LocalResources.current
|
val resources = LocalResources.current
|
||||||
val loading = stringResource(R.string.settings_license_loading)
|
val loading = stringResource(R.string.settings_license_loading)
|
||||||
@@ -422,7 +424,7 @@ private fun SettingsEditDialog(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun KeyTransferDialog(
|
internal fun KeyTransferDialog(
|
||||||
repository: SettingsRepository,
|
repository: SettingsRepository,
|
||||||
authentication: AuthenticationRepository
|
authentication: AuthenticationRepository
|
||||||
) {
|
) {
|
||||||
@@ -436,6 +438,15 @@ private fun KeyTransferDialog(
|
|||||||
var frame by remember { mutableStateOf(0) }
|
var frame by remember { mutableStateOf(0) }
|
||||||
var passphrase by rememberProtectedInput(authentication.presentation)
|
var passphrase by rememberProtectedInput(authentication.presentation)
|
||||||
var payload by rememberProtectedInput(authentication.presentation)
|
var payload by rememberProtectedInput(authentication.presentation)
|
||||||
|
var exportConfirmed by remember(fingerprint, privateKey) { mutableStateOf(false) }
|
||||||
|
var importConfirmed by remember(state.transfer.ready) { mutableStateOf(false) }
|
||||||
|
var animate by remember { mutableStateOf(false) }
|
||||||
|
LaunchedEffect(animate, state.transfer.frames) {
|
||||||
|
while (animate && state.transfer.frames.size > 1) {
|
||||||
|
kotlinx.coroutines.delay(1200)
|
||||||
|
frame = (frame + 1) % state.transfer.frames.size
|
||||||
|
}
|
||||||
|
}
|
||||||
ProtectedWindow()
|
ProtectedWindow()
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
properties = DialogProperties(
|
properties = DialogProperties(
|
||||||
@@ -454,6 +465,7 @@ private fun KeyTransferDialog(
|
|||||||
ProtectedInputSurface(authentication.presentation)
|
ProtectedInputSurface(authentication.presentation)
|
||||||
state.error?.let { Text(it, color = MaterialTheme.colorScheme.error) }
|
state.error?.let { Text(it, color = MaterialTheme.colorScheme.error) }
|
||||||
if (state.busy) CircularProgressIndicator()
|
if (state.busy) CircularProgressIndicator()
|
||||||
|
if (!state.transfer.setup) {
|
||||||
state.transfer.keys.forEach { key ->
|
state.transfer.keys.forEach { key ->
|
||||||
Row(
|
Row(
|
||||||
Modifier.fillMaxWidth().selectable(
|
Modifier.fillMaxWidth().selectable(
|
||||||
@@ -486,13 +498,31 @@ private fun KeyTransferDialog(
|
|||||||
SecretField(stringResource(R.string.setup_passphrase), passphrase) {
|
SecretField(stringResource(R.string.setup_passphrase), passphrase) {
|
||||||
passphrase = it
|
passphrase = it
|
||||||
}
|
}
|
||||||
TextButton(enabled = !state.busy && fingerprint.isNotEmpty(), onClick = {
|
if (privateKey) {
|
||||||
|
SettingsToggle(
|
||||||
|
stringResource(R.string.qr_export_private_confirm),
|
||||||
|
exportConfirmed
|
||||||
|
) {
|
||||||
|
exportConfirmed =
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TextButton(
|
||||||
|
enabled =
|
||||||
|
!state.busy && fingerprint.isNotEmpty() && (!privateKey || exportConfirmed),
|
||||||
|
onClick = {
|
||||||
repository.exportKey(fingerprint, privateKey, passphrase)
|
repository.exportKey(fingerprint, privateKey, passphrase)
|
||||||
passphrase = ""
|
passphrase = ""
|
||||||
frame =
|
frame =
|
||||||
0
|
0
|
||||||
}) { Text(stringResource(R.string.settings_export_confirm)) }
|
}
|
||||||
|
) { Text(stringResource(R.string.settings_export_confirm)) }
|
||||||
state.transfer.frames.getOrNull(frame)?.let { qr ->
|
state.transfer.frames.getOrNull(frame)?.let { qr ->
|
||||||
|
state.transfer.exportedKey?.let { exported ->
|
||||||
|
Text(exported.title)
|
||||||
|
Text(exported.fingerprint)
|
||||||
|
}
|
||||||
|
QrDisplayWindow()
|
||||||
val description =
|
val description =
|
||||||
stringResource(
|
stringResource(
|
||||||
R.string.settings_qr_frame,
|
R.string.settings_qr_frame,
|
||||||
@@ -533,12 +563,28 @@ private fun KeyTransferDialog(
|
|||||||
TextButton(enabled = frame > 0, onClick = {
|
TextButton(enabled = frame > 0, onClick = {
|
||||||
frame -= 1
|
frame -= 1
|
||||||
}) { Text(stringResource(R.string.settings_previous)) }
|
}) { Text(stringResource(R.string.settings_previous)) }
|
||||||
TextButton(enabled = frame < state.transfer.frames.lastIndex, onClick = {
|
TextButton(
|
||||||
|
enabled = frame < state.transfer.frames.lastIndex,
|
||||||
|
onClick = {
|
||||||
frame +=
|
frame +=
|
||||||
1
|
1
|
||||||
}) { Text(stringResource(R.string.settings_next)) }
|
}
|
||||||
|
) { Text(stringResource(R.string.settings_next)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (state.transfer.frames.size > 1) {
|
||||||
|
SettingsToggle(stringResource(R.string.qr_animate), animate) {
|
||||||
|
animate = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state.transfer.setup) {
|
||||||
|
SecretField(stringResource(R.string.setup_passphrase), passphrase) {
|
||||||
|
passphrase =
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state.transfer.ready == null && !state.busy) QrCameraPane(repository)
|
||||||
TextButton(enabled = !state.busy, onClick = repository::chooseQrImages) {
|
TextButton(enabled = !state.busy, onClick = repository::chooseQrImages) {
|
||||||
Text(stringResource(R.string.settings_qr_images))
|
Text(stringResource(R.string.settings_qr_images))
|
||||||
}
|
}
|
||||||
@@ -564,10 +610,15 @@ private fun KeyTransferDialog(
|
|||||||
state.transfer.total.toInt()
|
state.transfer.total.toInt()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
if (state.transfer.duplicate) Text(stringResource(R.string.qr_duplicate))
|
||||||
state.transfer.ready?.let {
|
state.transfer.ready?.let {
|
||||||
Text(it.title)
|
Text(it.title)
|
||||||
Text(it.fingerprint)
|
Text(it.fingerprint)
|
||||||
SettingsToggle(stringResource(R.string.settings_make_default), makeDefault) {
|
if (!state.transfer.setup) {
|
||||||
|
SettingsToggle(
|
||||||
|
stringResource(R.string.settings_make_default),
|
||||||
|
makeDefault
|
||||||
|
) {
|
||||||
makeDefault =
|
makeDefault =
|
||||||
it
|
it
|
||||||
}
|
}
|
||||||
@@ -575,11 +626,34 @@ private fun KeyTransferDialog(
|
|||||||
overwrite =
|
overwrite =
|
||||||
it
|
it
|
||||||
}
|
}
|
||||||
TextButton(enabled = !state.busy, onClick = {
|
}
|
||||||
|
if (it.privateKey) {
|
||||||
|
SettingsToggle(
|
||||||
|
stringResource(R.string.qr_import_private_confirm),
|
||||||
|
importConfirmed
|
||||||
|
) {
|
||||||
|
importConfirmed =
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TextButton(
|
||||||
|
enabled = !state.busy && (!it.privateKey || importConfirmed),
|
||||||
|
onClick = {
|
||||||
repository.importKey(passphrase, makeDefault, overwrite)
|
repository.importKey(passphrase, makeDefault, overwrite)
|
||||||
passphrase =
|
passphrase =
|
||||||
""
|
""
|
||||||
}) { Text(stringResource(R.string.settings_import_confirm)) }
|
}
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
stringResource(
|
||||||
|
if (state.transfer.setup) {
|
||||||
|
R.string.qr_setup_import
|
||||||
|
} else {
|
||||||
|
R.string.settings_import_confirm
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -171,7 +171,13 @@ private fun ShellDestination(
|
|||||||
Modifier.fillMaxSize().verticalScroll(rememberScrollState()),
|
Modifier.fillMaxSize().verticalScroll(rememberScrollState()),
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
) {
|
) {
|
||||||
OnboardingScreen(viewModel.onboarding, setupForm, scroll = false)
|
OnboardingScreen(
|
||||||
|
viewModel.onboarding,
|
||||||
|
setupForm,
|
||||||
|
viewModel.settings,
|
||||||
|
viewModel.authentication,
|
||||||
|
scroll = false
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ready && route == ShellRoute.Passwords -> {
|
ready && route == ShellRoute.Passwords -> {
|
||||||
|
|||||||
@@ -224,4 +224,15 @@
|
|||||||
<item quantity="other">%1$d results</item>
|
<item quantity="other">%1$d results</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="settings_license_loading">Loading license…</string>
|
<string name="settings_license_loading">Loading license…</string>
|
||||||
|
<string name="qr_scan">Scan GPG QR codes</string>
|
||||||
|
<string name="qr_pause">Pause camera</string>
|
||||||
|
<string name="qr_resume">Resume camera</string>
|
||||||
|
<string name="qr_camera_denied">Camera access is required to scan. If permission was denied, allow it in app settings or choose QR images.</string>
|
||||||
|
<string name="qr_camera_settings">Open camera permission settings</string>
|
||||||
|
<string name="qr_camera_missing">The camera is unavailable. Choose QR images or paste an armored key.</string>
|
||||||
|
<string name="qr_duplicate">Duplicate frame; progress is unchanged.</string>
|
||||||
|
<string name="qr_import_private_confirm">I checked this fingerprint and authorize importing its private key material.</string>
|
||||||
|
<string name="qr_export_private_confirm">I checked this fingerprint and authorize displaying its private QR codes.</string>
|
||||||
|
<string name="qr_animate">Automatically advance frames</string>
|
||||||
|
<string name="qr_setup_import">Prepare the scanned key</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
[versions]
|
[versions]
|
||||||
|
camera = "1.6.2"
|
||||||
agp = "9.4.1"
|
agp = "9.4.1"
|
||||||
kotlin = "2.4.21"
|
kotlin = "2.4.21"
|
||||||
ksp = "2.3.12"
|
ksp = "2.3.12"
|
||||||
@@ -28,6 +29,9 @@ biometric = "1.1.0"
|
|||||||
fragment = "1.9.1"
|
fragment = "1.9.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "camera" }
|
||||||
|
camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "camera" }
|
||||||
|
camera-view = { module = "androidx.camera:camera-view", version.ref = "camera" }
|
||||||
benchmark-macro = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "benchmark" }
|
benchmark-macro = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "benchmark" }
|
||||||
rustls-verifier = { group = "rustls", name = "rustls-platform-verifier", version.ref = "rustlsVerifier" }
|
rustls-verifier = { group = "rustls", name = "rustls-platform-verifier", version.ref = "rustlsVerifier" }
|
||||||
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "compose" }
|
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "compose" }
|
||||||
|
|||||||
@@ -183,6 +183,11 @@
|
|||||||
<sha256 value="03fb659177c8618e47425925c11bc91f384703ea26c265be9b25cd79292b511c" origin="Generated by Gradle"/>
|
<sha256 value="03fb659177c8618e47425925c11bc91f384703ea26c265be9b25cd79292b511c" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.appcompat" name="appcompat" version="1.1.0">
|
||||||
|
<artifact name="appcompat-1.1.0.pom">
|
||||||
|
<sha256 value="340d617121f8ef8e02a6680c8f357aa3e542276d0c8a1cdcb6fd98984b2cb7b9" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.appcompat" name="appcompat" version="1.2.0">
|
<component group="androidx.appcompat" name="appcompat" version="1.2.0">
|
||||||
<artifact name="appcompat-1.2.0.aar">
|
<artifact name="appcompat-1.2.0.aar">
|
||||||
<sha256 value="3d2131a55a61a777322e2126e0018011efa6339e53b44153eb651b16020cca70" origin="Generated by Gradle"/>
|
<sha256 value="3d2131a55a61a777322e2126e0018011efa6339e53b44153eb651b16020cca70" origin="Generated by Gradle"/>
|
||||||
@@ -284,6 +289,70 @@
|
|||||||
<sha256 value="4999f205b2b38e31180ad58111e32d564190c2024fbfd58527e2da8bfb67ff65" origin="Generated by Gradle"/>
|
<sha256 value="4999f205b2b38e31180ad58111e32d564190c2024fbfd58527e2da8bfb67ff65" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.camera" name="camera-camera2" version="1.6.2">
|
||||||
|
<artifact name="camera-camera2-1.6.2.aar">
|
||||||
|
<sha256 value="5a55014ed96feda81a37799faf9f96150025a4434699d55caa1cdebf2ae07e20" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="camera-camera2-1.6.2.module">
|
||||||
|
<sha256 value="4694b995fbb4934e5e1e3cedabef426e799a510cfc179b659c4e9632f6b2fe75" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.camera" name="camera-camera2-pipe" version="1.6.2">
|
||||||
|
<artifact name="camera-camera2-pipe-1.6.2.aar">
|
||||||
|
<sha256 value="b357bd94fd4273ff88f453f7e712a22e100adc932324fc6b51fbe9ef9cf45515" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="camera-camera2-pipe-1.6.2.module">
|
||||||
|
<sha256 value="5470741b0a6fe88e560e7d929097e2ec60e7406aef09b48ab900b0befa102c0f" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.camera" name="camera-core" version="1.6.2">
|
||||||
|
<artifact name="camera-core-1.6.2.aar">
|
||||||
|
<sha256 value="ebd66f090414f4c12f23a55b5023aeee1b096da8a06c02a0b6fb3520c4ddadf6" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="camera-core-1.6.2.module">
|
||||||
|
<sha256 value="bee75b4ef561862030702a51f692057e034ae1f600f3091b2a5e5a89856ab410" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.camera" name="camera-lifecycle" version="1.6.2">
|
||||||
|
<artifact name="camera-lifecycle-1.6.2.aar">
|
||||||
|
<sha256 value="b7b701a3c6838bc7c4acd1372140e889fdf9681bf833ebfc638fdbe28ed5fa32" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="camera-lifecycle-1.6.2.module">
|
||||||
|
<sha256 value="bd7fd00cb9de0f2ce8c3400b52504cf7691590bb29a1550a71b58255e483ff47" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.camera" name="camera-video" version="1.6.2">
|
||||||
|
<artifact name="camera-video-1.6.2.aar">
|
||||||
|
<sha256 value="dee568da7d1ce009506a538b2916cce6f23473a835b0aeb4e8193483ff1174d0" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="camera-video-1.6.2.module">
|
||||||
|
<sha256 value="cf1e3fb9362af9c020f1126f8c56e7578f73a96b6f670136cc756a907182733c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.camera" name="camera-view" version="1.6.2">
|
||||||
|
<artifact name="camera-view-1.6.2.aar">
|
||||||
|
<sha256 value="2f258b88422b925717d2d1d1714d5572e48e2194336be227b35fc60000f6e166" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="camera-view-1.6.2.module">
|
||||||
|
<sha256 value="c84dc907bff8a46133631d1e93edcef78ac608c83abd07b51056f9cca4ae800c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.camera.featurecombinationquery" name="featurecombinationquery" version="1.6.2">
|
||||||
|
<artifact name="featurecombinationquery-1.6.2.aar">
|
||||||
|
<sha256 value="2321cfd29678e3128284d1622bb6b06e0fecd2c2e69140471ab00e8616e622c2" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="featurecombinationquery-1.6.2.module">
|
||||||
|
<sha256 value="4f6edda1492eaa928cfe7516d8efd097ed2f59ee4cedf1bec2d3345a3d6137fd" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.camera.viewfinder" name="viewfinder-core" version="1.5.1">
|
||||||
|
<artifact name="viewfinder-core-1.5.1.aar">
|
||||||
|
<sha256 value="31179ed5509e4d6d8d667efb91a039cac897b2bfd800d4c6e0b5bed376b4fa69" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="viewfinder-core-1.5.1.module">
|
||||||
|
<sha256 value="31407c1af39b26a59bebdcd61a39b7aa1a8b7f51c63aa61127d4f977a36d877c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.cardview" name="cardview" version="1.0.0">
|
<component group="androidx.cardview" name="cardview" version="1.0.0">
|
||||||
<artifact name="cardview-1.0.0.aar">
|
<artifact name="cardview-1.0.0.aar">
|
||||||
<sha256 value="1193c04c22a3d6b5946dae9f4e8c59d6adde6a71b6bd5d87fb99d82dda1afec7" origin="Generated by Gradle"/>
|
<sha256 value="1193c04c22a3d6b5946dae9f4e8c59d6adde6a71b6bd5d87fb99d82dda1afec7" origin="Generated by Gradle"/>
|
||||||
@@ -848,6 +917,14 @@
|
|||||||
<sha256 value="afd7094d3a07422be2e991bc87048542ae9724a5c42bd54b5cae3029c7970a1d" origin="Generated by Gradle"/>
|
<sha256 value="afd7094d3a07422be2e991bc87048542ae9724a5c42bd54b5cae3029c7970a1d" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.concurrent" name="concurrent-futures-ktx" version="1.1.0">
|
||||||
|
<artifact name="concurrent-futures-ktx-1.1.0.jar">
|
||||||
|
<sha256 value="1968bf52039e38636aa6f114cd17d7256919d1e8997417716fef9d1da1f24d85" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="concurrent-futures-ktx-1.1.0.module">
|
||||||
|
<sha256 value="69b79724566d49140846700690b8d2165231c577e93e66726a443e8f976bbe19" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.concurrent" name="concurrent-futures-ktx" version="1.2.0">
|
<component group="androidx.concurrent" name="concurrent-futures-ktx" version="1.2.0">
|
||||||
<artifact name="concurrent-futures-ktx-1.2.0.jar">
|
<artifact name="concurrent-futures-ktx-1.2.0.jar">
|
||||||
<sha256 value="e1f3e17bb4358ccd6c77ca45f70635c9aba237261f19eaa4f64a0218c00e2a3e" origin="Generated by Gradle"/>
|
<sha256 value="e1f3e17bb4358ccd6c77ca45f70635c9aba237261f19eaa4f64a0218c00e2a3e" origin="Generated by Gradle"/>
|
||||||
@@ -903,6 +980,11 @@
|
|||||||
<sha256 value="afb5ea494dd083ed404cd51f580d218e37362f8ae326e893bee521290ed34920" origin="Generated by Gradle"/>
|
<sha256 value="afb5ea494dd083ed404cd51f580d218e37362f8ae326e893bee521290ed34920" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.core" name="core" version="1.7.0">
|
||||||
|
<artifact name="core-1.7.0.module">
|
||||||
|
<sha256 value="988f820899d5a4982e5c878ca1cd417970ace332ea2ff72f5be19b233fa0e788" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.core" name="core" version="1.8.0">
|
<component group="androidx.core" name="core" version="1.8.0">
|
||||||
<artifact name="core-1.8.0.module">
|
<artifact name="core-1.8.0.module">
|
||||||
<sha256 value="505f1838869611519d65ec7feb650e88856e3682e37e42a2a24b73e655a98d74" origin="Generated by Gradle"/>
|
<sha256 value="505f1838869611519d65ec7feb650e88856e3682e37e42a2a24b73e655a98d74" origin="Generated by Gradle"/>
|
||||||
@@ -916,6 +998,14 @@
|
|||||||
<sha256 value="8674ade1d12962469dd2d1e6edc03b465f20d180b0840a129bc40b351e8651d1" origin="Generated by Gradle"/>
|
<sha256 value="8674ade1d12962469dd2d1e6edc03b465f20d180b0840a129bc40b351e8651d1" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.core" name="core-backported-fixes" version="1.0.0">
|
||||||
|
<artifact name="core-backported-fixes-1.0.0.aar">
|
||||||
|
<sha256 value="874722634db5f60745ab2f64d734dd81d3ee4eb71f175263e6565dabea54713d" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="core-backported-fixes-1.0.0.module">
|
||||||
|
<sha256 value="05aef3e2e15168190894999d4b14907c84d066837964ec900f7a2f0e4d9354ac" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.core" name="core-ktx" version="1.1.0">
|
<component group="androidx.core" name="core-ktx" version="1.1.0">
|
||||||
<artifact name="core-ktx-1.1.0.pom">
|
<artifact name="core-ktx-1.1.0.pom">
|
||||||
<sha256 value="729d11bad16d87c6212dc9ab80e9c770d333115062136e0732164a6b1696e11c" origin="Generated by Gradle"/>
|
<sha256 value="729d11bad16d87c6212dc9ab80e9c770d333115062136e0732164a6b1696e11c" origin="Generated by Gradle"/>
|
||||||
@@ -1042,6 +1132,14 @@
|
|||||||
<sha256 value="92be16cccb757f807bddd92f1fca95a038a810ccca051c4149c11682478954b8" origin="Generated by Gradle"/>
|
<sha256 value="92be16cccb757f807bddd92f1fca95a038a810ccca051c4149c11682478954b8" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.exifinterface" name="exifinterface" version="1.4.2">
|
||||||
|
<artifact name="exifinterface-1.4.2.aar">
|
||||||
|
<sha256 value="6bb2b68682a2023c55f35f941444ffea0157947b061e4fd7606ba935e2e77425" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="exifinterface-1.4.2.module">
|
||||||
|
<sha256 value="6365165eb5aacc700a34b1650a2910ea01ebd819821b89af7689fa41274fb00b" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.fragment" name="fragment" version="1.2.5">
|
<component group="androidx.fragment" name="fragment" version="1.2.5">
|
||||||
<artifact name="fragment-1.2.5.pom">
|
<artifact name="fragment-1.2.5.pom">
|
||||||
<sha256 value="df0aca46b62bb47cc662cbcee63372db6d2a2859478ee38b594fba3433fe30a5" origin="Generated by Gradle"/>
|
<sha256 value="df0aca46b62bb47cc662cbcee63372db6d2a2859478ee38b594fba3433fe30a5" origin="Generated by Gradle"/>
|
||||||
@@ -1100,6 +1198,11 @@
|
|||||||
<sha256 value="2baaf7f17551765524bd1e4d2f954a2a0178a112039cf549ba8b7d4b41e66931" origin="Generated by Gradle"/>
|
<sha256 value="2baaf7f17551765524bd1e4d2f954a2a0178a112039cf549ba8b7d4b41e66931" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-common" version="2.1.0">
|
||||||
|
<artifact name="lifecycle-common-2.1.0.pom">
|
||||||
|
<sha256 value="692c2a60437a95220c8fbb6e8943196f255f535d1a7c58714e6c46530782f276" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-common" version="2.10.0">
|
<component group="androidx.lifecycle" name="lifecycle-common" version="2.10.0">
|
||||||
<artifact name="lifecycle-common-2.10.0.module">
|
<artifact name="lifecycle-common-2.10.0.module">
|
||||||
<sha256 value="5d1247b1edfbdc9ddedcbe525c9d2629567b1c538cb7a9c620cd044a124b5c73" origin="Generated by Gradle"/>
|
<sha256 value="5d1247b1edfbdc9ddedcbe525c9d2629567b1c538cb7a9c620cd044a124b5c73" origin="Generated by Gradle"/>
|
||||||
@@ -1170,6 +1273,11 @@
|
|||||||
<sha256 value="1d1837f3942b33ea30aa2301fdcea2639408a0fd6fd4368c22478fa8153aebbf" origin="Generated by Gradle"/>
|
<sha256 value="1d1837f3942b33ea30aa2301fdcea2639408a0fd6fd4368c22478fa8153aebbf" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-livedata" version="2.1.0">
|
||||||
|
<artifact name="lifecycle-livedata-2.1.0.pom">
|
||||||
|
<sha256 value="1e4c580c995e41cd18455cfb87e3e43955be9db9ec63a8fb3c7259f01b7c4e3c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-livedata" version="2.10.0">
|
<component group="androidx.lifecycle" name="lifecycle-livedata" version="2.10.0">
|
||||||
<artifact name="lifecycle-livedata-2.10.0.aar">
|
<artifact name="lifecycle-livedata-2.10.0.aar">
|
||||||
<sha256 value="3e8c009fc88da1c52e4ed05a81269d5ac9bd405046f300307f5e3a17e201a6df" origin="Generated by Gradle"/>
|
<sha256 value="3e8c009fc88da1c52e4ed05a81269d5ac9bd405046f300307f5e3a17e201a6df" origin="Generated by Gradle"/>
|
||||||
@@ -1186,6 +1294,11 @@
|
|||||||
<sha256 value="d990bc920ae43729d702d80077328e8a59781ea5a35b24c02bc47d326ae73d7d" origin="Generated by Gradle"/>
|
<sha256 value="d990bc920ae43729d702d80077328e8a59781ea5a35b24c02bc47d326ae73d7d" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-livedata" version="2.3.1">
|
||||||
|
<artifact name="lifecycle-livedata-2.3.1.module">
|
||||||
|
<sha256 value="93494e78d5049dff897fde50f477e7b965e9a3de4a1ed453b5f0cbc409eb4e4c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-livedata" version="2.6.1">
|
<component group="androidx.lifecycle" name="lifecycle-livedata" version="2.6.1">
|
||||||
<artifact name="lifecycle-livedata-2.6.1.aar">
|
<artifact name="lifecycle-livedata-2.6.1.aar">
|
||||||
<sha256 value="67359f609dfc2bf65da1270b23033f856064ec279f058e0a70c715f7c9003031" origin="Generated by Gradle"/>
|
<sha256 value="67359f609dfc2bf65da1270b23033f856064ec279f058e0a70c715f7c9003031" origin="Generated by Gradle"/>
|
||||||
@@ -1194,6 +1307,11 @@
|
|||||||
<sha256 value="e2659e87e890b52b66f300471828b387a205e5387a392713190166f399ecf641" origin="Generated by Gradle"/>
|
<sha256 value="e2659e87e890b52b66f300471828b387a205e5387a392713190166f399ecf641" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.1.0">
|
||||||
|
<artifact name="lifecycle-livedata-core-2.1.0.pom">
|
||||||
|
<sha256 value="6839d2e68c8fee4cc3bbf04e6b291a6ae842403fcd5f8d944c27814d296deff3" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.10.0">
|
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.10.0">
|
||||||
<artifact name="lifecycle-livedata-core-2.10.0.aar">
|
<artifact name="lifecycle-livedata-core-2.10.0.aar">
|
||||||
<sha256 value="12dd61a9843ccebb4547d3ebe2f6d030ca8f6988d22f8fad19c0af93b4a97e95" origin="Generated by Gradle"/>
|
<sha256 value="12dd61a9843ccebb4547d3ebe2f6d030ca8f6988d22f8fad19c0af93b4a97e95" origin="Generated by Gradle"/>
|
||||||
@@ -1215,6 +1333,11 @@
|
|||||||
<sha256 value="aa51621be3817d1f5d21336b0c0525fe96ae899cec656c13d8ea18a51ea32c2f" origin="Generated by Gradle"/>
|
<sha256 value="aa51621be3817d1f5d21336b0c0525fe96ae899cec656c13d8ea18a51ea32c2f" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.3.1">
|
||||||
|
<artifact name="lifecycle-livedata-core-2.3.1.module">
|
||||||
|
<sha256 value="b1e095d550d39a7d6c815761d6dbe3fd64eb31a39dc28146e78bbf2c01ba8f41" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.6.1">
|
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.6.1">
|
||||||
<artifact name="lifecycle-livedata-core-2.6.1.aar">
|
<artifact name="lifecycle-livedata-core-2.6.1.aar">
|
||||||
<sha256 value="2256780a3cff4a1e57fbb3d442557c17dc363ab8af105bcaf5261d8e2d5db949" origin="Generated by Gradle"/>
|
<sha256 value="2256780a3cff4a1e57fbb3d442557c17dc363ab8af105bcaf5261d8e2d5db949" origin="Generated by Gradle"/>
|
||||||
@@ -1563,6 +1686,30 @@
|
|||||||
<sha256 value="c978d550808b47434aa49a63164110a50b55b0bcc6160a93a2e37d5110df8c5e" origin="Generated by Gradle"/>
|
<sha256 value="c978d550808b47434aa49a63164110a50b55b0bcc6160a93a2e37d5110df8c5e" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.media3" name="media3-common" version="1.9.0">
|
||||||
|
<artifact name="media3-common-1.9.0.aar">
|
||||||
|
<sha256 value="714114bf8a56fe44f0f78b499ae7ea3bed52391313794c8abdc1b687700d42aa" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="media3-common-1.9.0.module">
|
||||||
|
<sha256 value="02d42f8fd7cc53c385256f417df73a5cf30e8b7c5635ca5786148518ce711b75" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.media3" name="media3-container" version="1.9.0">
|
||||||
|
<artifact name="media3-container-1.9.0.aar">
|
||||||
|
<sha256 value="f73cea4fe8a2bf9eb6462bfb7a547d1aaf55395d0007eed6fadb129b56927c0d" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="media3-container-1.9.0.module">
|
||||||
|
<sha256 value="5a5f4d796aa34a3480ea75df73892d68eba7cd4bc239c116eee3816ce973d469" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.media3" name="media3-muxer" version="1.9.0">
|
||||||
|
<artifact name="media3-muxer-1.9.0.aar">
|
||||||
|
<sha256 value="452b182d84cfe20d1154d999107b9aac7c218ad8ee208d35d067916a92a02031" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="media3-muxer-1.9.0.module">
|
||||||
|
<sha256 value="e22678eed7457db37ceb4f14d96c761fa5055a114b4750892cf42b820a791428" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.navigation3" name="navigation3-runtime" version="1.2.0">
|
<component group="androidx.navigation3" name="navigation3-runtime" version="1.2.0">
|
||||||
<artifact name="navigation3-runtime-1.2.0.module">
|
<artifact name="navigation3-runtime-1.2.0.module">
|
||||||
<sha256 value="ff14442bf489768bbd2126536921a4d007bdf2d117b2c0451be67cd58eb66a21" origin="Generated by Gradle"/>
|
<sha256 value="ff14442bf489768bbd2126536921a4d007bdf2d117b2c0451be67cd58eb66a21" origin="Generated by Gradle"/>
|
||||||
@@ -1989,6 +2136,19 @@
|
|||||||
<sha256 value="6ec8aa998df9b964424c7ab215738237a9b2cc4301da135bb9b8cdc62325fb3e" origin="Generated by Gradle"/>
|
<sha256 value="6ec8aa998df9b964424c7ab215738237a9b2cc4301da135bb9b8cdc62325fb3e" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.tracing" name="tracing-ktx" version="1.2.0">
|
||||||
|
<artifact name="tracing-ktx-1.2.0.module">
|
||||||
|
<sha256 value="39288b23c71a4391132aec9951f5e27f41727a2cdff69c6e4b4ece49f63e540c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.tracing" name="tracing-ktx" version="2.0.0">
|
||||||
|
<artifact name="tracing-ktx-2.0.0.aar">
|
||||||
|
<sha256 value="7e7cf1386841b11310138723eb9f36b5eaf6c8caec896b16f99e579d220d6a0c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="tracing-ktx-2.0.0.module">
|
||||||
|
<sha256 value="f30609942614488befb6edaa36aa4d3b4fb1c1b7b79780630d3ca3a02b08c0a5" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.tracing" name="tracing-perfetto" version="1.0.1">
|
<component group="androidx.tracing" name="tracing-perfetto" version="1.0.1">
|
||||||
<artifact name="tracing-perfetto-1.0.1.aar">
|
<artifact name="tracing-perfetto-1.0.1.aar">
|
||||||
<sha256 value="5387298b5bdd8f7d98315fe8720a757056ba0b9b5d9544d2e3fabc26b9ac55a6" origin="Generated by Gradle"/>
|
<sha256 value="5387298b5bdd8f7d98315fe8720a757056ba0b9b5d9544d2e3fabc26b9ac55a6" origin="Generated by Gradle"/>
|
||||||
@@ -2551,6 +2711,11 @@
|
|||||||
<sha256 value="05f740c6648165db00cf618dd56c200c4725e358e6d54f5853e0bec15734ea0a" origin="Generated by Gradle"/>
|
<sha256 value="05f740c6648165db00cf618dd56c200c4725e358e6d54f5853e0bec15734ea0a" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="com.google.auto" name="auto-parent" version="7">
|
||||||
|
<artifact name="auto-parent-7.pom">
|
||||||
|
<sha256 value="a46426fccb5d32705ad9cbbc996f786bd048cc8cbdd21db046500169f15a4356" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="com.google.auto.value" name="auto-value-annotations" version="1.6.2">
|
<component group="com.google.auto.value" name="auto-value-annotations" version="1.6.2">
|
||||||
<artifact name="auto-value-annotations-1.6.2.jar">
|
<artifact name="auto-value-annotations-1.6.2.jar">
|
||||||
<sha256 value="b48b04ddba40e8ac33bf036f06fc43995fc5084bd94bdaace807ce27d3bea3fb" origin="Generated by Gradle"/>
|
<sha256 value="b48b04ddba40e8ac33bf036f06fc43995fc5084bd94bdaace807ce27d3bea3fb" origin="Generated by Gradle"/>
|
||||||
@@ -2559,11 +2724,24 @@
|
|||||||
<sha256 value="1c76cd462fc96e7aa96dc70ce82f0d54063d6df16db35c9c7d9cc0d1a99d3fff" origin="Generated by Gradle"/>
|
<sha256 value="1c76cd462fc96e7aa96dc70ce82f0d54063d6df16db35c9c7d9cc0d1a99d3fff" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="com.google.auto.value" name="auto-value-annotations" version="1.6.3">
|
||||||
|
<artifact name="auto-value-annotations-1.6.3.jar">
|
||||||
|
<sha256 value="0e951fee8c31f60270bc46553a8586001b7b93dbb12aec06373aa99a150392c0" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="auto-value-annotations-1.6.3.pom">
|
||||||
|
<sha256 value="e1fc780f7ee025e662b3da72723dbe2ac8dac0a2f8920f265315c4e1be3d765c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="com.google.auto.value" name="auto-value-parent" version="1.6.2">
|
<component group="com.google.auto.value" name="auto-value-parent" version="1.6.2">
|
||||||
<artifact name="auto-value-parent-1.6.2.pom">
|
<artifact name="auto-value-parent-1.6.2.pom">
|
||||||
<sha256 value="27b640c82179f5cff62009c0b72033d9bc60f60e9902a66802274b7fe37fc81c" origin="Generated by Gradle"/>
|
<sha256 value="27b640c82179f5cff62009c0b72033d9bc60f60e9902a66802274b7fe37fc81c" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="com.google.auto.value" name="auto-value-parent" version="1.6.3">
|
||||||
|
<artifact name="auto-value-parent-1.6.3.pom">
|
||||||
|
<sha256 value="e59df5732b4cb34d5727181446f9ded9ce4425131a0a1062519eea196de4d8a1" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="com.google.code.findbugs" name="jsr305" version="3.0.2">
|
<component group="com.google.code.findbugs" name="jsr305" version="3.0.2">
|
||||||
<artifact name="jsr305-3.0.2.jar">
|
<artifact name="jsr305-3.0.2.jar">
|
||||||
<sha256 value="766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7" origin="Generated by Gradle"/>
|
<sha256 value="766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7" origin="Generated by Gradle"/>
|
||||||
@@ -2601,6 +2779,14 @@
|
|||||||
<sha256 value="265ba959a8e13c3a06133f04b539169c1018daffd4d33f53c453ab4cb386f570" origin="Generated by Gradle"/>
|
<sha256 value="265ba959a8e13c3a06133f04b539169c1018daffd4d33f53c453ab4cb386f570" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="com.google.dagger" name="dagger" version="2.59">
|
||||||
|
<artifact name="dagger-2.59.jar">
|
||||||
|
<sha256 value="94d5b23812cc12fa903c9ac4a42978e7e7b2622e6b51c17f8b12037ceece43cd" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="dagger-2.59.pom">
|
||||||
|
<sha256 value="0e47846618c7a1b7a8124fd20623a667643d73cbe0a561bb87056151aa967538" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="com.google.dagger" name="dagger" version="2.60.1">
|
<component group="com.google.dagger" name="dagger" version="2.60.1">
|
||||||
<artifact name="dagger-2.60.1.jar">
|
<artifact name="dagger-2.60.1.jar">
|
||||||
<sha256 value="b012d0df527b51bfcd8953d5fcb4d022a45ebe66010d6f181ede68d1572b5cb2" origin="Generated by Gradle"/>
|
<sha256 value="b012d0df527b51bfcd8953d5fcb4d022a45ebe66010d6f181ede68d1572b5cb2" origin="Generated by Gradle"/>
|
||||||
@@ -2716,6 +2902,9 @@
|
|||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
<component group="com.google.errorprone" name="error_prone_annotations" version="2.18.0">
|
<component group="com.google.errorprone" name="error_prone_annotations" version="2.18.0">
|
||||||
|
<artifact name="error_prone_annotations-2.18.0.jar">
|
||||||
|
<sha256 value="9e6814cb71816988a4fd1b07a993a8f21bb7058d522c162b1de849e19bea54ae" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
<artifact name="error_prone_annotations-2.18.0.pom">
|
<artifact name="error_prone_annotations-2.18.0.pom">
|
||||||
<sha256 value="920135797dcca5917b5a5c017642a58d340a4cd1bcd12f56f892a5663bd7bddc" origin="Generated by Gradle"/>
|
<sha256 value="920135797dcca5917b5a5c017642a58d340a4cd1bcd12f56f892a5663bd7bddc" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
@@ -2725,6 +2914,14 @@
|
|||||||
<sha256 value="4ca5a35d61235e16549ac346d1e34551cdf0fe27e84aa57e03cbeb255ea4e5da" origin="Generated by Gradle"/>
|
<sha256 value="4ca5a35d61235e16549ac346d1e34551cdf0fe27e84aa57e03cbeb255ea4e5da" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="com.google.errorprone" name="error_prone_annotations" version="2.28.0">
|
||||||
|
<artifact name="error_prone_annotations-2.28.0.jar">
|
||||||
|
<sha256 value="f3fc8a3a0a4020706a373b00e7f57c2512dd26d1f83d28c7d38768f8682b231e" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="error_prone_annotations-2.28.0.pom">
|
||||||
|
<sha256 value="0ce909f13a568148476e5ee200f380f98c75ba08971aaf15db295eb77598ef3a" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="com.google.errorprone" name="error_prone_annotations" version="2.3.1">
|
<component group="com.google.errorprone" name="error_prone_annotations" version="2.3.1">
|
||||||
<artifact name="error_prone_annotations-2.3.1.pom">
|
<artifact name="error_prone_annotations-2.3.1.pom">
|
||||||
<sha256 value="3edce6b711ba368efe16b9b7aacb0214fbd648414cb9b965953a2e7ed89a819a" origin="Generated by Gradle"/>
|
<sha256 value="3edce6b711ba368efe16b9b7aacb0214fbd648414cb9b965953a2e7ed89a819a" origin="Generated by Gradle"/>
|
||||||
@@ -2764,6 +2961,11 @@
|
|||||||
<sha256 value="fa81829d049559df6927f9c9a6fd6bbd09f8b50e6d4736ae72c8300b6c3d7654" origin="Generated by Gradle"/>
|
<sha256 value="fa81829d049559df6927f9c9a6fd6bbd09f8b50e6d4736ae72c8300b6c3d7654" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="com.google.errorprone" name="error_prone_parent" version="2.28.0">
|
||||||
|
<artifact name="error_prone_parent-2.28.0.pom">
|
||||||
|
<sha256 value="accefdbb5416cef5fcd2ddc37db4f1fcb34a2193cc1a55dfe5970a131b3e7683" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="com.google.errorprone" name="error_prone_parent" version="2.3.1">
|
<component group="com.google.errorprone" name="error_prone_parent" version="2.3.1">
|
||||||
<artifact name="error_prone_parent-2.3.1.pom">
|
<artifact name="error_prone_parent-2.3.1.pom">
|
||||||
<sha256 value="767525d9a81129cd081968382980336327be4162b1e2251a182911daa733c123" origin="Generated by Gradle"/>
|
<sha256 value="767525d9a81129cd081968382980336327be4162b1e2251a182911daa733c123" origin="Generated by Gradle"/>
|
||||||
@@ -2837,6 +3039,25 @@
|
|||||||
<sha256 value="13d4e2998aac652fc6d7b9eaf3e495fa2952bf98ef68a2c49aa5eaa0bbe731a9" origin="Generated by Gradle"/>
|
<sha256 value="13d4e2998aac652fc6d7b9eaf3e495fa2952bf98ef68a2c49aa5eaa0bbe731a9" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="com.google.guava" name="guava" version="32.0.1-android">
|
||||||
|
<artifact name="guava-32.0.1-android.jar">
|
||||||
|
<sha256 value="12429ff9ac33b7afd8b1a5071179757cf4d3c47f0f4099bc0384e644ecbf82dd" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="guava-32.0.1-android.pom">
|
||||||
|
<sha256 value="cf26ce63461fb585cad25dc6932765883122643c3beec5e3269f667c73295ac4" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="com.google.guava" name="guava" version="33.3.1-android">
|
||||||
|
<artifact name="guava-33.3.1-android.jar">
|
||||||
|
<sha256 value="2c3e41d1b380f2044d257947a3aa82dabf3ae4b978622745254aa18b6cf89ab0" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="guava-33.3.1-android.module">
|
||||||
|
<sha256 value="6971614ddeee003e54d2b69c6b0c94ce8a5b5eba980d16455c81df9089a7acb7" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="guava-33.3.1-jre.jar">
|
||||||
|
<sha256 value="4bf0e2c5af8e4525c96e8fde17a4f7307f97f8478f11c4c8e35a0e3298ae4e90" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="com.google.guava" name="guava" version="33.4.0-jre">
|
<component group="com.google.guava" name="guava" version="33.4.0-jre">
|
||||||
<artifact name="guava-33.4.0-jre.jar">
|
<artifact name="guava-33.4.0-jre.jar">
|
||||||
<sha256 value="b918c98a7e44dbe94ebd9fe3e40cddaadb5a93e6a78eb6008b42df237241e538" origin="Generated by Gradle"/>
|
<sha256 value="b918c98a7e44dbe94ebd9fe3e40cddaadb5a93e6a78eb6008b42df237241e538" origin="Generated by Gradle"/>
|
||||||
@@ -2863,6 +3084,16 @@
|
|||||||
<sha256 value="30a51d34b075c9b4eb6a2da3fba6c1f5047b45225a3a03aebcefc0b7880e5735" origin="Generated by Gradle"/>
|
<sha256 value="30a51d34b075c9b4eb6a2da3fba6c1f5047b45225a3a03aebcefc0b7880e5735" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="com.google.guava" name="guava-parent" version="32.0.1-android">
|
||||||
|
<artifact name="guava-parent-32.0.1-android.pom">
|
||||||
|
<sha256 value="cddb3a941d71be5e871f39a239ba3bb8883c88c7763d8a3d2d342b09a1d5da30" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="com.google.guava" name="guava-parent" version="33.3.1-android">
|
||||||
|
<artifact name="guava-parent-33.3.1-android.pom">
|
||||||
|
<sha256 value="6e11986ea7250b51f847157e2dc937f32a306804dfce0007a5e81ddb9b95c579" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="com.google.guava" name="guava-parent" version="33.4.0-android">
|
<component group="com.google.guava" name="guava-parent" version="33.4.0-android">
|
||||||
<artifact name="guava-parent-33.4.0-android.pom">
|
<artifact name="guava-parent-33.4.0-android.pom">
|
||||||
<sha256 value="7220ede61026596fbc720ee4b93246fa2d14f328058532b59ef053de397c7d83" origin="Generated by Gradle"/>
|
<sha256 value="7220ede61026596fbc720ee4b93246fa2d14f328058532b59ef053de397c7d83" origin="Generated by Gradle"/>
|
||||||
@@ -2903,6 +3134,9 @@
|
|||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
<component group="com.google.j2objc" name="j2objc-annotations" version="2.8">
|
<component group="com.google.j2objc" name="j2objc-annotations" version="2.8">
|
||||||
|
<artifact name="j2objc-annotations-2.8.jar">
|
||||||
|
<sha256 value="f02a95fa1a5e95edb3ed859fd0fb7df709d121a35290eff8b74dce2ab7f4d6ed" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
<artifact name="j2objc-annotations-2.8.pom">
|
<artifact name="j2objc-annotations-2.8.pom">
|
||||||
<sha256 value="37f87798b18385113c918bfa9e1276fe50735ef8fa849b5800c519d54dbf11f8" origin="Generated by Gradle"/>
|
<sha256 value="37f87798b18385113c918bfa9e1276fe50735ef8fa849b5800c519d54dbf11f8" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
@@ -3610,6 +3844,14 @@
|
|||||||
<sha256 value="66f563d8a2a1ee395a1283992fd646347f42054d071592d1f477523816e397fa" origin="Generated by Gradle"/>
|
<sha256 value="66f563d8a2a1ee395a1283992fd646347f42054d071592d1f477523816e397fa" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.checkerframework" name="checker-qual" version="3.33.0">
|
||||||
|
<artifact name="checker-qual-3.33.0.jar">
|
||||||
|
<sha256 value="e316255bbfcd9fe50d165314b85abb2b33cb2a66a93c491db648e498a82c2de1" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="checker-qual-3.33.0.module">
|
||||||
|
<sha256 value="e8521d75625d41272c767d262a153ac163cc505b66644a2ef705fa8949ffb4e5" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.checkerframework" name="checker-qual" version="3.43.0">
|
<component group="org.checkerframework" name="checker-qual" version="3.43.0">
|
||||||
<artifact name="checker-qual-3.43.0.jar">
|
<artifact name="checker-qual-3.43.0.jar">
|
||||||
<sha256 value="3fbc2e98f05854c3df16df9abaa955b91b15b3ecac33623208ed6424640ef0f6" origin="Generated by Gradle"/>
|
<sha256 value="3fbc2e98f05854c3df16df9abaa955b91b15b3ecac33623208ed6424640ef0f6" origin="Generated by Gradle"/>
|
||||||
@@ -3768,6 +4010,11 @@
|
|||||||
<sha256 value="3090b4e873054cdc29991ae94c92fa45afb4c145d460441d803baf6ef165bbb8" origin="Generated by Gradle"/>
|
<sha256 value="3090b4e873054cdc29991ae94c92fa45afb4c145d460441d803baf6ef165bbb8" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-bom" version="1.8.0">
|
||||||
|
<artifact name="kotlin-bom-1.8.0.pom">
|
||||||
|
<sha256 value="681f9878548c0a149c678092fd8b1f4cc7c5c41ba1b24397101c1073a6c76dda" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-bom" version="2.3.21">
|
<component group="org.jetbrains.kotlin" name="kotlin-bom" version="2.3.21">
|
||||||
<artifact name="kotlin-bom-2.3.21.pom">
|
<artifact name="kotlin-bom-2.3.21.pom">
|
||||||
<sha256 value="950704bad04c5143656cfca1d2c574f25fcad9cac33905ab22a57e9fdf7bfd88" origin="Generated by Gradle"/>
|
<sha256 value="950704bad04c5143656cfca1d2c574f25fcad9cac33905ab22a57e9fdf7bfd88" origin="Generated by Gradle"/>
|
||||||
@@ -4400,6 +4647,19 @@
|
|||||||
<sha256 value="ee66712b1006e971636f11554af63c56835caf315382ce23e54f59f5b8b9d4f9" origin="Generated by Gradle"/>
|
<sha256 value="ee66712b1006e971636f11554af63c56835caf315382ce23e54f59f5b8b9d4f9" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlinx" name="atomicfu" version="0.28.0">
|
||||||
|
<artifact name="atomicfu-0.28.0.module">
|
||||||
|
<sha256 value="535568c9291a3da7705c4b40535eacedf86b248df570ac52669c907d4bb8558b" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlinx" name="atomicfu-jvm" version="0.28.0">
|
||||||
|
<artifact name="atomicfu-jvm-0.28.0.jar">
|
||||||
|
<sha256 value="39576ec46b83412ff7a2909d24cccbba90400e91f9aa67b250309bc0872ecf52" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="atomicfu-jvm-0.28.0.module">
|
||||||
|
<sha256 value="34b623af9c25ca7f2e52406f10495c46e6f410835d7a058c60ba36923d689635" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-android" version="1.11.0">
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-android" version="1.11.0">
|
||||||
<artifact name="kotlinx-coroutines-android-1.11.0.jar">
|
<artifact name="kotlinx-coroutines-android-1.11.0.jar">
|
||||||
<sha256 value="c2cb206d27017c7d1bf5ff179787397543d13748dbabb0d7237e1585e0b29044" origin="Generated by Gradle"/>
|
<sha256 value="c2cb206d27017c7d1bf5ff179787397543d13748dbabb0d7237e1585e0b29044" origin="Generated by Gradle"/>
|
||||||
|
|||||||
@@ -22,6 +22,14 @@ androidx.benchmark:benchmark-macro:1.5.0=benchmarkCompileClasspath,benchmarkLint
|
|||||||
androidx.benchmark:benchmark-traceprocessor-android:1.5.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
androidx.benchmark:benchmark-traceprocessor-android:1.5.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
||||||
androidx.benchmark:benchmark-traceprocessor:1.5.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
androidx.benchmark:benchmark-traceprocessor:1.5.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
||||||
androidx.biometric:biometric:1.1.0=benchmarkTestedApks,debugTestedApks
|
androidx.biometric:biometric:1.1.0=benchmarkTestedApks,debugTestedApks
|
||||||
|
androidx.camera.featurecombinationquery:featurecombinationquery:1.6.2=benchmarkTestedApks,debugTestedApks
|
||||||
|
androidx.camera.viewfinder:viewfinder-core:1.5.1=benchmarkTestedApks,debugTestedApks
|
||||||
|
androidx.camera:camera-camera2-pipe:1.6.2=benchmarkTestedApks,debugTestedApks
|
||||||
|
androidx.camera:camera-camera2:1.6.2=benchmarkTestedApks,debugTestedApks
|
||||||
|
androidx.camera:camera-core:1.6.2=benchmarkTestedApks,debugTestedApks
|
||||||
|
androidx.camera:camera-lifecycle:1.6.2=benchmarkTestedApks,debugTestedApks
|
||||||
|
androidx.camera:camera-video:1.6.2=benchmarkTestedApks,debugTestedApks
|
||||||
|
androidx.camera:camera-view:1.6.2=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.collection:collection-jvm:1.6.0=benchmarkTestedApks,debugTestedApks
|
androidx.collection:collection-jvm:1.6.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.collection:collection:1.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
androidx.collection:collection:1.0.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
||||||
androidx.collection:collection:1.6.0=benchmarkTestedApks,debugTestedApks
|
androidx.collection:collection:1.6.0=benchmarkTestedApks,debugTestedApks
|
||||||
@@ -64,9 +72,11 @@ androidx.compose.ui:ui-util-jvmstubs:1.12.1=benchmarkTestedApks,debugTestedApks
|
|||||||
androidx.compose.ui:ui-util:1.12.1=benchmarkTestedApks,debugTestedApks
|
androidx.compose.ui:ui-util:1.12.1=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.compose.ui:ui:1.12.1=benchmarkTestedApks,debugTestedApks
|
androidx.compose.ui:ui:1.12.1=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.compose:compose-bom:2026.09.00=benchmarkTestedApks,debugTestedApks
|
androidx.compose:compose-bom:2026.09.00=benchmarkTestedApks,debugTestedApks
|
||||||
|
androidx.concurrent:concurrent-futures-ktx:1.1.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.concurrent:concurrent-futures-ktx:1.2.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
androidx.concurrent:concurrent-futures-ktx:1.2.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
||||||
androidx.concurrent:concurrent-futures:1.1.0=benchmarkTestedApks,debugTestedApks
|
androidx.concurrent:concurrent-futures:1.1.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.concurrent:concurrent-futures:1.2.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
androidx.concurrent:concurrent-futures:1.2.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
||||||
|
androidx.core:core-backported-fixes:1.0.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.core:core-ktx:1.18.0=benchmarkTestedApks,debugTestedApks
|
androidx.core:core-ktx:1.18.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.core:core-viewtree:1.0.0=benchmarkTestedApks,debugTestedApks
|
androidx.core:core-viewtree:1.0.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.core:core:1.18.0=benchmarkTestedApks,debugTestedApks
|
androidx.core:core:1.18.0=benchmarkTestedApks,debugTestedApks
|
||||||
@@ -74,6 +84,7 @@ androidx.core:core:1.9.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,
|
|||||||
androidx.cursoradapter:cursoradapter:1.0.0=benchmarkTestedApks,debugTestedApks
|
androidx.cursoradapter:cursoradapter:1.0.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.customview:customview:1.0.0=benchmarkTestedApks,debugTestedApks
|
androidx.customview:customview:1.0.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.drawerlayout:drawerlayout:1.0.0=benchmarkTestedApks,debugTestedApks
|
androidx.drawerlayout:drawerlayout:1.0.0=benchmarkTestedApks,debugTestedApks
|
||||||
|
androidx.exifinterface:exifinterface:1.4.2=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.fragment:fragment:1.9.1=benchmarkTestedApks,debugTestedApks
|
androidx.fragment:fragment:1.9.1=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.interpolator:interpolator:1.0.0=benchmarkTestedApks,debugTestedApks
|
androidx.interpolator:interpolator:1.0.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.lifecycle:lifecycle-common-jvm:2.11.0=benchmarkTestedApks,debugTestedApks
|
androidx.lifecycle:lifecycle-common-jvm:2.11.0=benchmarkTestedApks,debugTestedApks
|
||||||
@@ -97,6 +108,9 @@ androidx.lifecycle:lifecycle-viewmodel-savedstate-desktop:2.11.0=benchmarkTested
|
|||||||
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.11.0=benchmarkTestedApks,debugTestedApks
|
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.11.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.lifecycle:lifecycle-viewmodel:2.11.0=benchmarkTestedApks,debugTestedApks
|
androidx.lifecycle:lifecycle-viewmodel:2.11.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.loader:loader:1.0.0=benchmarkTestedApks,debugTestedApks
|
androidx.loader:loader:1.0.0=benchmarkTestedApks,debugTestedApks
|
||||||
|
androidx.media3:media3-common:1.9.0=benchmarkTestedApks,debugTestedApks
|
||||||
|
androidx.media3:media3-container:1.9.0=benchmarkTestedApks,debugTestedApks
|
||||||
|
androidx.media3:media3-muxer:1.9.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.navigation3:navigation3-runtime-desktop:1.2.0=benchmarkTestedApks,debugTestedApks
|
androidx.navigation3:navigation3-runtime-desktop:1.2.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.navigation3:navigation3-runtime:1.2.0=benchmarkTestedApks,debugTestedApks
|
androidx.navigation3:navigation3-runtime:1.2.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.navigation3:navigation3-ui-jvmstubs:1.2.0=benchmarkTestedApks,debugTestedApks
|
androidx.navigation3:navigation3-ui-jvmstubs:1.2.0=benchmarkTestedApks,debugTestedApks
|
||||||
@@ -125,6 +139,7 @@ androidx.test:rules:1.5.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath
|
|||||||
androidx.test:runner:1.7.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
androidx.test:runner:1.7.0=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
||||||
androidx.tracing:tracing-desktop:2.0.0=benchmarkTestedApks,debugTestedApks
|
androidx.tracing:tracing-desktop:2.0.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.tracing:tracing-ktx:1.1.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
androidx.tracing:tracing-ktx:1.1.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
||||||
|
androidx.tracing:tracing-ktx:2.0.0=benchmarkTestedApks,debugTestedApks
|
||||||
androidx.tracing:tracing-perfetto-binary:1.0.1=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
androidx.tracing:tracing-perfetto-binary:1.0.1=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
||||||
androidx.tracing:tracing-perfetto-handshake:1.0.1=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
androidx.tracing:tracing-perfetto-handshake:1.0.1=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
||||||
androidx.tracing:tracing-perfetto:1.0.1=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
androidx.tracing:tracing-perfetto:1.0.1=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
||||||
@@ -169,18 +184,21 @@ com.android.tools:sdk-common:32.4.1=androidLintTool
|
|||||||
com.android.tools:sdklib:32.4.1=androidLintTool
|
com.android.tools:sdklib:32.4.1=androidLintTool
|
||||||
com.github.ajalt.clikt:clikt-jvm:5.0.3=ktlint
|
com.github.ajalt.clikt:clikt-jvm:5.0.3=ktlint
|
||||||
com.github.ajalt.clikt:clikt:5.0.3=ktlint
|
com.github.ajalt.clikt:clikt:5.0.3=ktlint
|
||||||
|
com.google.auto.value:auto-value-annotations:1.6.3=benchmarkTestedApks,debugTestedApks
|
||||||
com.google.code.findbugs:jsr305:3.0.2=androidLintTool,benchmarkTestedApks,debugTestedApks
|
com.google.code.findbugs:jsr305:3.0.2=androidLintTool,benchmarkTestedApks,debugTestedApks
|
||||||
com.google.code.gson:gson:2.11.0=androidLintTool
|
com.google.code.gson:gson:2.11.0=androidLintTool
|
||||||
com.google.dagger:dagger-lint-aar:2.60.1=benchmarkTestedApks,debugTestedApks
|
com.google.dagger:dagger-lint-aar:2.60.1=benchmarkTestedApks,debugTestedApks
|
||||||
com.google.dagger:dagger:2.60.1=benchmarkTestedApks,debugTestedApks
|
com.google.dagger:dagger:2.60.1=benchmarkTestedApks,debugTestedApks
|
||||||
com.google.dagger:hilt-android:2.60.1=benchmarkTestedApks,debugTestedApks
|
com.google.dagger:hilt-android:2.60.1=benchmarkTestedApks,debugTestedApks
|
||||||
com.google.dagger:hilt-core:2.60.1=benchmarkTestedApks,debugTestedApks
|
com.google.dagger:hilt-core:2.60.1=benchmarkTestedApks,debugTestedApks
|
||||||
|
com.google.errorprone:error_prone_annotations:2.28.0=benchmarkTestedApks,debugTestedApks
|
||||||
com.google.errorprone:error_prone_annotations:2.36.0=androidLintTool
|
com.google.errorprone:error_prone_annotations:2.36.0=androidLintTool
|
||||||
com.google.guava:failureaccess:1.0.2=androidLintTool
|
com.google.guava:failureaccess:1.0.2=androidLintTool,benchmarkTestedApks,debugTestedApks
|
||||||
|
com.google.guava:guava:33.3.1-android=benchmarkTestedApks,debugTestedApks
|
||||||
com.google.guava:guava:33.4.0-jre=androidLintTool
|
com.google.guava:guava:33.4.0-jre=androidLintTool
|
||||||
com.google.guava:listenablefuture:1.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,benchmarkTestedApks,debugLintChecksClasspath,debugRuntimeClasspath,debugTestedApks
|
com.google.guava:listenablefuture:1.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
||||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=androidLintTool
|
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=androidLintTool,benchmarkTestedApks,debugTestedApks
|
||||||
com.google.j2objc:j2objc-annotations:3.0.0=androidLintTool
|
com.google.j2objc:j2objc-annotations:3.0.0=androidLintTool,benchmarkTestedApks,debugTestedApks
|
||||||
com.google.jimfs:jimfs:1.1=androidLintTool
|
com.google.jimfs:jimfs:1.1=androidLintTool
|
||||||
com.google.protobuf:protobuf-java:3.25.5=androidLintTool,unified-test-platform-gradle-work-action
|
com.google.protobuf:protobuf-java:3.25.5=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
com.pinterest.ktlint:ktlint-cli-reporter-baseline:1.7.1=ktlint,ktlintBaselineReporter
|
com.pinterest.ktlint:ktlint-cli-reporter-baseline:1.7.1=ktlint,ktlintBaselineReporter
|
||||||
@@ -233,11 +251,12 @@ org.apache.httpcomponents:httpmime:4.5.6=androidLintTool
|
|||||||
org.bouncycastle:bcpkix-jdk18on:1.80.2=androidLintTool
|
org.bouncycastle:bcpkix-jdk18on:1.80.2=androidLintTool
|
||||||
org.bouncycastle:bcprov-jdk18on:1.80.2=androidLintTool
|
org.bouncycastle:bcprov-jdk18on:1.80.2=androidLintTool
|
||||||
org.bouncycastle:bcutil-jdk18on:1.80.2=androidLintTool
|
org.bouncycastle:bcutil-jdk18on:1.80.2=androidLintTool
|
||||||
org.checkerframework:checker-qual:3.43.0=androidLintTool
|
org.checkerframework:checker-qual:3.43.0=androidLintTool,benchmarkTestedApks,debugTestedApks
|
||||||
org.ec4j.core:ec4j-core:1.1.1=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.ec4j.core:ec4j-core:1.1.1=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
||||||
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
||||||
org.hamcrest:hamcrest-core:1.3=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
org.hamcrest:hamcrest-core:1.3=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
||||||
|
org.jetbrains.kotlin:kotlin-bom:1.8.0=benchmarkTestedApks,debugTestedApks
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
@@ -270,6 +289,8 @@ org.jetbrains.kotlin:kotlin-stdlib:2.2.10=androidLintTool,unified-test-platform-
|
|||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.21=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,benchmarkTestedApks,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugTestedApks,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.21=benchmarkCompileClasspath,benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,benchmarkTestedApks,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugTestedApks,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-tooling-core:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-tooling-core:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
|
org.jetbrains.kotlinx:atomicfu-jvm:0.28.0=benchmarkTestedApks,debugTestedApks
|
||||||
|
org.jetbrains.kotlinx:atomicfu:0.28.0=benchmarkTestedApks,debugTestedApks
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=benchmarkTestedApks,debugTestedApks
|
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=benchmarkTestedApks,debugTestedApks
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0=benchmarkLintChecksClasspath,benchmarkRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=benchmarkTestedApks,debugTestedApks
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=benchmarkTestedApks,debugTestedApks
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ kotlin {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":core"))
|
implementation(project(":core"))
|
||||||
|
implementation(libs.camera.camera2)
|
||||||
|
implementation(libs.camera.lifecycle)
|
||||||
|
implementation(libs.camera.view)
|
||||||
implementation(libs.biometric)
|
implementation(libs.biometric)
|
||||||
implementation(libs.fragment)
|
implementation(libs.fragment)
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
|
|||||||
@@ -14,13 +14,23 @@ androidx.appcompat:appcompat:1.2.0=debugAndroidTestLintChecksClasspath,debugAndr
|
|||||||
androidx.arch.core:core-common:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.arch.core:core-common:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.arch.core:core-runtime:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.arch.core:core-runtime:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.biometric:biometric:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.biometric:biometric:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera.featurecombinationquery:featurecombinationquery:1.6.2=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera.viewfinder:viewfinder-core:1.5.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera:camera-camera2-pipe:1.6.2=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera:camera-camera2:1.6.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera:camera-core:1.6.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera:camera-lifecycle:1.6.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera:camera-video:1.6.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.camera:camera-view:1.6.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.collection:collection-jvm:1.4.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
androidx.collection:collection-jvm:1.4.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
androidx.collection:collection-jvm:1.6.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.collection:collection-jvm:1.6.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.collection:collection:1.4.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
androidx.collection:collection:1.4.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
androidx.collection:collection:1.6.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.collection:collection:1.6.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.concurrent:concurrent-futures-ktx:1.1.0=debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.concurrent:concurrent-futures-ktx:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.concurrent:concurrent-futures-ktx:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
androidx.concurrent:concurrent-futures:1.1.0=debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.concurrent:concurrent-futures:1.1.0=debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.concurrent:concurrent-futures:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.concurrent:concurrent-futures:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.core:core-backported-fixes:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.core:core-ktx:1.13.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.core:core-ktx:1.13.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.core:core-ktx:1.9.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
androidx.core:core-ktx:1.9.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
androidx.core:core-viewtree:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.core:core-viewtree:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -29,6 +39,7 @@ androidx.core:core:1.9.0=debugAndroidTestCompileClasspath,debugCompileClasspath,
|
|||||||
androidx.cursoradapter:cursoradapter:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.cursoradapter:cursoradapter:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.customview:customview:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.customview:customview:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.drawerlayout:drawerlayout:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.drawerlayout:drawerlayout:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.exifinterface:exifinterface:1.4.2=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.fragment:fragment:1.9.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.fragment:fragment:1.9.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.interpolator:interpolator:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.interpolator:interpolator:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.lifecycle:lifecycle-common-jvm:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.lifecycle:lifecycle-common-jvm:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -46,6 +57,9 @@ androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.10.0=debugAndroidTes
|
|||||||
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.lifecycle:lifecycle-viewmodel:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.lifecycle:lifecycle-viewmodel:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.loader:loader:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.loader:loader:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.media3:media3-common:1.9.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.media3:media3-container:1.9.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.media3:media3-muxer:1.9.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.profileinstaller:profileinstaller:1.4.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.profileinstaller:profileinstaller:1.4.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.savedstate:savedstate-android:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.savedstate:savedstate-android:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.savedstate:savedstate-ktx:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.savedstate:savedstate-ktx:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -56,6 +70,7 @@ androidx.test:core:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintCh
|
|||||||
androidx.test:monitor:1.8.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.test:monitor:1.8.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
androidx.test:runner:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.test:runner:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
androidx.tracing:tracing-android:2.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.tracing:tracing-android:2.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.tracing:tracing-ktx:2.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.tracing:tracing:1.1.0=debugAndroidTestCompileClasspath
|
androidx.tracing:tracing:1.1.0=debugAndroidTestCompileClasspath
|
||||||
androidx.tracing:tracing:2.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.tracing:tracing:2.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.vectordrawable:vectordrawable-animated:1.1.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.vectordrawable:vectordrawable-animated:1.1.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -95,14 +110,21 @@ com.android.tools:sdk-common:32.4.1=androidLintTool
|
|||||||
com.android.tools:sdklib:32.4.1=androidLintTool
|
com.android.tools:sdklib:32.4.1=androidLintTool
|
||||||
com.github.ajalt.clikt:clikt-jvm:5.0.3=ktlint
|
com.github.ajalt.clikt:clikt-jvm:5.0.3=ktlint
|
||||||
com.github.ajalt.clikt:clikt:5.0.3=ktlint
|
com.github.ajalt.clikt:clikt:5.0.3=ktlint
|
||||||
com.google.code.findbugs:jsr305:3.0.2=androidLintTool
|
com.google.auto.value:auto-value-annotations:1.6.3=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
com.google.code.findbugs:jsr305:3.0.2=androidLintTool,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
com.google.code.gson:gson:2.11.0=androidLintTool
|
com.google.code.gson:gson:2.11.0=androidLintTool
|
||||||
|
com.google.dagger:dagger:2.59=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
com.google.errorprone:error_prone_annotations:2.18.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
|
com.google.errorprone:error_prone_annotations:2.28.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
com.google.errorprone:error_prone_annotations:2.36.0=androidLintTool
|
com.google.errorprone:error_prone_annotations:2.36.0=androidLintTool
|
||||||
com.google.guava:failureaccess:1.0.2=androidLintTool
|
com.google.guava:failureaccess:1.0.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
|
com.google.guava:failureaccess:1.0.2=androidLintTool,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
com.google.guava:guava:32.0.1-android=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
|
com.google.guava:guava:33.3.1-android=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
com.google.guava:guava:33.4.0-jre=androidLintTool
|
com.google.guava:guava:33.4.0-jre=androidLintTool
|
||||||
com.google.guava:listenablefuture:1.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=androidLintTool,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=androidLintTool
|
com.google.j2objc:j2objc-annotations:2.8=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
com.google.j2objc:j2objc-annotations:3.0.0=androidLintTool
|
com.google.j2objc:j2objc-annotations:3.0.0=androidLintTool,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
com.google.jimfs:jimfs:1.1=androidLintTool
|
com.google.jimfs:jimfs:1.1=androidLintTool
|
||||||
com.google.protobuf:protobuf-java:3.25.5=androidLintTool,unified-test-platform-gradle-work-action
|
com.google.protobuf:protobuf-java:3.25.5=androidLintTool,unified-test-platform-gradle-work-action
|
||||||
com.pinterest.ktlint:ktlint-cli-reporter-baseline:1.7.1=ktlint,ktlintBaselineReporter
|
com.pinterest.ktlint:ktlint-cli-reporter-baseline:1.7.1=ktlint,ktlintBaselineReporter
|
||||||
@@ -132,8 +154,9 @@ io.github.detekt.sarif4k:sarif4k:0.6.0=ktlint,ktlintReporter
|
|||||||
io.github.oshai:kotlin-logging-jvm:7.0.7=ktlint,ktlintBaselineReporter,ktlintReporter,ktlintRuleset
|
io.github.oshai:kotlin-logging-jvm:7.0.7=ktlint,ktlintBaselineReporter,ktlintReporter,ktlintRuleset
|
||||||
io.github.oshai:kotlin-logging:5.1.0=ktlint,ktlintBaselineReporter,ktlintReporter
|
io.github.oshai:kotlin-logging:5.1.0=ktlint,ktlintBaselineReporter,ktlintReporter
|
||||||
jakarta.activation:jakarta.activation-api:1.2.1=androidLintTool
|
jakarta.activation:jakarta.activation-api:1.2.1=androidLintTool
|
||||||
|
jakarta.inject:jakarta.inject-api:2.0.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=androidLintTool
|
jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=androidLintTool
|
||||||
javax.inject:javax.inject:1=androidLintTool
|
javax.inject:javax.inject:1=androidLintTool,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
junit:junit:4.13.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
junit:junit:4.13.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
||||||
net.java.dev.jna:jna:5.19.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
net.java.dev.jna:jna:5.19.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -149,11 +172,13 @@ org.apache.httpcomponents:httpmime:4.5.6=androidLintTool
|
|||||||
org.bouncycastle:bcpkix-jdk18on:1.80.2=androidLintTool
|
org.bouncycastle:bcpkix-jdk18on:1.80.2=androidLintTool
|
||||||
org.bouncycastle:bcprov-jdk18on:1.80.2=androidLintTool
|
org.bouncycastle:bcprov-jdk18on:1.80.2=androidLintTool
|
||||||
org.bouncycastle:bcutil-jdk18on:1.80.2=androidLintTool
|
org.bouncycastle:bcutil-jdk18on:1.80.2=androidLintTool
|
||||||
org.checkerframework:checker-qual:3.43.0=androidLintTool
|
org.checkerframework:checker-qual:3.33.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
|
org.checkerframework:checker-qual:3.43.0=androidLintTool,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.ec4j.core:ec4j-core:1.1.1=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.ec4j.core:ec4j-core:1.1.1=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
||||||
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
||||||
org.hamcrest:hamcrest-core:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
org.hamcrest:hamcrest-core:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
|
org.jetbrains.kotlin:kotlin-bom:1.8.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
@@ -186,6 +211,8 @@ org.jetbrains.kotlin:kotlin-stdlib:2.2.10=androidLintTool,unified-test-platform-
|
|||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.21=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.21=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-tooling-core:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-tooling-core:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
|
org.jetbrains.kotlinx:atomicfu-jvm:0.28.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.jetbrains.kotlinx:atomicfu:0.28.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<application>
|
<application>
|
||||||
<activity android:name="de.rfc1437.ironstorage.platform.KeystoreTestActivity" android:exported="false" android:theme="@android:style/Theme.Material.Light.NoActionBar" />
|
<activity android:name="de.rfc1437.ironstorage.platform.KeystoreTestActivity" android:exported="false" android:theme="@android:style/Theme.Material.Light.NoActionBar" />
|
||||||
</application>
|
</application>
|
||||||
|
|||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
package de.rfc1437.ironstorage.platform
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import androidx.test.core.app.ActivityScenario
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class AndroidQrCameraTest {
|
||||||
|
@Test fun livePreviewDeliversBoundedPlanesAndCanBeClosedAndReopened() {
|
||||||
|
val context = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
assertEquals(
|
||||||
|
PackageManager.PERMISSION_GRANTED,
|
||||||
|
context.checkSelfPermission(Manifest.permission.CAMERA)
|
||||||
|
)
|
||||||
|
ActivityScenario.launch(KeystoreTestActivity::class.java).use { activity ->
|
||||||
|
repeat(2) {
|
||||||
|
val received = CountDownLatch(1)
|
||||||
|
val failed = CountDownLatch(1)
|
||||||
|
var camera: AndroidQrCamera? = null
|
||||||
|
activity.onActivity { host ->
|
||||||
|
camera = AndroidQrCamera(host, { frame ->
|
||||||
|
try {
|
||||||
|
assertTrue(frame.width in 1u..2048u)
|
||||||
|
assertTrue(frame.height in 1u..2048u)
|
||||||
|
assertTrue(frame.pixels.size <= 4 * 1024 * 1024)
|
||||||
|
assertTrue(frame.rotationDegrees in listOf(0u, 90u, 180u, 270u))
|
||||||
|
received.countDown()
|
||||||
|
} finally {
|
||||||
|
frame.pixels.fill(0)
|
||||||
|
}
|
||||||
|
}, { failed.countDown() })
|
||||||
|
host.setContentView(requireNotNull(camera).view)
|
||||||
|
assertTrue(requireNotNull(camera).view.clipToOutline)
|
||||||
|
}
|
||||||
|
assertTrue(
|
||||||
|
"The emulator camera did not deliver a frame",
|
||||||
|
received.await(15, TimeUnit.SECONDS)
|
||||||
|
)
|
||||||
|
assertFalse("CameraX failed to bind", failed.count == 0L)
|
||||||
|
activity.onActivity { camera?.close() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package de.rfc1437.ironstorage.platform
|
||||||
|
|
||||||
|
import android.util.Size
|
||||||
|
import androidx.camera.core.CameraSelector
|
||||||
|
import androidx.camera.core.ImageAnalysis
|
||||||
|
import androidx.camera.core.Preview
|
||||||
|
import androidx.camera.core.resolutionselector.ResolutionSelector
|
||||||
|
import androidx.camera.core.resolutionselector.ResolutionStrategy
|
||||||
|
import androidx.camera.lifecycle.ProcessCameraProvider
|
||||||
|
import androidx.camera.view.PreviewView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import de.rfc1437.ironstorage.core.CameraFrame
|
||||||
|
import de.rfc1437.ironstorage.core.CameraPreview
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
|
internal class AndroidQrCamera(
|
||||||
|
private val activity: FragmentActivity,
|
||||||
|
private val frame: (CameraFrame) -> Unit,
|
||||||
|
private val failure: () -> Unit
|
||||||
|
) : CameraPreview {
|
||||||
|
override val view = PreviewView(activity).apply {
|
||||||
|
implementationMode = PreviewView.ImplementationMode.COMPATIBLE
|
||||||
|
outlineProvider = android.view.ViewOutlineProvider.BOUNDS
|
||||||
|
clipToOutline = true
|
||||||
|
scaleType = PreviewView.ScaleType.FIT_CENTER
|
||||||
|
importantForAccessibility = android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO
|
||||||
|
}
|
||||||
|
private val executor = Executors.newSingleThreadExecutor()
|
||||||
|
private val preview = Preview.Builder().build()
|
||||||
|
private val analysis = ImageAnalysis.Builder()
|
||||||
|
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
||||||
|
.setResolutionSelector(
|
||||||
|
ResolutionSelector.Builder().setResolutionStrategy(
|
||||||
|
ResolutionStrategy(Size(1280, 720), ResolutionStrategy.FALLBACK_RULE_CLOSEST_LOWER)
|
||||||
|
).build()
|
||||||
|
).build()
|
||||||
|
private var provider: ProcessCameraProvider? = null
|
||||||
|
|
||||||
|
@Volatile private var active = true
|
||||||
|
|
||||||
|
init {
|
||||||
|
analysis.setAnalyzer(executor) { image ->
|
||||||
|
var bytes: ByteArray? = null
|
||||||
|
try {
|
||||||
|
if (active && image.width in 1..2048 && image.height in 1..2048) {
|
||||||
|
val plane = image.planes[0]
|
||||||
|
val source = plane.buffer.duplicate()
|
||||||
|
if (source.remaining() <= 4 * 1024 * 1024) {
|
||||||
|
val pixels = ByteArray(source.remaining())
|
||||||
|
bytes = pixels
|
||||||
|
source.get(pixels)
|
||||||
|
if (active) {
|
||||||
|
frame(
|
||||||
|
CameraFrame(
|
||||||
|
pixels,
|
||||||
|
image.width.toUInt(),
|
||||||
|
image.height.toUInt(),
|
||||||
|
plane.rowStride.toUInt(),
|
||||||
|
plane.pixelStride.toUInt(),
|
||||||
|
image.imageInfo.rotationDegrees.toUInt()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
// The receiver clears transferred bytes after the native call.
|
||||||
|
bytes = null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
failure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
bytes?.fill(0)
|
||||||
|
image.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val pending = ProcessCameraProvider.getInstance(activity)
|
||||||
|
pending.addListener({
|
||||||
|
if (active) {
|
||||||
|
try {
|
||||||
|
provider = pending.get()
|
||||||
|
preview.setSurfaceProvider(view.surfaceProvider)
|
||||||
|
provider!!.bindToLifecycle(
|
||||||
|
activity,
|
||||||
|
CameraSelector.DEFAULT_BACK_CAMERA,
|
||||||
|
preview,
|
||||||
|
analysis
|
||||||
|
)
|
||||||
|
} catch (_: java.util.concurrent.ExecutionException) {
|
||||||
|
close()
|
||||||
|
failure()
|
||||||
|
} catch (_: InterruptedException) {
|
||||||
|
Thread.currentThread().interrupt()
|
||||||
|
close()
|
||||||
|
failure()
|
||||||
|
} catch (_: IllegalArgumentException) {
|
||||||
|
close()
|
||||||
|
failure()
|
||||||
|
} catch (_: SecurityException) {
|
||||||
|
close()
|
||||||
|
failure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, ContextCompat.getMainExecutor(activity))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
active = false
|
||||||
|
analysis.clearAnalyzer()
|
||||||
|
provider?.unbind(preview, analysis)
|
||||||
|
provider = null
|
||||||
|
executor.shutdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -40,6 +40,13 @@ class AndroidSettingsPlatform(
|
|||||||
host.clear()
|
host.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
override fun cameraPreview(
|
||||||
|
frame: (de.rfc1437.ironstorage.core.CameraFrame) -> Unit,
|
||||||
|
failure: () -> Unit
|
||||||
|
): de.rfc1437.ironstorage.core.CameraPreview? {
|
||||||
|
val activity = host.get() ?: return null
|
||||||
|
return AndroidQrCamera(activity, frame, failure)
|
||||||
|
}
|
||||||
override fun chooseQrImages(): Boolean {
|
override fun chooseQrImages(): Boolean {
|
||||||
val picker = picker ?: return false
|
val picker = picker ?: return false
|
||||||
return try {
|
return try {
|
||||||
|
|||||||
@@ -101,6 +101,24 @@ impl MobileAndroidOnboarding {
|
|||||||
.import(SecretBytes::new(armor.into_bytes()), secret(passphrase))?
|
.import(SecretBytes::new(armor.into_bytes()), secret(passphrase))?
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
|
pub fn import_scanned(
|
||||||
|
&self,
|
||||||
|
transfer: Arc<crate::MobileKeyTransferImport>,
|
||||||
|
passphrase: Option<String>,
|
||||||
|
) -> Result<MobileAndroidSetupStatus, crate::MobileKeyTransferFfiError> {
|
||||||
|
let importer =
|
||||||
|
transfer
|
||||||
|
.importer
|
||||||
|
.lock()
|
||||||
|
.map_err(|_| crate::MobileKeyTransferFfiError::Failed {
|
||||||
|
kind: crate::MobileKeyTransferErrorKind::Failed,
|
||||||
|
message: "the key-transfer session is unavailable".to_owned(),
|
||||||
|
})?;
|
||||||
|
Ok(self
|
||||||
|
.setup
|
||||||
|
.import_scanned(&importer, secret(passphrase))?
|
||||||
|
.into())
|
||||||
|
}
|
||||||
pub fn setup_local(
|
pub fn setup_local(
|
||||||
&self,
|
&self,
|
||||||
fingerprint: String,
|
fingerprint: String,
|
||||||
|
|||||||
@@ -1581,6 +1581,10 @@ pub struct MobileKeyTransfer {
|
|||||||
|
|
||||||
#[uniffi::export]
|
#[uniffi::export]
|
||||||
impl MobileKeyTransfer {
|
impl MobileKeyTransfer {
|
||||||
|
pub fn export_visible(&self) -> bool {
|
||||||
|
self.service.export_visible()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn keys(&self) -> Vec<MobileKeyTransferKey> {
|
pub fn keys(&self) -> Vec<MobileKeyTransferKey> {
|
||||||
self.service.keys().iter().map(Into::into).collect()
|
self.service.keys().iter().map(Into::into).collect()
|
||||||
}
|
}
|
||||||
@@ -1635,6 +1639,31 @@ pub struct MobileKeyTransferImport {
|
|||||||
|
|
||||||
#[uniffi::export]
|
#[uniffi::export]
|
||||||
impl MobileKeyTransferImport {
|
impl MobileKeyTransferImport {
|
||||||
|
pub fn add_camera(
|
||||||
|
&self,
|
||||||
|
frame: platform::MobileCameraFrame,
|
||||||
|
rotation_degrees: u32,
|
||||||
|
) -> Result<Option<MobileKeyTransferProgress>, MobileKeyTransferFfiError> {
|
||||||
|
self.importer
|
||||||
|
.lock()
|
||||||
|
.map_err(|_| MobileKeyTransferFfiError::Failed {
|
||||||
|
kind: MobileKeyTransferErrorKind::Failed,
|
||||||
|
message: "the key-transfer session is unavailable".to_owned(),
|
||||||
|
})?
|
||||||
|
.add_camera(
|
||||||
|
ironstorage::mobile_platform::MobileCameraFrame {
|
||||||
|
luminance: ironstorage::repository::SecretBytes::new(frame.luminance),
|
||||||
|
width: frame.width,
|
||||||
|
height: frame.height,
|
||||||
|
row_stride: frame.row_stride,
|
||||||
|
pixel_stride: frame.pixel_stride,
|
||||||
|
},
|
||||||
|
rotation_degrees,
|
||||||
|
)
|
||||||
|
.map(|progress| progress.map(Into::into))
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_image(
|
pub fn add_image(
|
||||||
&self,
|
&self,
|
||||||
image: Vec<u8>,
|
image: Vec<u8>,
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
//! Storage-owned OpenPGP key transfer for native mobile QR adapters.
|
//! Storage-owned OpenPGP key transfer for native mobile QR adapters.
|
||||||
|
|
||||||
use std::{collections::BTreeMap, error::Error, fmt, fs, io::Write as _, path::Path};
|
use std::{
|
||||||
|
collections::BTreeMap, error::Error, fmt, fs, io::Write as _, path::Path, sync::Mutex,
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::atomic_file::TempFile;
|
use crate::atomic_file::TempFile;
|
||||||
use cap_std::{ambient_authority, fs::Dir};
|
use cap_std::{ambient_authority, fs::Dir};
|
||||||
@@ -17,6 +20,9 @@ use crate::{
|
|||||||
const FRAME_PREFIX: &str = "ISKT1";
|
const FRAME_PREFIX: &str = "ISKT1";
|
||||||
const FRAME_CHUNK_BYTES: usize = 1_600;
|
const FRAME_CHUNK_BYTES: usize = 1_600;
|
||||||
const MAX_TRANSFER_FRAMES: usize = 11_000;
|
const MAX_TRANSFER_FRAMES: usize = 11_000;
|
||||||
|
const MAX_TRANSFER_BYTES: usize = MAX_TRANSFER_FRAMES * FRAME_CHUNK_BYTES;
|
||||||
|
// Bound eager QR matrices to under 8 MiB on lower-memory mobile clients.
|
||||||
|
const MAX_EXPORT_FRAMES: usize = 256;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum MobileKeyTransferKind {
|
pub enum MobileKeyTransferKind {
|
||||||
@@ -140,13 +146,18 @@ impl MobileKeyTransferOutcome {
|
|||||||
pub struct MobileKeyTransferService {
|
pub struct MobileKeyTransferService {
|
||||||
config: Config,
|
config: Config,
|
||||||
keys: KeyStore,
|
keys: KeyStore,
|
||||||
|
export_deadline: Mutex<Option<Instant>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MobileKeyTransferService {
|
impl MobileKeyTransferService {
|
||||||
pub fn load() -> Result<Self, MobileKeyTransferError> {
|
pub fn load() -> Result<Self, MobileKeyTransferError> {
|
||||||
let config = Config::load(None)?;
|
let config = Config::load(None)?;
|
||||||
let keys = load_keys_or_empty(config.key_material())?;
|
let keys = load_keys_or_empty(config.key_material())?;
|
||||||
Ok(Self { config, keys })
|
Ok(Self {
|
||||||
|
config,
|
||||||
|
keys,
|
||||||
|
export_deadline: Mutex::new(None),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keys(&self) -> Vec<MobileKeyTransferKey> {
|
pub fn keys(&self) -> Vec<MobileKeyTransferKey> {
|
||||||
@@ -169,6 +180,11 @@ impl MobileKeyTransferService {
|
|||||||
.find(|key| key.fingerprint().as_str() == fingerprint)
|
.find(|key| key.fingerprint().as_str() == fingerprint)
|
||||||
.ok_or(MobileKeyTransferError::KeyUnavailable)?;
|
.ok_or(MobileKeyTransferError::KeyUnavailable)?;
|
||||||
let frames = encode_frames(armor)?;
|
let frames = encode_frames(armor)?;
|
||||||
|
*self
|
||||||
|
.export_deadline
|
||||||
|
.lock()
|
||||||
|
.map_err(|_| MobileKeyTransferError::KeyUnavailable)? =
|
||||||
|
Some(Instant::now() + self.config.authentication_timeout().duration());
|
||||||
Ok(MobileKeyTransferExport {
|
Ok(MobileKeyTransferExport {
|
||||||
key: transfer_key_with_kind(&info, kind),
|
key: transfer_key_with_kind(&info, kind),
|
||||||
frames,
|
frames,
|
||||||
@@ -178,13 +194,20 @@ impl MobileKeyTransferService {
|
|||||||
pub fn importer(&self) -> MobileKeyTransferImport {
|
pub fn importer(&self) -> MobileKeyTransferImport {
|
||||||
MobileKeyTransferImport::new(self.config.clone())
|
MobileKeyTransferImport::new(self.config.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn export_visible(&self) -> bool {
|
||||||
|
self.export_deadline
|
||||||
|
.lock()
|
||||||
|
.ok()
|
||||||
|
.is_some_and(|deadline| deadline.is_some_and(|deadline| Instant::now() < deadline))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MobileKeyTransferImport {
|
pub struct MobileKeyTransferImport {
|
||||||
destination: MobileKeyTransferDestination,
|
destination: MobileKeyTransferDestination,
|
||||||
digest: Option<String>,
|
digest: Option<String>,
|
||||||
total: Option<usize>,
|
total: Option<usize>,
|
||||||
chunks: BTreeMap<usize, Vec<u8>>,
|
chunks: BTreeMap<usize, SecretBytes>,
|
||||||
complete: Option<SecretBytes>,
|
complete: Option<SecretBytes>,
|
||||||
key: Option<MobileKeyTransferKey>,
|
key: Option<MobileKeyTransferKey>,
|
||||||
}
|
}
|
||||||
@@ -195,6 +218,31 @@ enum MobileKeyTransferDestination {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MobileKeyTransferImport {
|
impl MobileKeyTransferImport {
|
||||||
|
pub fn add_camera(
|
||||||
|
&mut self,
|
||||||
|
frame: crate::mobile_platform::MobileCameraFrame,
|
||||||
|
rotation_degrees: u32,
|
||||||
|
) -> Result<Option<MobileKeyTransferProgress>, MobileKeyTransferError> {
|
||||||
|
if frame.width > 2048
|
||||||
|
|| frame.height > 2048
|
||||||
|
|| frame.luminance.expose().len() > 4 * 1024 * 1024
|
||||||
|
{
|
||||||
|
return Err(MobileKeyTransferError::InvalidFrame);
|
||||||
|
}
|
||||||
|
match frame.decode_rotated(rotation_degrees) {
|
||||||
|
Ok(payload) => self.add_frame(payload).map(Some),
|
||||||
|
Err(QrError::NotFound) => Ok(None),
|
||||||
|
Err(_) => Err(MobileKeyTransferError::InvalidFrame),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn completed_armor(&self) -> Result<SecretBytes, MobileKeyTransferError> {
|
||||||
|
self.complete
|
||||||
|
.as_ref()
|
||||||
|
.map(|armor| SecretBytes::new(armor.expose().to_vec()))
|
||||||
|
.ok_or(MobileKeyTransferError::IncompleteTransfer)
|
||||||
|
}
|
||||||
|
|
||||||
fn new(config: Config) -> Self {
|
fn new(config: Config) -> Self {
|
||||||
Self {
|
Self {
|
||||||
destination: MobileKeyTransferDestination::Configured(Box::new(config)),
|
destination: MobileKeyTransferDestination::Configured(Box::new(config)),
|
||||||
@@ -230,6 +278,9 @@ impl MobileKeyTransferImport {
|
|||||||
&mut self,
|
&mut self,
|
||||||
payload: SecretBytes,
|
payload: SecretBytes,
|
||||||
) -> Result<MobileKeyTransferProgress, MobileKeyTransferError> {
|
) -> Result<MobileKeyTransferProgress, MobileKeyTransferError> {
|
||||||
|
if payload.expose().len() > MAX_TRANSFER_BYTES {
|
||||||
|
return Err(MobileKeyTransferError::InvalidFrame);
|
||||||
|
}
|
||||||
if self.complete.is_some() {
|
if self.complete.is_some() {
|
||||||
return Err(MobileKeyTransferError::AlreadyComplete);
|
return Err(MobileKeyTransferError::AlreadyComplete);
|
||||||
}
|
}
|
||||||
@@ -251,52 +302,58 @@ impl MobileKeyTransferImport {
|
|||||||
if digest.len() != 64 || !digest.bytes().all(|byte| byte.is_ascii_hexdigit()) {
|
if digest.len() != 64 || !digest.bytes().all(|byte| byte.is_ascii_hexdigit()) {
|
||||||
return Err(MobileKeyTransferError::InvalidFrame);
|
return Err(MobileKeyTransferError::InvalidFrame);
|
||||||
}
|
}
|
||||||
|
let digest = digest.to_ascii_lowercase();
|
||||||
let sequence = parse_positive(fields.next())?;
|
let sequence = parse_positive(fields.next())?;
|
||||||
let total = parse_positive(fields.next())?;
|
let total = parse_positive(fields.next())?;
|
||||||
if sequence > total || total > MAX_TRANSFER_FRAMES {
|
if sequence > total || total > MAX_TRANSFER_FRAMES {
|
||||||
return Err(MobileKeyTransferError::InvalidFrame);
|
return Err(MobileKeyTransferError::InvalidFrame);
|
||||||
}
|
}
|
||||||
let chunk = BASE64URL_NOPAD
|
let encoded = fields.next().ok_or(MobileKeyTransferError::InvalidFrame)?;
|
||||||
.decode(
|
if encoded.len() > FRAME_CHUNK_BYTES.div_ceil(3) * 4 {
|
||||||
fields
|
return Err(MobileKeyTransferError::InvalidFrame);
|
||||||
.next()
|
}
|
||||||
.ok_or(MobileKeyTransferError::InvalidFrame)?
|
let chunk = SecretBytes::new(
|
||||||
.as_bytes(),
|
BASE64URL_NOPAD
|
||||||
)
|
.decode(encoded.as_bytes())
|
||||||
.map_err(|_| MobileKeyTransferError::InvalidFrame)?;
|
.map_err(|_| MobileKeyTransferError::InvalidFrame)?,
|
||||||
if chunk.is_empty() || chunk.len() > FRAME_CHUNK_BYTES {
|
);
|
||||||
|
if chunk.expose().is_empty() || chunk.expose().len() > FRAME_CHUNK_BYTES {
|
||||||
return Err(MobileKeyTransferError::InvalidFrame);
|
return Err(MobileKeyTransferError::InvalidFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.digest.as_deref().is_some_and(|value| value != digest)
|
if self
|
||||||
|
.digest
|
||||||
|
.as_deref()
|
||||||
|
.is_some_and(|value| value != digest.as_str())
|
||||||
|| self.total.is_some_and(|value| value != total)
|
|| self.total.is_some_and(|value| value != total)
|
||||||
{
|
{
|
||||||
return Err(MobileKeyTransferError::MixedTransfers);
|
return Err(MobileKeyTransferError::MixedTransfers);
|
||||||
}
|
}
|
||||||
self.digest
|
self.digest.get_or_insert(digest);
|
||||||
.get_or_insert_with(|| digest.to_ascii_lowercase());
|
|
||||||
self.total.get_or_insert(total);
|
self.total.get_or_insert(total);
|
||||||
if let Some(existing) = self.chunks.get(&sequence) {
|
if let Some(existing) = self.chunks.get(&sequence) {
|
||||||
if existing == &chunk {
|
if existing.expose() == chunk.expose() {
|
||||||
return Ok(self.progress(true));
|
return Ok(self.progress(true));
|
||||||
}
|
}
|
||||||
return Err(MobileKeyTransferError::ConflictingFrame);
|
return Err(MobileKeyTransferError::ConflictingFrame);
|
||||||
}
|
}
|
||||||
self.chunks.insert(sequence, chunk);
|
self.chunks.insert(sequence, chunk);
|
||||||
if self.chunks.len() == total {
|
if self.chunks.len() == total {
|
||||||
let mut armor = Vec::new();
|
let mut armor = zeroize::Zeroizing::new(Vec::new());
|
||||||
for sequence in 1..=total {
|
for sequence in 1..=total {
|
||||||
armor.extend(
|
armor.extend_from_slice(
|
||||||
self.chunks
|
self.chunks
|
||||||
.get(&sequence)
|
.get(&sequence)
|
||||||
.ok_or(MobileKeyTransferError::IncompleteTransfer)?,
|
.ok_or(MobileKeyTransferError::IncompleteTransfer)?
|
||||||
|
.expose(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let actual = HEXLOWER.encode(&Sha256::digest(&armor));
|
let actual = HEXLOWER.encode(&Sha256::digest(armor.as_slice()));
|
||||||
if self.digest.as_deref() != Some(actual.as_str()) {
|
if self.digest.as_deref() != Some(actual.as_str()) {
|
||||||
return Err(MobileKeyTransferError::ChecksumMismatch);
|
return Err(MobileKeyTransferError::ChecksumMismatch);
|
||||||
}
|
}
|
||||||
self.finish(SecretBytes::new(armor))?;
|
self.finish(SecretBytes::new(std::mem::take(&mut *armor)))?;
|
||||||
|
self.chunks.clear();
|
||||||
}
|
}
|
||||||
Ok(self.progress(false))
|
Ok(self.progress(false))
|
||||||
}
|
}
|
||||||
@@ -435,7 +492,11 @@ impl MobileKeyTransferImport {
|
|||||||
|
|
||||||
fn progress(&self, duplicate: bool) -> MobileKeyTransferProgress {
|
fn progress(&self, duplicate: bool) -> MobileKeyTransferProgress {
|
||||||
MobileKeyTransferProgress {
|
MobileKeyTransferProgress {
|
||||||
received: self.chunks.len().max(usize::from(self.complete.is_some())),
|
received: if self.complete.is_some() {
|
||||||
|
self.total.unwrap_or(1)
|
||||||
|
} else {
|
||||||
|
self.chunks.len()
|
||||||
|
},
|
||||||
total: self.total.unwrap_or(1),
|
total: self.total.unwrap_or(1),
|
||||||
duplicate,
|
duplicate,
|
||||||
key: self.key.clone(),
|
key: self.key.clone(),
|
||||||
@@ -576,7 +637,7 @@ fn encode_multipart(
|
|||||||
}
|
}
|
||||||
let digest = HEXLOWER.encode(&Sha256::digest(armor.expose()));
|
let digest = HEXLOWER.encode(&Sha256::digest(armor.expose()));
|
||||||
let total = armor.expose().len().div_ceil(chunk_bytes);
|
let total = armor.expose().len().div_ceil(chunk_bytes);
|
||||||
if total == 0 || total > MAX_TRANSFER_FRAMES {
|
if total == 0 || total > MAX_EXPORT_FRAMES {
|
||||||
return Err(MobileKeyTransferError::QrPayload);
|
return Err(MobileKeyTransferError::QrPayload);
|
||||||
}
|
}
|
||||||
let mut frames = Vec::with_capacity(total);
|
let mut frames = Vec::with_capacity(total);
|
||||||
@@ -706,6 +767,7 @@ mod tests {
|
|||||||
MobileKeyTransferService, encode_multipart, load_keys_or_empty,
|
MobileKeyTransferService, encode_multipart, load_keys_or_empty,
|
||||||
};
|
};
|
||||||
use crate::{config::Config, crypto::KeyStore, repository::SecretBytes};
|
use crate::{config::Config, crypto::KeyStore, repository::SecretBytes};
|
||||||
|
use std::{sync::Mutex, time::Instant};
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
|
||||||
const ALICE_PUBLIC: &[u8] =
|
const ALICE_PUBLIC: &[u8] =
|
||||||
@@ -714,6 +776,89 @@ mod tests {
|
|||||||
include_bytes!("../tests/fixtures/compatibility/keys/alice-secret.asc");
|
include_bytes!("../tests/fixtures/compatibility/keys/alice-secret.asc");
|
||||||
const ALICE_FINGERPRINT: &str = "7E5C5241B25F6FFAAD717EBFA132DCB2DC23AE30";
|
const ALICE_FINGERPRINT: &str = "7E5C5241B25F6FFAAD717EBFA132DCB2DC23AE30";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn export_rejects_oversized_matrix_sets_before_rendering() {
|
||||||
|
assert!(matches!(
|
||||||
|
encode_multipart(SecretBytes::new(vec![0; 257]), 1),
|
||||||
|
Err(MobileKeyTransferError::QrPayload)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn export_visibility_is_bounded_and_does_not_renew_while_reading() {
|
||||||
|
let fixture = configured_secret_key().unwrap();
|
||||||
|
let service = MobileKeyTransferService {
|
||||||
|
keys: load_keys_or_empty(fixture.config.key_material()).unwrap(),
|
||||||
|
config: fixture.config,
|
||||||
|
export_deadline: Mutex::new(None),
|
||||||
|
};
|
||||||
|
assert!(!service.export_visible());
|
||||||
|
service
|
||||||
|
.export(ALICE_FINGERPRINT, MobileKeyTransferKind::Public, None)
|
||||||
|
.unwrap();
|
||||||
|
assert!(service.export_visible());
|
||||||
|
*service.export_deadline.lock().unwrap() = Some(Instant::now());
|
||||||
|
assert!(!service.export_visible());
|
||||||
|
assert!(!service.export_visible());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn camera_multipart_is_exact_duplicate_safe_and_transactional()
|
||||||
|
-> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let fixture = configured_public_key()?;
|
||||||
|
let mut importer = MobileKeyTransferImport::new(fixture.config.clone());
|
||||||
|
let mut frames = encode_multipart(SecretBytes::new(ALICE_SECRET.to_vec()), 128)?;
|
||||||
|
frames.reverse();
|
||||||
|
for (index, frame) in frames.iter().enumerate() {
|
||||||
|
let matrix = frame.matrix();
|
||||||
|
let width = (matrix.width() + 8) * 4;
|
||||||
|
let height = width + 8;
|
||||||
|
let row = width * 2 + 13;
|
||||||
|
let mut pixels = vec![255; height * row];
|
||||||
|
for y in 0..height {
|
||||||
|
for x in 0..width {
|
||||||
|
let dark = x / 4 >= 4
|
||||||
|
&& y / 4 >= 4
|
||||||
|
&& matrix.is_dark(x / 4 - 4, y / 4 - 4).unwrap_or(false);
|
||||||
|
pixels[y * row + x * 2] = if dark { 0 } else { 255 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let camera = || crate::mobile_platform::MobileCameraFrame {
|
||||||
|
width: width as u32,
|
||||||
|
height: height as u32,
|
||||||
|
row_stride: row as u32,
|
||||||
|
pixel_stride: 2,
|
||||||
|
luminance: SecretBytes::new(pixels.clone()),
|
||||||
|
};
|
||||||
|
let progress = importer
|
||||||
|
.add_camera(camera(), [0, 90, 180, 270][index % 4])?
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(progress.received(), index + 1);
|
||||||
|
if index + 1 < frames.len() {
|
||||||
|
assert!(importer.add_camera(camera(), 0)?.unwrap().duplicate());
|
||||||
|
assert_eq!(
|
||||||
|
importer.import(None, true, false),
|
||||||
|
Err(MobileKeyTransferError::IncompleteTransfer)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(importer.completed_armor()?.expose(), ALICE_SECRET);
|
||||||
|
assert_eq!(
|
||||||
|
importer.import(Some(SecretBytes::new(b"wrong".to_vec())), true, false),
|
||||||
|
Err(MobileKeyTransferError::IncorrectPassphrase)
|
||||||
|
);
|
||||||
|
let before = std::fs::read(fixture.key_path.join("alice-public.asc"))?;
|
||||||
|
importer.import(
|
||||||
|
Some(SecretBytes::new(b"fixture-alice-passphrase".to_vec())),
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
assert_eq!(before, ALICE_PUBLIC);
|
||||||
|
let keys = KeyStore::load(fixture.config.key_material())?;
|
||||||
|
assert!(keys.infos().any(|key| key.has_secret()));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn qr_images_reconstruct_the_same_key_and_reject_invalid_images()
|
fn qr_images_reconstruct_the_same_key_and_reject_invalid_images()
|
||||||
-> Result<(), Box<dyn std::error::Error>> {
|
-> Result<(), Box<dyn std::error::Error>> {
|
||||||
@@ -750,8 +895,14 @@ mod tests {
|
|||||||
let mut importer = MobileKeyTransferImport::new(fixture.config);
|
let mut importer = MobileKeyTransferImport::new(fixture.config);
|
||||||
let mut frames = encode_multipart(SecretBytes::new(ALICE_SECRET.to_vec()), 128)?;
|
let mut frames = encode_multipart(SecretBytes::new(ALICE_SECRET.to_vec()), 128)?;
|
||||||
frames.reverse();
|
frames.reverse();
|
||||||
for frame in frames {
|
for (index, frame) in frames.into_iter().enumerate() {
|
||||||
importer.add_frame(SecretBytes::new(frame.payload().to_vec()))?;
|
let mut payload = frame.payload().to_vec();
|
||||||
|
if index % 2 == 0 {
|
||||||
|
for byte in &mut payload[6..70] {
|
||||||
|
byte.make_ascii_uppercase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
importer.add_frame(SecretBytes::new(payload))?;
|
||||||
}
|
}
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
importer.complete.as_ref().map(SecretBytes::expose),
|
importer.complete.as_ref().map(SecretBytes::expose),
|
||||||
@@ -769,6 +920,7 @@ mod tests {
|
|||||||
-> Result<(), Box<dyn std::error::Error>> {
|
-> Result<(), Box<dyn std::error::Error>> {
|
||||||
let fixture = configured_secret_key()?;
|
let fixture = configured_secret_key()?;
|
||||||
let service = MobileKeyTransferService {
|
let service = MobileKeyTransferService {
|
||||||
|
export_deadline: Mutex::new(None),
|
||||||
config: fixture.config.clone(),
|
config: fixture.config.clone(),
|
||||||
keys: KeyStore::load(&fixture.key_path)?,
|
keys: KeyStore::load(&fixture.key_path)?,
|
||||||
};
|
};
|
||||||
@@ -953,6 +1105,7 @@ mod tests {
|
|||||||
let fixture = configured_key("placeholder", b"")?;
|
let fixture = configured_key("placeholder", b"")?;
|
||||||
std::fs::remove_file(fixture.key_path.join("placeholder"))?;
|
std::fs::remove_file(fixture.key_path.join("placeholder"))?;
|
||||||
let service = MobileKeyTransferService {
|
let service = MobileKeyTransferService {
|
||||||
|
export_deadline: Mutex::new(None),
|
||||||
keys: load_keys_or_empty(&fixture.key_path)?,
|
keys: load_keys_or_empty(&fixture.key_path)?,
|
||||||
config: fixture.config.clone(),
|
config: fixture.config.clone(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -163,6 +163,15 @@ impl AndroidOnboarding {
|
|||||||
self.status_unlocked()
|
self.status_unlocked()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn import_scanned(
|
||||||
|
&self,
|
||||||
|
transfer: &crate::mobile_key_transfer::MobileKeyTransferImport,
|
||||||
|
passphrase: Option<SecretBytes>,
|
||||||
|
) -> Result<AndroidOnboardingStatus, crate::mobile_key_transfer::MobileKeyTransferError> {
|
||||||
|
self.import(transfer.completed_armor()?, passphrase)
|
||||||
|
.map_err(crate::mobile_key_transfer::MobileKeyTransferError::LocalSetup)
|
||||||
|
}
|
||||||
|
|
||||||
fn stage_key(
|
fn stage_key(
|
||||||
&self,
|
&self,
|
||||||
fingerprint: &str,
|
fingerprint: &str,
|
||||||
@@ -1052,6 +1061,40 @@ pub(crate) mod tests {
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn scanned_import_stages_exact_key_without_creating_a_store() {
|
||||||
|
use crate::mobile_key_transfer::{MobileKeyTransferError, MobileKeyTransferImport};
|
||||||
|
let temp = tempfile::tempdir().unwrap();
|
||||||
|
let private = storage(temp.path());
|
||||||
|
let backend = Arc::new(Backend::default());
|
||||||
|
let setup = AndroidOnboarding::new(&private, backend).unwrap();
|
||||||
|
let mut transfer = MobileKeyTransferImport::local_setup();
|
||||||
|
assert!(matches!(
|
||||||
|
setup.import_scanned(&transfer, password()),
|
||||||
|
Err(MobileKeyTransferError::IncompleteTransfer)
|
||||||
|
));
|
||||||
|
transfer
|
||||||
|
.add_frame(SecretBytes::new(
|
||||||
|
include_bytes!("../../tests/fixtures/compatibility/keys/alice-secret.asc").to_vec(),
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
assert!(
|
||||||
|
setup
|
||||||
|
.import_scanned(&transfer, Some(SecretBytes::new(b"wrong".to_vec())))
|
||||||
|
.is_err()
|
||||||
|
);
|
||||||
|
assert!(setup.status().unwrap().keys.is_empty());
|
||||||
|
let status = setup.import_scanned(&transfer, password()).unwrap();
|
||||||
|
assert_eq!(status.keys[0].fingerprint().as_str(), ALICE);
|
||||||
|
assert!(!status.configured);
|
||||||
|
assert!(setup.configuration().unwrap().is_none());
|
||||||
|
assert!(matches!(
|
||||||
|
setup.import_scanned(&transfer, password()),
|
||||||
|
Err(MobileKeyTransferError::LocalSetup(_))
|
||||||
|
));
|
||||||
|
assert_eq!(setup.status().unwrap().keys.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn imported_key_restarts_then_creates_a_pass_compatible_local_store() {
|
fn imported_key_restarts_then_creates_a_pass_compatible_local_store() {
|
||||||
let temp = tempfile::tempdir().unwrap();
|
let temp = tempfile::tempdir().unwrap();
|
||||||
|
|||||||
@@ -90,6 +90,10 @@ pub struct MobileCameraFrame {
|
|||||||
|
|
||||||
impl MobileCameraFrame {
|
impl MobileCameraFrame {
|
||||||
pub fn decode(&self) -> Result<SecretBytes, QrError> {
|
pub fn decode(&self) -> Result<SecretBytes, QrError> {
|
||||||
|
self.decode_rotated(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_rotated(&self, rotation_degrees: u32) -> Result<SecretBytes, QrError> {
|
||||||
let width = self.width as usize;
|
let width = self.width as usize;
|
||||||
let height = self.height as usize;
|
let height = self.height as usize;
|
||||||
let row = self.row_stride as usize;
|
let row = self.row_stride as usize;
|
||||||
@@ -99,6 +103,7 @@ impl MobileCameraFrame {
|
|||||||
|| !(1..=4096).contains(&height)
|
|| !(1..=4096).contains(&height)
|
||||||
|| !(1..=4).contains(&pixel)
|
|| !(1..=4).contains(&pixel)
|
||||||
|| bytes.len() > 32 * 1024 * 1024
|
|| bytes.len() > 32 * 1024 * 1024
|
||||||
|
|| !matches!(rotation_degrees, 0 | 90 | 180 | 270)
|
||||||
{
|
{
|
||||||
return Err(QrError::InvalidImage);
|
return Err(QrError::InvalidImage);
|
||||||
}
|
}
|
||||||
@@ -112,7 +117,20 @@ impl MobileCameraFrame {
|
|||||||
if row <= last_column || last >= bytes.len() {
|
if row <= last_column || last >= bytes.len() {
|
||||||
return Err(QrError::InvalidImage);
|
return Err(QrError::InvalidImage);
|
||||||
}
|
}
|
||||||
QrMatrix::decode_luminance(width, height, |x, y| bytes[y * row + x * pixel])
|
let (output_width, output_height) = if matches!(rotation_degrees, 90 | 270) {
|
||||||
|
(height, width)
|
||||||
|
} else {
|
||||||
|
(width, height)
|
||||||
|
};
|
||||||
|
QrMatrix::decode_luminance(output_width, output_height, |x, y| {
|
||||||
|
let (x, y) = match rotation_degrees {
|
||||||
|
90 => (y, height - 1 - x),
|
||||||
|
180 => (width - 1 - x, height - 1 - y),
|
||||||
|
270 => (width - 1 - y, x),
|
||||||
|
_ => (x, y),
|
||||||
|
};
|
||||||
|
bytes[y * row + x * pixel]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,6 +241,61 @@ impl fmt::Debug for MobileCredentialRequest {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn camera_planes_decode_padded_pixels_at_every_orientation() {
|
||||||
|
let payload = SecretBytes::new(b"camera-qr-byte-exact".to_vec());
|
||||||
|
let matrix = QrMatrix::encode(&payload).unwrap();
|
||||||
|
let size = (matrix.width() + 8) * 5;
|
||||||
|
let row = size * 2 + 7;
|
||||||
|
let mut pixels = vec![255; size * row];
|
||||||
|
for y in 0..size {
|
||||||
|
for x in 0..size {
|
||||||
|
let dark = x / 5 >= 4
|
||||||
|
&& y / 5 >= 4
|
||||||
|
&& matrix.is_dark(x / 5 - 4, y / 5 - 4).unwrap_or(false);
|
||||||
|
pixels[y * row + x * 2] = if dark { 0 } else { 255 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for rotation in [0, 90, 180, 270] {
|
||||||
|
let decoded = MobileCameraFrame {
|
||||||
|
luminance: SecretBytes::new(pixels.clone()),
|
||||||
|
width: size as u32,
|
||||||
|
height: size as u32,
|
||||||
|
row_stride: row as u32,
|
||||||
|
pixel_stride: 2,
|
||||||
|
}
|
||||||
|
.decode_rotated(rotation)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(decoded.expose(), payload.expose());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn camera_rejects_truncated_oversized_and_invalid_planes() {
|
||||||
|
for (width, height, row, step, rotation, length) in [
|
||||||
|
(0, 1, 1, 1, 0, 1),
|
||||||
|
(4097, 1, 4097, 1, 0, 4097),
|
||||||
|
(2, 2, 2, 1, 0, 3),
|
||||||
|
(2, 2, 1, 1, 0, 4),
|
||||||
|
(2, 2, 2, 0, 0, 4),
|
||||||
|
(2, 2, 2, 1, 45, 4),
|
||||||
|
(2, 2, u32::MAX, 1, 0, 4),
|
||||||
|
(1, 1, 1, 1, 0, 32 * 1024 * 1024 + 1),
|
||||||
|
] {
|
||||||
|
assert!(matches!(
|
||||||
|
MobileCameraFrame {
|
||||||
|
luminance: SecretBytes::new(vec![255; length]),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
row_stride: row,
|
||||||
|
pixel_stride: step,
|
||||||
|
}
|
||||||
|
.decode_rotated(rotation),
|
||||||
|
Err(QrError::InvalidImage)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn roots_and_caller_facts_are_validated_without_creating_data_or_grants() {
|
fn roots_and_caller_facts_are_validated_without_creating_data_or_grants() {
|
||||||
let paths =
|
let paths =
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# Android GPG QR transfer
|
||||||
|
|
||||||
|
Issue [#106](https://git.rfc1437.de/hugo/IronStorage/issues/106) uses the shared
|
||||||
|
ASCII-armored OpenPGP and `ISKT1` multipart format. `crates/storage` owns frame
|
||||||
|
bounds/orientation, QR decoding, checksum/reassembly, identity, passphrase
|
||||||
|
validation, duplicate handling and transactional key installation. Kotlin only
|
||||||
|
supplies camera facts and renders storage-provided QR matrices.
|
||||||
|
|
||||||
|
## Import and export
|
||||||
|
|
||||||
|
Open Preferences → Import or export GPG QR codes. Scanning requests camera
|
||||||
|
permission, binds CameraX Preview and ImageAnalysis to the Activity lifecycle,
|
||||||
|
and uses only the latest Y plane. Pause closes the camera while retaining the
|
||||||
|
in-memory multipart session; resume opens a fresh camera. Frames can arrive in
|
||||||
|
any order. Duplicate frames leave the received count unchanged. The complete
|
||||||
|
key's Rust-derived identity and fingerprint appear before import. Private import
|
||||||
|
requires a separate fingerprint/security confirmation. Default-key selection
|
||||||
|
and replacement are explicit controls; incorrect passphrases, incomplete,
|
||||||
|
conflicting or mismatched transfers cannot replace valid keys/configuration.
|
||||||
|
|
||||||
|
Onboarding → Import existing GPG key → Scan GPG QR codes uses the same scanner
|
||||||
|
and review, then stages the key through Android's existing onboarding transaction.
|
||||||
|
It does not create a store or bypass the later local/HTTPS setup choice. Public
|
||||||
|
keys cannot become onboarding/default decryption keys; Rust rejects them.
|
||||||
|
|
||||||
|
Export selects a storage-provided key. Private export requires a GPG passphrase
|
||||||
|
and a separate fingerprint/security confirmation. Every displayed export remains
|
||||||
|
labeled with the identity that produced it, even if selection changes. Previous
|
||||||
|
matrices are erased before a new export. Multipart exports support previous/next
|
||||||
|
and optional automatic frame advancement. Brightness and keep-screen-on apply
|
||||||
|
only while QR display is composed and are restored on disposal. Frame ticks do
|
||||||
|
not renew the storage-owned visibility deadline (the configured authentication
|
||||||
|
timeout).
|
||||||
|
|
||||||
|
## Privacy and interruption
|
||||||
|
|
||||||
|
The Activity and transfer dialog use `FLAG_SECURE`. Lock/background/focus loss,
|
||||||
|
process recreation and dismissal remove transfer state, clear Kotlin matrices
|
||||||
|
and inputs, and drop the Rust importer/exporter. Rust multipart chunks and
|
||||||
|
reassembly buffers zeroize on drop. No camera frame, armor or QR payload is
|
||||||
|
written to Android persistence, photos, clipboard, saved instance state or logs.
|
||||||
|
Only an explicitly confirmed successful import persists GPG-compatible keys.
|
||||||
|
|
||||||
|
Camera permission prompts, an external image picker, device rotation and app
|
||||||
|
backgrounding follow the existing fail-closed lifecycle policy: an interrupted
|
||||||
|
transfer is discarded; reopen and rescan rather than retaining private bytes
|
||||||
|
across an OS interruption. A camera pause within the active dialog retains
|
||||||
|
progress. Denial (including permanent denial) presents a settings link and image/
|
||||||
|
manual alternatives. Missing/busy camera reports an actionable recovery message.
|
||||||
|
|
||||||
|
Camera decoding accepts at most 2048 × 2048 pixels and a 4 MiB Y plane, validates
|
||||||
|
row/pixel strides and the four quarter-turn rotations before accessing pixels,
|
||||||
|
and allows one native decode in flight. Kotlin clears the input plane before
|
||||||
|
publishing a completed key to state observers, with a final cleanup on every
|
||||||
|
error/cancellation path. CameraX drops obsolete frames rather
|
||||||
|
than queueing them. Imported `ISKT1` envelopes retain the existing 11,000-frame/
|
||||||
|
17.6 MB armor bound and 1,600-byte chunk bound. Export rejects more than 256
|
||||||
|
frames before allocating matrices, keeping the matrix set below 8 MiB.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
Rust tests use upstream-compatible Alice public/private armor to prove byte-exact
|
||||||
|
single/multipart reconstruction, rotated/padded camera planes, out-of-order and
|
||||||
|
duplicate delivery, incomplete/corrupt/mismatched rejection, wrong-passphrase
|
||||||
|
retention, import rollback, export size bounds and deadline polling without renewal.
|
||||||
|
Native Android settings tests also exercise camera planes through generated UniFFI
|
||||||
|
and verify Kotlin frame bytes and QR matrices are cleared. Compose tests check
|
||||||
|
private import/export confirmation and hidden-input saved-state exclusions.
|
||||||
|
`AndroidQrCameraTest` exercises actual emulator CameraX frame delivery and repeated
|
||||||
|
close/reopen; the preview is clipped in both Android View and Compose layout.
|
||||||
|
|
||||||
|
Build gates include both ARM ABIs, debug/release/AAB, JVM tests, lint/ktlint,
|
||||||
|
architecture/source checks, exact dependency locks/checksums, the license/SBOM
|
||||||
|
gate, every native ELF/APK 16 KB alignment check, and matching FULL release symbols.
|
||||||
|
CameraX 1.6.2 and its exact transitives are reviewed against official Maven POM
|
||||||
|
licenses; camera-core includes Apache-2.0 and BSD-3-Clause portions. The merged
|
||||||
|
manifest removes Media3's unused ACCESS_NETWORK_STATE permission; only CAMERA
|
||||||
|
is added for this feature.
|
||||||
|
|
||||||
|
Validation is emulator-only under the milestone's ARM support policy. The
|
||||||
|
Keystore enrollment/invalidation tests require separate interactive device setup;
|
||||||
|
their setup failures are not camera test results and do not establish biometric
|
||||||
|
coverage for this change.
|
||||||
|
|
||||||
|
Recorded for #106 on 2026-10-12:
|
||||||
|
|
||||||
|
| Environment | Evidence |
|
||||||
|
| --- | --- |
|
||||||
|
| API 26 ARM, 4 KB | Native settings/viewer fixture including private export and relock erasure; 14 bridge tests; app runner OK (32 reported, including four opt-in/biometric methods not enabled); final onboarding/settings regression group 4 passed; CameraX close/reopen passed |
|
||||||
|
| API 37 ARM, strict 16 KB | Native fixture including private export and relock erasure; 14 bridge tests; CameraX close/reopen passed; original app run included both passing QR settings tests |
|
||||||
|
| API 37 ARM, 4 KB, computer use | Update retained existing store/preferences; camera permission interruption discarded transfer; live CameraX preview and clipped scrolling controls inspected; private export stayed disabled until fingerprint confirmation |
|
||||||
|
| Rust 1.97.1 and Android packages | Required workspace gates, androidVerification and release lint, license/SBOM, debug/release manifests/backup exclusions, ARM native alignment and release FULL-symbol checks passed |
|
||||||
|
|
||||||
|
Private export from the retained simulator profile awaits optional user input.
|
||||||
|
Successful private export/import and erasure evidence above uses isolated,
|
||||||
|
encrypted compatibility fixtures rather than a user's passphrase.
|
||||||
@@ -46,9 +46,9 @@ shared core's recipient/signing rules, pass/pass-otp format, HOTP counter safety
|
|||||||
Git failure semantics and secret-redaction requirements remain binding wherever
|
Git failure semantics and secret-redaction requirements remain binding wherever
|
||||||
an Android workflow invokes them; platform presentation may not replace them.
|
an Android workflow invokes them; platform presentation may not replace them.
|
||||||
|
|
||||||
Current iPhone camera adapters pass OS-decoded QR bytes. Android #106/#91 must
|
Current iPhone camera adapters pass OS-decoded QR bytes. Android #106 supplies bounded Y-plane/stride/orientation facts through the
|
||||||
also supply bounded image/frame facts for Rust decoding as required by the
|
shared native contract; storage decodes and reassembles the transfer. See
|
||||||
Android contract; that additional adapter is pending, not an existing API.
|
[key-transfer.md](key-transfer.md) for interruption/security behavior and evidence.
|
||||||
The external-credential matching/grant API required by #109 must be implemented
|
The external-credential matching/grant API required by #109 must be implemented
|
||||||
in storage, rather than copying frontend selection assumptions from AutoFill.
|
in storage, rather than copying frontend selection assumptions from AutoFill.
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ fn manifest_text(source: &str) -> Result<(), Box<dyn Error>> {
|
|||||||
"android.permission.USE_FINGERPRINT",
|
"android.permission.USE_FINGERPRINT",
|
||||||
"de.rfc1437.ironstorage.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION",
|
"de.rfc1437.ironstorage.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION",
|
||||||
"android.permission.INTERNET",
|
"android.permission.INTERNET",
|
||||||
|
"android.permission.CAMERA",
|
||||||
];
|
];
|
||||||
for node in root.children().filter(|node| node.is_element()) {
|
for node in root.children().filter(|node| node.is_element()) {
|
||||||
if node.tag_name().name().starts_with("uses-permission")
|
if node.tag_name().name().starts_with("uses-permission")
|
||||||
@@ -448,6 +449,13 @@ mod tests {
|
|||||||
))
|
))
|
||||||
.is_ok()
|
.is_ok()
|
||||||
);
|
);
|
||||||
|
assert!(
|
||||||
|
manifest_text(&source.replace(
|
||||||
|
"<application",
|
||||||
|
"<uses-permission android:name=\"android.permission.CAMERA\"/><application"
|
||||||
|
))
|
||||||
|
.is_ok()
|
||||||
|
);
|
||||||
for bad in [
|
for bad in [
|
||||||
source.replace("allowBackup=\"false\"", "allowBackup=\"true\""),
|
source.replace("allowBackup=\"false\"", "allowBackup=\"true\""),
|
||||||
source.replace(
|
source.replace(
|
||||||
@@ -456,7 +464,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
source.replace(
|
source.replace(
|
||||||
"<application",
|
"<application",
|
||||||
"<uses-permission android:name=\"android.permission.CAMERA\"/><application",
|
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/><application",
|
||||||
),
|
),
|
||||||
] {
|
] {
|
||||||
assert!(manifest_text(&bad).is_err());
|
assert!(manifest_text(&bad).is_err());
|
||||||
|
|||||||
@@ -191,6 +191,8 @@ fn audit_package_abis(path: &Path, abis: &[&str]) -> Result<(), Box<dyn Error>>
|
|||||||
if ![
|
if ![
|
||||||
"libironstorage_android.so",
|
"libironstorage_android.so",
|
||||||
"libjnidispatch.so",
|
"libjnidispatch.so",
|
||||||
|
"libimage_processing_util_jni.so",
|
||||||
|
"libsurface_util_jni.so",
|
||||||
"libandroidx.graphics.path.so",
|
"libandroidx.graphics.path.so",
|
||||||
]
|
]
|
||||||
.contains(&library)
|
.contains(&library)
|
||||||
|
|||||||
Reference in new issue
Block a user