From 2d5549b0e0bd65b9c8780d72f2c7758a92a8898b Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Fri, 13 Oct 2023 14:36:32 -0700 Subject: [PATCH 01/13] Update versions --- CONTRIBUTING.md | 2 +- build.gradle.kts | 1 - buildSrc/build.gradle.kts | 4 ---- buildSrc/src/main/java/Dependencies.kt | 14 +++++++------- compose-tests/build.gradle.kts | 8 +++++--- .../src/androidTest/AndroidManifest.xml | 3 +-- compose-tests/src/main/AndroidManifest.xml | 2 +- compose-unsupported-tests/build.gradle.kts | 8 +++++--- .../src/androidTest/AndroidManifest.xml | 3 +-- .../src/main/AndroidManifest.xml | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- radiography/build.gradle.kts | 6 ++++-- radiography/src/androidTest/AndroidManifest.xml | 3 +-- radiography/src/main/AndroidManifest.xml | 2 +- .../java/radiography/internal/ComposeViews.kt | 4 ++-- sample-compose/build.gradle.kts | 16 +++++++++------- .../src/androidTest/AndroidManifest.xml | 3 +-- sample-compose/src/main/AndroidManifest.xml | 4 ++-- sample/build.gradle.kts | 6 ++++-- sample/src/androidTest/AndroidManifest.xml | 2 +- sample/src/main/AndroidManifest.xml | 4 ++-- 21 files changed, 50 insertions(+), 49 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7725594..6421043 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ Contributing ============ -If you would like to contribute code to Workflow you can do so through GitHub by +If you would like to contribute code to Radiography you can do so through GitHub by forking the repository and sending a pull request. When submitting code, please make every effort to follow existing conventions diff --git a/build.gradle.kts b/build.gradle.kts index 66bf31f..e8b6c44 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -67,7 +67,6 @@ subprojects { repositories { google() mavenCentral() - jcenter() } apply(plugin = "org.jlleitschuh.gradle.ktlint") diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index ef8bac5..a6217e0 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -5,7 +5,3 @@ plugins { repositories { mavenCentral() } - -kotlinDslPluginOptions { - experimentalWarning.set(false) -} diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index b602cf5..4025872 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -3,15 +3,15 @@ object Versions { * To change this in the IDE, use `systemProp.square.kotlinVersion=x.y.z` in your * `~/.gradle/gradle.properties` file. */ - val KotlinCompiler = System.getProperty("square.kotlinVersion") ?: "1.5.21" + val KotlinCompiler = System.getProperty("square.kotlinVersion") ?: "1.9.10" - const val AndroidXTest = "1.4.0" - const val Compose = "1.0.1" + const val AndroidXTest = "1.5.0" + const val Compose = "1.5.3" } object Dependencies { object Build { - const val Android = "com.android.tools.build:gradle:7.0.0" + const val Android = "com.android.tools.build:gradle:8.1.2" const val MavenPublish = "com.vanniktech:gradle-maven-publish-plugin:0.14.0" val Kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.KotlinCompiler}" const val Ktlint = "org.jlleitschuh.gradle:ktlint-gradle:9.2.1" @@ -24,7 +24,7 @@ object Dependencies { const val Curtains = "com.squareup.curtains:curtains:1.2.2" const val JUnit = "junit:junit:4.13" const val Mockito = "org.mockito:mockito-core:3.11.2" - const val Robolectric = "org.robolectric:robolectric:4.6.1" + const val Robolectric = "org.robolectric:robolectric:4.10.3" const val Truth = "com.google.truth:truth:1.1.3" class Compose(composeVersion: String = Versions.Compose) { @@ -37,9 +37,9 @@ object Dependencies { object InstrumentationTests { const val Core = "androidx.test:core:${Versions.AndroidXTest}" - const val Espresso = "androidx.test.espresso:espresso-core:3.4.0" + const val Espresso = "androidx.test.espresso:espresso-core:3.5.1" const val JUnit = "androidx.test.ext:junit:1.1.3" - const val Orchestrator = "androidx.test:orchestrator:${Versions.AndroidXTest}" + const val Orchestrator = "androidx.test:orchestrator:1.4.2" const val Rules = "androidx.test:rules:${Versions.AndroidXTest}" const val Runner = "androidx.test:runner:${Versions.AndroidXTest}" } diff --git a/compose-tests/build.gradle.kts b/compose-tests/build.gradle.kts index e2878e8..e7089e5 100644 --- a/compose-tests/build.gradle.kts +++ b/compose-tests/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } android { - compileSdk = 30 + compileSdk = 31 compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -15,7 +15,7 @@ android { defaultConfig { minSdk = 21 - targetSdk = 30 + targetSdk = 31 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -28,12 +28,14 @@ android { kotlinCompilerExtensionVersion = Versions.Compose } - packagingOptions { + packaging { resources.excludes += listOf( "META-INF/AL2.0", "META-INF/LGPL2.1", ) } + namespace = "com.squareup.radiography.test.compose.empty" + testNamespace = "com.squareup.radiography.test.compose" } tasks.withType { diff --git a/compose-tests/src/androidTest/AndroidManifest.xml b/compose-tests/src/androidTest/AndroidManifest.xml index 609799b..f8232ee 100644 --- a/compose-tests/src/androidTest/AndroidManifest.xml +++ b/compose-tests/src/androidTest/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/compose-tests/src/main/AndroidManifest.xml b/compose-tests/src/main/AndroidManifest.xml index cee04d2..cc947c5 100644 --- a/compose-tests/src/main/AndroidManifest.xml +++ b/compose-tests/src/main/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/compose-unsupported-tests/build.gradle.kts b/compose-unsupported-tests/build.gradle.kts index 2b65cc0..b0f82f0 100644 --- a/compose-unsupported-tests/build.gradle.kts +++ b/compose-unsupported-tests/build.gradle.kts @@ -14,7 +14,7 @@ val oldComposeVersion = "1.0.1" val oldComposeCompiler = "1.5.21" android { - compileSdk = 30 + compileSdk = 31 compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -23,7 +23,7 @@ android { defaultConfig { minSdk = 21 - targetSdk = 30 + targetSdk = 31 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -36,12 +36,14 @@ android { kotlinCompilerExtensionVersion = oldComposeVersion } - packagingOptions { + packaging { resources.excludes += listOf( "META-INF/AL2.0", "META-INF/LGPL2.1" ) } + namespace = "com.squareup.radiography.test.compose.unsupported.empty" + testNamespace = "com.squareup.radiography.test.compose.unsupported" } tasks.withType { diff --git a/compose-unsupported-tests/src/androidTest/AndroidManifest.xml b/compose-unsupported-tests/src/androidTest/AndroidManifest.xml index 58d7480..2bbf553 100644 --- a/compose-unsupported-tests/src/androidTest/AndroidManifest.xml +++ b/compose-unsupported-tests/src/androidTest/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/compose-unsupported-tests/src/main/AndroidManifest.xml b/compose-unsupported-tests/src/main/AndroidManifest.xml index 4ae2014..cc947c5 100644 --- a/compose-unsupported-tests/src/main/AndroidManifest.xml +++ b/compose-unsupported-tests/src/main/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index af7be50..fce403e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/radiography/build.gradle.kts b/radiography/build.gradle.kts index a08224c..3b57e70 100644 --- a/radiography/build.gradle.kts +++ b/radiography/build.gradle.kts @@ -22,7 +22,7 @@ plugins { } android { - compileSdk = 30 + compileSdk = 31 compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -31,7 +31,7 @@ android { defaultConfig { minSdk = 17 - targetSdk = 30 + targetSdk = 31 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -42,6 +42,8 @@ android { testOptions { execution = "ANDROIDX_TEST_ORCHESTRATOR" } + namespace = "com.squareup.radiography" + testNamespace = "com.squareup.radiography.test" } tasks.withType { diff --git a/radiography/src/androidTest/AndroidManifest.xml b/radiography/src/androidTest/AndroidManifest.xml index 2d02676..f1ee14a 100644 --- a/radiography/src/androidTest/AndroidManifest.xml +++ b/radiography/src/androidTest/AndroidManifest.xml @@ -1,5 +1,4 @@ - + - + diff --git a/radiography/src/main/java/radiography/internal/ComposeViews.kt b/radiography/src/main/java/radiography/internal/ComposeViews.kt index c9f4376..10bfd0d 100644 --- a/radiography/src/main/java/radiography/internal/ComposeViews.kt +++ b/radiography/src/main/java/radiography/internal/ComposeViews.kt @@ -4,7 +4,6 @@ import android.util.SparseArray import android.view.View import androidx.compose.runtime.Composer import androidx.compose.runtime.Composition -import androidx.compose.runtime.InternalComposeApi import androidx.compose.ui.tooling.data.UiToolingDataApi import androidx.compose.ui.tooling.data.asTree import radiography.ExperimentalRadiographyComposeApi @@ -125,8 +124,9 @@ private fun tryGetLayoutInfos(composeView: View): Sequence? { // public (eg LayoutNode), so we'd need to use even more (brittle) reflection to do that parsing. // That said, once Compose is more stable, it might be worth it to read the slot table directly, // since then we could drop the requirement for the Tooling library to be on the classpath. - @OptIn(InternalComposeApi::class, UiToolingDataApi::class) + @OptIn(UiToolingDataApi::class) val rootGroup = composer.compositionData.asTree() + @OptIn(UiToolingDataApi::class) return rootGroup.layoutInfos } diff --git a/sample-compose/build.gradle.kts b/sample-compose/build.gradle.kts index 9a8b000..749d86a 100644 --- a/sample-compose/build.gradle.kts +++ b/sample-compose/build.gradle.kts @@ -6,10 +6,10 @@ plugins { } /** Use a separate property for the sample so we can test with different versions easily. */ -val sampleComposeVersion = "1.0.1" +val sampleComposeVersion = "1.5.3" android { - compileSdk = 30 + compileSdk = 34 compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -18,7 +18,7 @@ android { defaultConfig { minSdk = 21 - targetSdk = 30 + targetSdk = 34 applicationId = "com.squareup.radiography.sample.compose" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -31,10 +31,10 @@ android { kotlinCompilerExtensionVersion = sampleComposeVersion } - lint { - // Workaround lint bug. - disable("InvalidFragmentVersionForActivityResult") - } +// lint { +// // Workaround lint bug. +// disable("InvalidFragmentVersionForActivityResult") +// } packagingOptions { resources.excludes += listOf( @@ -42,6 +42,8 @@ android { "META-INF/LGPL2.1" ) } + namespace = "com.squareup.radiography.sample.compose" + testNamespace = "com.squareup.radiography.sample.compose.test" } tasks.withType { diff --git a/sample-compose/src/androidTest/AndroidManifest.xml b/sample-compose/src/androidTest/AndroidManifest.xml index 696f006..f8232ee 100644 --- a/sample-compose/src/androidTest/AndroidManifest.xml +++ b/sample-compose/src/androidTest/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/sample-compose/src/main/AndroidManifest.xml b/sample-compose/src/main/AndroidManifest.xml index 27ec7ad..b1a3013 100644 --- a/sample-compose/src/main/AndroidManifest.xml +++ b/sample-compose/src/main/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 113d489..16f3e03 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -20,7 +20,7 @@ plugins { } android { - compileSdk = 30 + compileSdk = 31 compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -29,10 +29,12 @@ android { defaultConfig { minSdk = 21 - targetSdk = 30 + targetSdk = 31 applicationId = "com.squareup.radiography.sample" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } + namespace = "com.squareup.radiography.sample" + testNamespace = "com.squareup.radiography.sample.test" } dependencies { diff --git a/sample/src/androidTest/AndroidManifest.xml b/sample/src/androidTest/AndroidManifest.xml index fdf430c..cc947c5 100644 --- a/sample/src/androidTest/AndroidManifest.xml +++ b/sample/src/androidTest/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 59d58be..545f04f 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -13,8 +13,7 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - + From 4144bf51ddb44e08c104221a759b1e5e438e0fe7 Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Fri, 13 Oct 2023 14:36:45 -0700 Subject: [PATCH 02/13] Update API check --- radiography/api/radiography.api | 87 +++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/radiography/api/radiography.api b/radiography/api/radiography.api index 32fbb4b..4fc02ee 100644 --- a/radiography/api/radiography.api +++ b/radiography/api/radiography.api @@ -8,6 +8,7 @@ public abstract interface annotation class radiography/ExperimentalRadiographyCo public final class radiography/Radiography { public static final field INSTANCE Lradiography/Radiography; + public final synthetic fun renderScannableViewTree$radiography_release (Ljava/lang/StringBuilder;Lradiography/ScannableView;Ljava/util/List;Lradiography/ViewFilter;)V public static final fun scan ()Ljava/lang/String; public static final fun scan (Lradiography/ScanScope;)Ljava/lang/String; public static final fun scan (Lradiography/ScanScope;Ljava/util/List;)Ljava/lang/String; @@ -21,6 +22,7 @@ public abstract interface class radiography/ScanScope { public final class radiography/ScanScopes { public static final field AllWindowsScope Lradiography/ScanScope; + public static final field EmptyScope Lradiography/ScanScope; public static final field FocusedWindowScope Lradiography/ScanScope; public static final field INSTANCE Lradiography/ScanScopes; public static final fun composeTestTagScope (Ljava/lang/String;)Lradiography/ScanScope; @@ -58,6 +60,10 @@ public final class radiography/ScannableView$ComposeView : radiography/Scannable public fun toString ()Ljava/lang/String; } +public final class radiography/ScannableViewKt { + public static final fun toScannableView (Lradiography/internal/ComposeLayoutInfo;)Lradiography/ScannableView; +} + public abstract interface class radiography/ViewFilter { public abstract fun matches (Lradiography/ScannableView;)Z } @@ -67,6 +73,7 @@ public final class radiography/ViewFilters { public static final field NoFilter Lradiography/ViewFilter; public static final fun and (Lradiography/ViewFilter;Lradiography/ViewFilter;)Lradiography/ViewFilter; public static final fun androidViewFilterFor (Ljava/lang/Class;Lkotlin/jvm/functions/Function1;)Lradiography/ViewFilter; + public final synthetic fun androidViewFilterFor (Lkotlin/jvm/functions/Function1;)Lradiography/ViewFilter; public static final fun skipComposeTestTagsFilter ([Ljava/lang/String;)Lradiography/ViewFilter; public static final fun skipIdsViewFilter ([I)Lradiography/ViewFilter; } @@ -82,6 +89,10 @@ public final class radiography/ViewStateRenderers { public static final field INSTANCE Lradiography/ViewStateRenderers; public static final field ViewRenderer Lradiography/ViewStateRenderer; public static final fun androidViewStateRendererFor (Ljava/lang/Class;Lkotlin/jvm/functions/Function2;)Lradiography/ViewStateRenderer; + public final synthetic fun androidViewStateRendererFor (Lkotlin/jvm/functions/Function2;)Lradiography/ViewStateRenderer; + public final fun appendTextValue$radiography_release (Lradiography/AttributeAppendable;Ljava/lang/String;Ljava/lang/CharSequence;ZI)V + public static final synthetic fun composeTextRenderer$radiography_release (ZI)Lradiography/ViewStateRenderer; + public static synthetic fun composeTextRenderer$radiography_release$default (ZIILjava/lang/Object;)Lradiography/ViewStateRenderer; public static final fun textViewRenderer ()Lradiography/ViewStateRenderer; public static final fun textViewRenderer (Z)Lradiography/ViewStateRenderer; public static final fun textViewRenderer (ZI)Lradiography/ViewStateRenderer; @@ -93,3 +104,79 @@ public final class radiography/ViewsKt { public static synthetic fun scan$default (Landroid/view/View;Ljava/util/List;Lradiography/ViewFilter;ILjava/lang/Object;)Ljava/lang/String; } +public abstract class radiography/internal/ComposeLayoutInfo { +} + +public final class radiography/internal/ComposeLayoutInfo$AndroidViewInfo : radiography/internal/ComposeLayoutInfo { + public fun (Landroid/view/View;)V + public final fun component1 ()Landroid/view/View; + public final fun copy (Landroid/view/View;)Lradiography/internal/ComposeLayoutInfo$AndroidViewInfo; + public static synthetic fun copy$default (Lradiography/internal/ComposeLayoutInfo$AndroidViewInfo;Landroid/view/View;ILjava/lang/Object;)Lradiography/internal/ComposeLayoutInfo$AndroidViewInfo; + public fun equals (Ljava/lang/Object;)Z + public final fun getView ()Landroid/view/View; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class radiography/internal/ComposeLayoutInfo$LayoutNodeInfo : radiography/internal/ComposeLayoutInfo { + public fun (Ljava/lang/String;Landroidx/compose/ui/unit/IntRect;Ljava/util/List;Lkotlin/sequences/Sequence;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Landroidx/compose/ui/unit/IntRect; + public final fun component3 ()Ljava/util/List; + public final fun component4 ()Lkotlin/sequences/Sequence; + public final fun copy (Ljava/lang/String;Landroidx/compose/ui/unit/IntRect;Ljava/util/List;Lkotlin/sequences/Sequence;)Lradiography/internal/ComposeLayoutInfo$LayoutNodeInfo; + public static synthetic fun copy$default (Lradiography/internal/ComposeLayoutInfo$LayoutNodeInfo;Ljava/lang/String;Landroidx/compose/ui/unit/IntRect;Ljava/util/List;Lkotlin/sequences/Sequence;ILjava/lang/Object;)Lradiography/internal/ComposeLayoutInfo$LayoutNodeInfo; + public fun equals (Ljava/lang/Object;)Z + public final fun getBounds ()Landroidx/compose/ui/unit/IntRect; + public final fun getChildren ()Lkotlin/sequences/Sequence; + public final fun getModifiers ()Ljava/util/List; + public final fun getName ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class radiography/internal/ComposeLayoutInfo$SubcompositionInfo : radiography/internal/ComposeLayoutInfo { + public fun (Ljava/lang/String;Landroidx/compose/ui/unit/IntRect;Lkotlin/sequences/Sequence;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Landroidx/compose/ui/unit/IntRect; + public final fun component3 ()Lkotlin/sequences/Sequence; + public final fun copy (Ljava/lang/String;Landroidx/compose/ui/unit/IntRect;Lkotlin/sequences/Sequence;)Lradiography/internal/ComposeLayoutInfo$SubcompositionInfo; + public static synthetic fun copy$default (Lradiography/internal/ComposeLayoutInfo$SubcompositionInfo;Ljava/lang/String;Landroidx/compose/ui/unit/IntRect;Lkotlin/sequences/Sequence;ILjava/lang/Object;)Lradiography/internal/ComposeLayoutInfo$SubcompositionInfo; + public fun equals (Ljava/lang/Object;)Z + public final fun getBounds ()Landroidx/compose/ui/unit/IntRect; + public final fun getChildren ()Lkotlin/sequences/Sequence; + public final fun getName ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class radiography/internal/ComposeLayoutInfoKt { + public static final fun getLayoutInfos (Landroidx/compose/ui/tooling/data/Group;)Lkotlin/sequences/Sequence; +} + +public final class radiography/internal/ComposeViewsKt { + public static final field COMPOSE_UNSUPPORTED_MESSAGE Ljava/lang/String; + public static final fun composeRenderingError (Ljava/lang/LinkageError;)Lradiography/ScannableView; + public static final fun getComposeScannableViews (Landroid/view/View;)Lkotlin/Pair; + public static final fun getMightBeComposeView (Landroid/view/View;)Z + public static final fun isComposeAvailable ()Z +} + +public final class radiography/internal/CompositionContextsKt { + public static final fun getCompositionContexts (Landroidx/compose/ui/tooling/data/Group;)Lkotlin/sequences/Sequence; + public static final fun tryGetComposers (Landroidx/compose/runtime/CompositionContext;)Ljava/lang/Iterable; +} + +public final class radiography/internal/RenderTreeStringKt { + public static final fun renderTreeString (Ljava/lang/StringBuilder;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V +} + +public final class radiography/internal/SemanticsKt { + public static final fun findTestTags (Lradiography/ScannableView$ComposeView;)Lkotlin/sequences/Sequence; +} + +public final class radiography/internal/StringsKt { + public static final fun ellipsize (Ljava/lang/CharSequence;I)Ljava/lang/CharSequence; + public static final fun formatPixelDimensions (II)Ljava/lang/String; +} + From db07c8f90cf4bceff50ad54f741a85baf436fd05 Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Fri, 13 Oct 2023 16:29:06 -0700 Subject: [PATCH 03/13] fix compose view interop --- buildSrc/src/main/java/Dependencies.kt | 2 +- compose-tests/build.gradle.kts | 4 ++-- .../radiography/test/compose/ComposeViewTest.kt | 1 + compose-unsupported-tests/build.gradle.kts | 11 ++++++----- radiography/build.gradle.kts | 4 ++-- .../radiography/internal/ComposeLayoutInfo.kt | 16 +++++++++------- sample/build.gradle.kts | 4 ++-- 7 files changed, 23 insertions(+), 19 deletions(-) diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 4025872..83c9b29 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -38,7 +38,7 @@ object Dependencies { object InstrumentationTests { const val Core = "androidx.test:core:${Versions.AndroidXTest}" const val Espresso = "androidx.test.espresso:espresso-core:3.5.1" - const val JUnit = "androidx.test.ext:junit:1.1.3" + const val JUnit = "androidx.test.ext:junit:1.1.5" const val Orchestrator = "androidx.test:orchestrator:1.4.2" const val Rules = "androidx.test:rules:${Versions.AndroidXTest}" const val Runner = "androidx.test:runner:${Versions.AndroidXTest}" diff --git a/compose-tests/build.gradle.kts b/compose-tests/build.gradle.kts index e7089e5..b96d2d1 100644 --- a/compose-tests/build.gradle.kts +++ b/compose-tests/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } android { - compileSdk = 31 + compileSdk = 34 compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -15,7 +15,7 @@ android { defaultConfig { minSdk = 21 - targetSdk = 31 + targetSdk = 34 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/compose-tests/src/androidTest/java/radiography/test/compose/ComposeViewTest.kt b/compose-tests/src/androidTest/java/radiography/test/compose/ComposeViewTest.kt index 0804ac1..7499043 100644 --- a/compose-tests/src/androidTest/java/radiography/test/compose/ComposeViewTest.kt +++ b/compose-tests/src/androidTest/java/radiography/test/compose/ComposeViewTest.kt @@ -44,6 +44,7 @@ class ComposeViewTest { assertThat(textComposable.children.asIterable()).isEmpty() } + // Needs fixing @Test fun composeView_children_includes_AndroidView() { composeRule.setContentWithExplicitRoot { Column { diff --git a/compose-unsupported-tests/build.gradle.kts b/compose-unsupported-tests/build.gradle.kts index b0f82f0..29f6eaa 100644 --- a/compose-unsupported-tests/build.gradle.kts +++ b/compose-unsupported-tests/build.gradle.kts @@ -2,7 +2,9 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id("com.android.library") + // Older version of Compose requires an older version of Kotlin. kotlin("android") +// kotlin("android") version "1.5.21" } /** @@ -10,11 +12,9 @@ plugins { * built with unsupported Compose versions. */ val oldComposeVersion = "1.0.1" -// Older version of Compose requires an older version of Kotlin. -val oldComposeCompiler = "1.5.21" android { - compileSdk = 31 + compileSdk = 34 compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -23,7 +23,7 @@ android { defaultConfig { minSdk = 21 - targetSdk = 31 + targetSdk = 34 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -58,10 +58,11 @@ tasks.withType { dependencies { androidTestImplementation(project(":radiography")) androidTestImplementation(Dependencies.AppCompat) - androidTestImplementation(Dependencies.Compose().Activity("1.3.0-alpha02")) + androidTestImplementation(Dependencies.Compose().Activity("1.3.1")) androidTestImplementation(Dependencies.Compose(oldComposeVersion).Material) androidTestImplementation(Dependencies.Compose(oldComposeVersion).Testing) androidTestImplementation(Dependencies.InstrumentationTests.Rules) + androidTestImplementation(Dependencies.InstrumentationTests.JUnit) androidTestImplementation(Dependencies.InstrumentationTests.Runner) androidTestImplementation(Dependencies.Truth) } diff --git a/radiography/build.gradle.kts b/radiography/build.gradle.kts index 3b57e70..28ceb4e 100644 --- a/radiography/build.gradle.kts +++ b/radiography/build.gradle.kts @@ -22,7 +22,7 @@ plugins { } android { - compileSdk = 31 + compileSdk = 34 compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -31,7 +31,7 @@ android { defaultConfig { minSdk = 17 - targetSdk = 31 + targetSdk = 34 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt b/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt index 2288047..84bb18f 100644 --- a/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt +++ b/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt @@ -4,7 +4,9 @@ package radiography.internal import android.view.View import android.view.ViewGroup import androidx.compose.runtime.InternalComposeApi +import androidx.compose.ui.InternalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.node.InteroperableComposeUiNode import androidx.compose.ui.node.Ref import androidx.compose.ui.tooling.data.CallGroup import androidx.compose.ui.tooling.data.Group @@ -125,13 +127,13 @@ private fun Group.subComposedChildren(name: String): Sequence = data.mapNotNull { datum -> - (datum as? Ref<*>) - ?.value - // The concrete type is actually an internal ViewGroup subclass that has all the wiring, but - // ultimately it's still just a ViewGroup so this simple check works. - ?.let { it as? ViewGroup } - ?.let(::AndroidViewInfo) +@OptIn(InternalComposeUiApi::class) +private fun Group.androidViewChildren(): List { + return data.mapNotNull { datum -> + (datum as? InteroperableComposeUiNode) + ?.getInteropView() + ?.let(::AndroidViewInfo) + } } /** diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 16f3e03..99b1543 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -20,7 +20,7 @@ plugins { } android { - compileSdk = 31 + compileSdk = 34 compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -29,7 +29,7 @@ android { defaultConfig { minSdk = 21 - targetSdk = 31 + targetSdk = 34 applicationId = "com.squareup.radiography.sample" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } From 25fd57b4d7156cfb6cd9430f470a6bb7217510bb Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Wed, 18 Oct 2023 08:56:08 -0700 Subject: [PATCH 04/13] Fix semantics --- .../main/java/radiography/ScannableView.kt | 151 ++++++++++-------- .../java/radiography/ViewStateRenderers.kt | 10 +- .../radiography/internal/ComposeLayoutInfo.kt | 57 ++++--- .../java/radiography/internal/ComposeViews.kt | 9 +- 4 files changed, 127 insertions(+), 100 deletions(-) diff --git a/radiography/src/main/java/radiography/ScannableView.kt b/radiography/src/main/java/radiography/ScannableView.kt index 1db841d..2a04d92 100644 --- a/radiography/src/main/java/radiography/ScannableView.kt +++ b/radiography/src/main/java/radiography/ScannableView.kt @@ -3,6 +3,9 @@ package radiography import android.view.View import android.view.ViewGroup import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.SemanticsConfiguration +import androidx.compose.ui.semantics.SemanticsModifier +import androidx.compose.ui.semantics.SemanticsNode import radiography.ScannableView.AndroidView import radiography.ScannableView.ComposeView import radiography.internal.ComposeLayoutInfo @@ -20,87 +23,99 @@ import radiography.internal.mightBeComposeView */ public sealed class ScannableView { - /** The string that be used to identify the type of the view in the rendered output. */ - public abstract val displayName: String + /** The string that be used to identify the type of the view in the rendered output. */ + public abstract val displayName: String - /** The children of this view. */ - public abstract val children: Sequence + /** The children of this view. */ + public abstract val children: Sequence - public class AndroidView(public val view: View) : ScannableView() { - override val displayName: String get() = view::class.java.simpleName - override val children: Sequence = view.scannableChildren() + public class AndroidView(public val view: View) : ScannableView() { + override val displayName: String get() = view::class.java.simpleName + override val children: Sequence = view.scannableChildren() - override fun toString(): String = "${AndroidView::class.java.simpleName}($displayName)" - } + override fun toString(): String = "${AndroidView::class.java.simpleName}($displayName)" + } + + /** + * Represents a group of Composables that make up a logical "view". + * + * @param modifiers The list of [Modifier]s that are currently applied to the Composable. + */ + @ExperimentalRadiographyComposeApi + public class ComposeView( + override val displayName: String, + public val width: Int, + public val height: Int, + public val modifiers: List, + public val semanticsNodes: List, + override val children: Sequence, + ) : ScannableView() { + override fun toString(): String = "${ComposeView::class.java.simpleName}($displayName)" - /** - * Represents a group of Composables that make up a logical "view". - * - * @param modifiers The list of [Modifier]s that are currently applied to the Composable. - */ - @ExperimentalRadiographyComposeApi - public class ComposeView( - override val displayName: String, - public val width: Int, - public val height: Int, - public val modifiers: List, - override val children: Sequence - ) : ScannableView() { - override fun toString(): String = "${ComposeView::class.java.simpleName}($displayName)" - } + public val semanticsConfigurations: List + get() { + return semanticsNodes.map { it.config }.ifEmpty { null } + ?: modifiers + .filterIsInstance() + .map { it.semanticsConfiguration } + } + } - /** - * Indicates that an exception was thrown while rendering part of the tree. - * This should be used for non-fatal errors, when the rest of the tree should still be processed. - * - * By default, exceptions thrown during rendering will abort the entire rendering process, and - * return the error message along with any portion of the tree that was rendered before the - * exception was thrown. - */ - public class ChildRenderingError(private val message: String) : ScannableView() { - override val displayName: String get() = message - override val children: Sequence get() = emptySequence() - } + /** + * Indicates that an exception was thrown while rendering part of the tree. + * This should be used for non-fatal errors, when the rest of the tree should still be processed. + * + * By default, exceptions thrown during rendering will abort the entire rendering process, and + * return the error message along with any portion of the tree that was rendered before the + * exception was thrown. + */ + public class ChildRenderingError(private val message: String) : ScannableView() { + override val displayName: String get() = message + override val children: Sequence get() = emptySequence() + } } -@OptIn(ExperimentalRadiographyComposeApi::class) private fun View.scannableChildren(): Sequence = sequence { - if (mightBeComposeView) { - val (composableViews, parsedComposables) = getComposeScannableViews(this@scannableChildren) - // If unsuccessful, the list will contain a RenderError, so yield it anyway. - yieldAll(composableViews) - if (parsedComposables) { - // Don't visit children ourselves, the compose renderer will have done that. - return@sequence + if (mightBeComposeView) { + val (composableViews, parsedComposables) = getComposeScannableViews(this@scannableChildren) + // If unsuccessful, the list will contain a RenderError, so yield it anyway. + yieldAll(composableViews) + if (parsedComposables) { + // Don't visit children ourselves, the compose renderer will have done that. + return@sequence + } } - } - if (this@scannableChildren !is ViewGroup) return@sequence + if (this@scannableChildren !is ViewGroup) return@sequence - for (i in 0 until childCount) { - // Child may be null, if children were removed by another thread after we captured the child - // count. getChildAt returns null for invalid indices, it doesn't throw. - val view = getChildAt(i) ?: continue - yield(AndroidView(view)) - } + for (i in 0 until childCount) { + // Child may be null, if children were removed by another thread after we captured the child + // count. getChildAt returns null for invalid indices, it doesn't throw. + val view = getChildAt(i) ?: continue + yield(AndroidView(view)) + } } @OptIn(ExperimentalRadiographyComposeApi::class) internal fun ComposeLayoutInfo.toScannableView(): ScannableView = when (val layoutInfo = this) { - is LayoutNodeInfo -> ComposeView( - displayName = layoutInfo.name, - // Can't use width and height properties because we're not targeting 1.8 bytecode. - width = layoutInfo.bounds.run { right - left }, - height = layoutInfo.bounds.run { bottom - top }, - modifiers = layoutInfo.modifiers, - children = layoutInfo.children.map(ComposeLayoutInfo::toScannableView) - ) - is SubcompositionInfo -> ComposeView( - displayName = layoutInfo.name, - width = layoutInfo.bounds.run { right - left }, - height = layoutInfo.bounds.run { bottom - top }, - children = layoutInfo.children.map(ComposeLayoutInfo::toScannableView), - modifiers = emptyList() - ) - is AndroidViewInfo -> AndroidView(layoutInfo.view) + is LayoutNodeInfo -> ComposeView( + displayName = layoutInfo.name, + // Can't use width and height properties because we're not targeting 1.8 bytecode. + width = layoutInfo.bounds.run { right - left }, + height = layoutInfo.bounds.run { bottom - top }, + modifiers = layoutInfo.modifiers, + semanticsNodes = layoutInfo.semanticsNodes, + children = layoutInfo.children.map(ComposeLayoutInfo::toScannableView) + ) + + is SubcompositionInfo -> ComposeView( + displayName = layoutInfo.name, + width = layoutInfo.bounds.run { right - left }, + height = layoutInfo.bounds.run { bottom - top }, + modifiers = emptyList(), + semanticsNodes = emptyList(), + children = layoutInfo.children.map(ComposeLayoutInfo::toScannableView), + ) + + is AndroidViewInfo -> AndroidView(layoutInfo.view) } diff --git a/radiography/src/main/java/radiography/ViewStateRenderers.kt b/radiography/src/main/java/radiography/ViewStateRenderers.kt index fcf4f5b..fa9310f 100644 --- a/radiography/src/main/java/radiography/ViewStateRenderers.kt +++ b/radiography/src/main/java/radiography/ViewStateRenderers.kt @@ -212,19 +212,17 @@ public object ViewStateRenderers { renderTextValue: Boolean = false, textValueMaxLength: Int = Int.MAX_VALUE ): ViewStateRenderer = if (!isComposeAvailable) NoRenderer else ViewStateRenderer { view -> - val semantics = (view as? ComposeView) - ?.modifiers - ?.filterIsInstance() - ?: return@ViewStateRenderer + val semantics = (view as? ComposeView)?.semanticsConfigurations ?: emptyList() + - semantics.mapNotNull { it.semanticsConfiguration.getOrNull(Text)?.joinToString() } + semantics.mapNotNull { it.getOrNull(Text)?.joinToString() } .takeUnless { it.isEmpty() } ?.joinToString(separator = " ") ?.also { appendTextValue(label = "text", it, renderTextValue, textValueMaxLength) } - semantics.mapNotNull { it.semanticsConfiguration.getOrNull(EditableText)?.text } + semantics.mapNotNull { it.getOrNull(EditableText)?.text } .takeUnless { it.isEmpty() } ?.joinToString(separator = " ") ?.also { diff --git a/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt b/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt index 84bb18f..1c3d518 100644 --- a/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt +++ b/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt @@ -3,11 +3,14 @@ package radiography.internal import android.view.View import android.view.ViewGroup -import androidx.compose.runtime.InternalComposeApi import androidx.compose.ui.InternalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.LayoutInfo import androidx.compose.ui.node.InteroperableComposeUiNode import androidx.compose.ui.node.Ref +import androidx.compose.ui.semantics.SemanticsNode +import androidx.compose.ui.semantics.SemanticsOwner +import androidx.compose.ui.semantics.getAllSemanticsNodes import androidx.compose.ui.tooling.data.CallGroup import androidx.compose.ui.tooling.data.Group import androidx.compose.ui.tooling.data.NodeGroup @@ -19,7 +22,7 @@ import radiography.internal.ComposeLayoutInfo.LayoutNodeInfo import radiography.internal.ComposeLayoutInfo.SubcompositionInfo /** - * Information about a Compose `LayoutNode`, extracted from a [Group] tree via [Group.layoutInfos]. + * Information about a Compose `LayoutNode`, extracted from a [Group] tree via [Group.computeLayoutInfos]. * * This is a useful layer of indirection from directly handling Groups because it allows us to * define our own notion of what an atomic unit of "composable" is independently from how Compose @@ -30,10 +33,11 @@ import radiography.internal.ComposeLayoutInfo.SubcompositionInfo */ internal sealed class ComposeLayoutInfo { data class LayoutNodeInfo( - val name: String, - val bounds: IntRect, - val modifiers: List, - val children: Sequence, + val name: String, + val bounds: IntRect, + val modifiers: List, + val children: Sequence, + val semanticsNodes: List, ) : ComposeLayoutInfo() data class SubcompositionInfo( @@ -47,11 +51,6 @@ internal sealed class ComposeLayoutInfo { ) : ComposeLayoutInfo() } -/** - * A sequence that lazily parses [ComposeLayoutInfo]s from a [Group] tree. - */ -internal val Group.layoutInfos: Sequence get() = computeLayoutInfos() - /** * Recursively parses [ComposeLayoutInfo]s from a [Group]. Groups form a tree and can contain different * type of nodes which represent function calls, arbitrary data stored directly in the slot table, @@ -64,37 +63,44 @@ internal val Group.layoutInfos: Sequence get() = computeLayou * to derive the "name" of the [ComposeLayoutInfo]. The other [ComposeLayoutInfo] properties come directly off * [NodeGroup] values. */ -private fun Group.computeLayoutInfos( - parentName: String = "" +internal fun Group.computeLayoutInfos( + parentName: String = "", + semanticsOwner: SemanticsOwner? = null, ): Sequence { val name = parentName.ifBlank { this.name }.orEmpty() // Things that we want to consider children of the current node, but aren't actually child nodes // as reported by Group.children. - val irregularChildren = subComposedChildren(name) + androidViewChildren() + val irregularChildren = subComposedChildren(name, semanticsOwner) + androidViewChildren() // Certain composables produce an internal structure that is hard to read if we report it exactly. // Instead, we use heuristics to recognize subtrees that match certain expected structures and // aggregate them somewhat before reporting. - tryParseSubcomposition(name, irregularChildren) + tryParseSubcomposition(name, irregularChildren, semanticsOwner) ?.let { return it } - tryParseAndroidView(name, irregularChildren) + tryParseAndroidView(name, irregularChildren, semanticsOwner) ?.let { return it } // This is an intermediate group that doesn't represent a LayoutNode, so we flatten by just // reporting its children without reporting a new subtree. if (this !is NodeGroup) { return children.asSequence() - .flatMap { it.computeLayoutInfos(name) } + irregularChildren + .flatMap { it.computeLayoutInfos(name, semanticsOwner) } + irregularChildren } val children = children.asSequence() // This node will "consume" the name, so reset it name to empty for children. - .flatMap { it.computeLayoutInfos() } + .flatMap { it.computeLayoutInfos(semanticsOwner = semanticsOwner) } + + val semanticsId = (this.node as? LayoutInfo)?.semanticsId + val semanticsNodes = semanticsOwner?.getAllSemanticsNodes(mergingEnabled = false) + ?.filter { it.id == semanticsId } + ?: emptyList() val layoutInfo = LayoutNodeInfo( name = name, bounds = box, modifiers = modifierInfo.map { it.modifier }, + semanticsNodes = semanticsNodes, children = children + irregularChildren, ) return sequenceOf(layoutInfo) @@ -106,15 +112,14 @@ private fun Group.computeLayoutInfos( * The compositionData val is marked as internal, and not intended for public consumption. * The returned [SubcompositionInfo]s should be collated by [tryParseSubcomposition]. */ -@OptIn(InternalComposeApi::class) -private fun Group.subComposedChildren(name: String): Sequence = +private fun Group.subComposedChildren(name: String, semanticsOwner: SemanticsOwner?): Sequence = getCompositionContexts() .flatMap { it.tryGetComposers().asSequence() } .map { subcomposer -> SubcompositionInfo( name = name, bounds = box, - children = subcomposer.compositionData.asTree().layoutInfos + children = subcomposer.compositionData.asTree().computeLayoutInfos(semanticsOwner = semanticsOwner) ) } @@ -154,12 +159,13 @@ private fun Group.androidViewChildren(): List { */ private fun Group.tryParseSubcomposition( name: String, - irregularChildren: Sequence + irregularChildren: Sequence, + semanticsOwner: SemanticsOwner? ): Sequence? { if (this.name != "SubcomposeLayout") return null val (subcompositions, regularChildren) = - (children.asSequence().flatMap { it.computeLayoutInfos(name) } + irregularChildren) + (children.asSequence().flatMap { it.computeLayoutInfos(name, semanticsOwner) } + irregularChildren) .partition { it is SubcompositionInfo } .let { // There's no type-safe partition operator so we just cast. @@ -208,13 +214,14 @@ private fun Group.tryParseSubcomposition( */ private fun Group.tryParseAndroidView( name: String, - irregularChildren: Sequence + irregularChildren: Sequence, + semanticsOwner: SemanticsOwner? ): Sequence? { if (this.name != "AndroidView") return null if (this !is CallGroup) return null val (androidViews, regularChildren) = - (children.asSequence().flatMap { it.computeLayoutInfos(name) } + irregularChildren) + (children.asSequence().flatMap { it.computeLayoutInfos(name, semanticsOwner) } + irregularChildren) .partition { it is AndroidViewInfo } .let { // There's no type-safe partition operator so we just cast. diff --git a/radiography/src/main/java/radiography/internal/ComposeViews.kt b/radiography/src/main/java/radiography/internal/ComposeViews.kt index 10bfd0d..5f3313b 100644 --- a/radiography/src/main/java/radiography/internal/ComposeViews.kt +++ b/radiography/src/main/java/radiography/internal/ComposeViews.kt @@ -1,9 +1,12 @@ package radiography.internal +import android.annotation.SuppressLint import android.util.SparseArray import android.view.View import androidx.compose.runtime.Composer import androidx.compose.runtime.Composition +import androidx.compose.ui.node.RootForTest +import androidx.compose.ui.platform.ViewRootForTest import androidx.compose.ui.tooling.data.UiToolingDataApi import androidx.compose.ui.tooling.data.asTree import radiography.ExperimentalRadiographyComposeApi @@ -62,9 +65,11 @@ private val viewKeyedTagsField: Field? by lazy(PUBLICATION) { * the right Compose artifacts aren't on the classpath, or the runtime Compose version is * unsupported, this function will return a [ChildRenderingError] and false. */ +@SuppressLint("VisibleForTests") @OptIn(ExperimentalRadiographyComposeApi::class) internal fun getComposeScannableViews(composeView: View): Pair, Boolean> { var linkageError: LinkageError? = null + val scannableViews = try { tryGetLayoutInfos(composeView) ?.map(ComposeLayoutInfo::toScannableView) @@ -126,8 +131,10 @@ private fun tryGetLayoutInfos(composeView: View): Sequence? { // since then we could drop the requirement for the Tooling library to be on the classpath. @OptIn(UiToolingDataApi::class) val rootGroup = composer.compositionData.asTree() + + val semanticsOwner = (composeView as? RootForTest)?.semanticsOwner @OptIn(UiToolingDataApi::class) - return rootGroup.layoutInfos + return rootGroup.computeLayoutInfos(semanticsOwner = semanticsOwner) } private fun View.getKeyedTags(): SparseArray<*> { From 58311712f4cc38b9bbcedfb9c01cd3bc80aa66ca Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Wed, 18 Oct 2023 10:17:35 -0700 Subject: [PATCH 05/13] Update ktlint --- buildSrc/src/main/java/Dependencies.kt | 2 +- .../main/java/radiography/ScannableView.kt | 154 +++++++++--------- .../java/radiography/ViewStateRenderers.kt | 1 - .../radiography/internal/ComposeLayoutInfo.kt | 2 +- .../java/radiography/internal/ComposeViews.kt | 1 - 5 files changed, 79 insertions(+), 81 deletions(-) diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 83c9b29..42e0a7f 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -14,7 +14,7 @@ object Dependencies { const val Android = "com.android.tools.build:gradle:8.1.2" const val MavenPublish = "com.vanniktech:gradle-maven-publish-plugin:0.14.0" val Kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.KotlinCompiler}" - const val Ktlint = "org.jlleitschuh.gradle:ktlint-gradle:9.2.1" + const val Ktlint = "org.jlleitschuh.gradle:ktlint-gradle:11.6.1" const val BinaryCompatibility = "org.jetbrains.kotlinx:binary-compatibility-validator:0.6.0" const val Dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.5.0" } diff --git a/radiography/src/main/java/radiography/ScannableView.kt b/radiography/src/main/java/radiography/ScannableView.kt index 2a04d92..3ba3bb7 100644 --- a/radiography/src/main/java/radiography/ScannableView.kt +++ b/radiography/src/main/java/radiography/ScannableView.kt @@ -23,99 +23,99 @@ import radiography.internal.mightBeComposeView */ public sealed class ScannableView { - /** The string that be used to identify the type of the view in the rendered output. */ - public abstract val displayName: String + /** The string that be used to identify the type of the view in the rendered output. */ + public abstract val displayName: String - /** The children of this view. */ - public abstract val children: Sequence + /** The children of this view. */ + public abstract val children: Sequence - public class AndroidView(public val view: View) : ScannableView() { - override val displayName: String get() = view::class.java.simpleName - override val children: Sequence = view.scannableChildren() + public class AndroidView(public val view: View) : ScannableView() { + override val displayName: String get() = view::class.java.simpleName + override val children: Sequence = view.scannableChildren() - override fun toString(): String = "${AndroidView::class.java.simpleName}($displayName)" - } + override fun toString(): String = "${AndroidView::class.java.simpleName}($displayName)" + } - /** - * Represents a group of Composables that make up a logical "view". - * - * @param modifiers The list of [Modifier]s that are currently applied to the Composable. - */ - @ExperimentalRadiographyComposeApi - public class ComposeView( - override val displayName: String, - public val width: Int, - public val height: Int, - public val modifiers: List, - public val semanticsNodes: List, - override val children: Sequence, - ) : ScannableView() { - override fun toString(): String = "${ComposeView::class.java.simpleName}($displayName)" + /** + * Represents a group of Composables that make up a logical "view". + * + * @param modifiers The list of [Modifier]s that are currently applied to the Composable. + */ + @ExperimentalRadiographyComposeApi + public class ComposeView( + override val displayName: String, + public val width: Int, + public val height: Int, + public val modifiers: List, + public val semanticsNodes: List, + override val children: Sequence, + ) : ScannableView() { + override fun toString(): String = "${ComposeView::class.java.simpleName}($displayName)" - public val semanticsConfigurations: List - get() { - return semanticsNodes.map { it.config }.ifEmpty { null } - ?: modifiers - .filterIsInstance() - .map { it.semanticsConfiguration } - } - } + public val semanticsConfigurations: List + get() { + return semanticsNodes.map { it.config }.ifEmpty { null } + ?: modifiers + .filterIsInstance() + .map { it.semanticsConfiguration } + } + } - /** - * Indicates that an exception was thrown while rendering part of the tree. - * This should be used for non-fatal errors, when the rest of the tree should still be processed. - * - * By default, exceptions thrown during rendering will abort the entire rendering process, and - * return the error message along with any portion of the tree that was rendered before the - * exception was thrown. - */ - public class ChildRenderingError(private val message: String) : ScannableView() { - override val displayName: String get() = message - override val children: Sequence get() = emptySequence() - } + /** + * Indicates that an exception was thrown while rendering part of the tree. + * This should be used for non-fatal errors, when the rest of the tree should still be processed. + * + * By default, exceptions thrown during rendering will abort the entire rendering process, and + * return the error message along with any portion of the tree that was rendered before the + * exception was thrown. + */ + public class ChildRenderingError(private val message: String) : ScannableView() { + override val displayName: String get() = message + override val children: Sequence get() = emptySequence() + } } private fun View.scannableChildren(): Sequence = sequence { - if (mightBeComposeView) { - val (composableViews, parsedComposables) = getComposeScannableViews(this@scannableChildren) - // If unsuccessful, the list will contain a RenderError, so yield it anyway. - yieldAll(composableViews) - if (parsedComposables) { - // Don't visit children ourselves, the compose renderer will have done that. - return@sequence - } + if (mightBeComposeView) { + val (composableViews, parsedComposables) = getComposeScannableViews(this@scannableChildren) + // If unsuccessful, the list will contain a RenderError, so yield it anyway. + yieldAll(composableViews) + if (parsedComposables) { + // Don't visit children ourselves, the compose renderer will have done that. + return@sequence } + } - if (this@scannableChildren !is ViewGroup) return@sequence + if (this@scannableChildren !is ViewGroup) return@sequence - for (i in 0 until childCount) { - // Child may be null, if children were removed by another thread after we captured the child - // count. getChildAt returns null for invalid indices, it doesn't throw. - val view = getChildAt(i) ?: continue - yield(AndroidView(view)) - } + for (i in 0 until childCount) { + // Child may be null, if children were removed by another thread after we captured the child + // count. getChildAt returns null for invalid indices, it doesn't throw. + val view = getChildAt(i) ?: continue + yield(AndroidView(view)) + } } @OptIn(ExperimentalRadiographyComposeApi::class) internal fun ComposeLayoutInfo.toScannableView(): ScannableView = when (val layoutInfo = this) { - is LayoutNodeInfo -> ComposeView( - displayName = layoutInfo.name, - // Can't use width and height properties because we're not targeting 1.8 bytecode. - width = layoutInfo.bounds.run { right - left }, - height = layoutInfo.bounds.run { bottom - top }, - modifiers = layoutInfo.modifiers, - semanticsNodes = layoutInfo.semanticsNodes, - children = layoutInfo.children.map(ComposeLayoutInfo::toScannableView) - ) + is LayoutNodeInfo -> ComposeView( + displayName = layoutInfo.name, + // Can't use width and height properties because we're not targeting 1.8 bytecode. + width = layoutInfo.bounds.run { right - left }, + height = layoutInfo.bounds.run { bottom - top }, + modifiers = layoutInfo.modifiers, + semanticsNodes = layoutInfo.semanticsNodes, + children = layoutInfo.children.map(ComposeLayoutInfo::toScannableView) + ) - is SubcompositionInfo -> ComposeView( - displayName = layoutInfo.name, - width = layoutInfo.bounds.run { right - left }, - height = layoutInfo.bounds.run { bottom - top }, - modifiers = emptyList(), - semanticsNodes = emptyList(), - children = layoutInfo.children.map(ComposeLayoutInfo::toScannableView), - ) + is SubcompositionInfo -> ComposeView( + displayName = layoutInfo.name, + width = layoutInfo.bounds.run { right - left }, + height = layoutInfo.bounds.run { bottom - top }, + modifiers = emptyList(), + semanticsNodes = emptyList(), + children = layoutInfo.children.map(ComposeLayoutInfo::toScannableView), + ) - is AndroidViewInfo -> AndroidView(layoutInfo.view) + is AndroidViewInfo -> AndroidView(layoutInfo.view) } diff --git a/radiography/src/main/java/radiography/ViewStateRenderers.kt b/radiography/src/main/java/radiography/ViewStateRenderers.kt index fa9310f..55d14fa 100644 --- a/radiography/src/main/java/radiography/ViewStateRenderers.kt +++ b/radiography/src/main/java/radiography/ViewStateRenderers.kt @@ -214,7 +214,6 @@ public object ViewStateRenderers { ): ViewStateRenderer = if (!isComposeAvailable) NoRenderer else ViewStateRenderer { view -> val semantics = (view as? ComposeView)?.semanticsConfigurations ?: emptyList() - semantics.mapNotNull { it.getOrNull(Text)?.joinToString() } .takeUnless { it.isEmpty() } ?.joinToString(separator = " ") diff --git a/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt b/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt index 1c3d518..436b089 100644 --- a/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt +++ b/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt @@ -100,7 +100,7 @@ internal fun Group.computeLayoutInfos( name = name, bounds = box, modifiers = modifierInfo.map { it.modifier }, - semanticsNodes = semanticsNodes, + semanticsNodes = semanticsNodes, children = children + irregularChildren, ) return sequenceOf(layoutInfo) diff --git a/radiography/src/main/java/radiography/internal/ComposeViews.kt b/radiography/src/main/java/radiography/internal/ComposeViews.kt index 5f3313b..65b243d 100644 --- a/radiography/src/main/java/radiography/internal/ComposeViews.kt +++ b/radiography/src/main/java/radiography/internal/ComposeViews.kt @@ -6,7 +6,6 @@ import android.view.View import androidx.compose.runtime.Composer import androidx.compose.runtime.Composition import androidx.compose.ui.node.RootForTest -import androidx.compose.ui.platform.ViewRootForTest import androidx.compose.ui.tooling.data.UiToolingDataApi import androidx.compose.ui.tooling.data.asTree import radiography.ExperimentalRadiographyComposeApi From 3e51e4c773563cc33b7f6b86760765e2bbc64185 Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Wed, 18 Oct 2023 10:23:38 -0700 Subject: [PATCH 06/13] update api file --- radiography/api/radiography.api | 15 ++++++++++----- .../java/radiography/internal/ComposeViews.kt | 1 - 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/radiography/api/radiography.api b/radiography/api/radiography.api index 4fc02ee..44c9f70 100644 --- a/radiography/api/radiography.api +++ b/radiography/api/radiography.api @@ -51,11 +51,13 @@ public final class radiography/ScannableView$ChildRenderingError : radiography/S } public final class radiography/ScannableView$ComposeView : radiography/ScannableView { - public fun (Ljava/lang/String;IILjava/util/List;Lkotlin/sequences/Sequence;)V + public fun (Ljava/lang/String;IILjava/util/List;Ljava/util/List;Lkotlin/sequences/Sequence;)V public fun getChildren ()Lkotlin/sequences/Sequence; public fun getDisplayName ()Ljava/lang/String; public final fun getHeight ()I public final fun getModifiers ()Ljava/util/List; + public final fun getSemanticsConfigurations ()Ljava/util/List; + public final fun getSemanticsNodes ()Ljava/util/List; public final fun getWidth ()I public fun toString ()Ljava/lang/String; } @@ -119,18 +121,20 @@ public final class radiography/internal/ComposeLayoutInfo$AndroidViewInfo : radi } public final class radiography/internal/ComposeLayoutInfo$LayoutNodeInfo : radiography/internal/ComposeLayoutInfo { - public fun (Ljava/lang/String;Landroidx/compose/ui/unit/IntRect;Ljava/util/List;Lkotlin/sequences/Sequence;)V + public fun (Ljava/lang/String;Landroidx/compose/ui/unit/IntRect;Ljava/util/List;Lkotlin/sequences/Sequence;Ljava/util/List;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Landroidx/compose/ui/unit/IntRect; public final fun component3 ()Ljava/util/List; public final fun component4 ()Lkotlin/sequences/Sequence; - public final fun copy (Ljava/lang/String;Landroidx/compose/ui/unit/IntRect;Ljava/util/List;Lkotlin/sequences/Sequence;)Lradiography/internal/ComposeLayoutInfo$LayoutNodeInfo; - public static synthetic fun copy$default (Lradiography/internal/ComposeLayoutInfo$LayoutNodeInfo;Ljava/lang/String;Landroidx/compose/ui/unit/IntRect;Ljava/util/List;Lkotlin/sequences/Sequence;ILjava/lang/Object;)Lradiography/internal/ComposeLayoutInfo$LayoutNodeInfo; + public final fun component5 ()Ljava/util/List; + public final fun copy (Ljava/lang/String;Landroidx/compose/ui/unit/IntRect;Ljava/util/List;Lkotlin/sequences/Sequence;Ljava/util/List;)Lradiography/internal/ComposeLayoutInfo$LayoutNodeInfo; + public static synthetic fun copy$default (Lradiography/internal/ComposeLayoutInfo$LayoutNodeInfo;Ljava/lang/String;Landroidx/compose/ui/unit/IntRect;Ljava/util/List;Lkotlin/sequences/Sequence;Ljava/util/List;ILjava/lang/Object;)Lradiography/internal/ComposeLayoutInfo$LayoutNodeInfo; public fun equals (Ljava/lang/Object;)Z public final fun getBounds ()Landroidx/compose/ui/unit/IntRect; public final fun getChildren ()Lkotlin/sequences/Sequence; public final fun getModifiers ()Ljava/util/List; public final fun getName ()Ljava/lang/String; + public final fun getSemanticsNodes ()Ljava/util/List; public fun hashCode ()I public fun toString ()Ljava/lang/String; } @@ -151,7 +155,8 @@ public final class radiography/internal/ComposeLayoutInfo$SubcompositionInfo : r } public final class radiography/internal/ComposeLayoutInfoKt { - public static final fun getLayoutInfos (Landroidx/compose/ui/tooling/data/Group;)Lkotlin/sequences/Sequence; + public static final fun computeLayoutInfos (Landroidx/compose/ui/tooling/data/Group;Ljava/lang/String;Landroidx/compose/ui/semantics/SemanticsOwner;)Lkotlin/sequences/Sequence; + public static synthetic fun computeLayoutInfos$default (Landroidx/compose/ui/tooling/data/Group;Ljava/lang/String;Landroidx/compose/ui/semantics/SemanticsOwner;ILjava/lang/Object;)Lkotlin/sequences/Sequence; } public final class radiography/internal/ComposeViewsKt { diff --git a/radiography/src/main/java/radiography/internal/ComposeViews.kt b/radiography/src/main/java/radiography/internal/ComposeViews.kt index 65b243d..3f7ff33 100644 --- a/radiography/src/main/java/radiography/internal/ComposeViews.kt +++ b/radiography/src/main/java/radiography/internal/ComposeViews.kt @@ -65,7 +65,6 @@ private val viewKeyedTagsField: Field? by lazy(PUBLICATION) { * unsupported, this function will return a [ChildRenderingError] and false. */ @SuppressLint("VisibleForTests") -@OptIn(ExperimentalRadiographyComposeApi::class) internal fun getComposeScannableViews(composeView: View): Pair, Boolean> { var linkageError: LinkageError? = null From fd21c07b95900fc71145a1fc5bdf8e985896ee0d Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Wed, 18 Oct 2023 10:29:43 -0700 Subject: [PATCH 07/13] clean up --- .../java/radiography/test/compose/ComposeViewTest.kt | 1 - compose-unsupported-tests/build.gradle.kts | 4 +--- sample-compose/build.gradle.kts | 7 +------ 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/compose-tests/src/androidTest/java/radiography/test/compose/ComposeViewTest.kt b/compose-tests/src/androidTest/java/radiography/test/compose/ComposeViewTest.kt index 7499043..0804ac1 100644 --- a/compose-tests/src/androidTest/java/radiography/test/compose/ComposeViewTest.kt +++ b/compose-tests/src/androidTest/java/radiography/test/compose/ComposeViewTest.kt @@ -44,7 +44,6 @@ class ComposeViewTest { assertThat(textComposable.children.asIterable()).isEmpty() } - // Needs fixing @Test fun composeView_children_includes_AndroidView() { composeRule.setContentWithExplicitRoot { Column { diff --git a/compose-unsupported-tests/build.gradle.kts b/compose-unsupported-tests/build.gradle.kts index 29f6eaa..4134648 100644 --- a/compose-unsupported-tests/build.gradle.kts +++ b/compose-unsupported-tests/build.gradle.kts @@ -2,9 +2,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id("com.android.library") - // Older version of Compose requires an older version of Kotlin. kotlin("android") -// kotlin("android") version "1.5.21" } /** @@ -58,7 +56,7 @@ tasks.withType { dependencies { androidTestImplementation(project(":radiography")) androidTestImplementation(Dependencies.AppCompat) - androidTestImplementation(Dependencies.Compose().Activity("1.3.1")) + androidTestImplementation(Dependencies.Compose().Activity("1.3.0-alpha02")) androidTestImplementation(Dependencies.Compose(oldComposeVersion).Material) androidTestImplementation(Dependencies.Compose(oldComposeVersion).Testing) androidTestImplementation(Dependencies.InstrumentationTests.Rules) diff --git a/sample-compose/build.gradle.kts b/sample-compose/build.gradle.kts index 749d86a..6e554ff 100644 --- a/sample-compose/build.gradle.kts +++ b/sample-compose/build.gradle.kts @@ -31,12 +31,7 @@ android { kotlinCompilerExtensionVersion = sampleComposeVersion } -// lint { -// // Workaround lint bug. -// disable("InvalidFragmentVersionForActivityResult") -// } - - packagingOptions { + packaging { resources.excludes += listOf( "META-INF/AL2.0", "META-INF/LGPL2.1" From 9f4fac00c649f98944326164207adf6607f07a27 Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Wed, 18 Oct 2023 10:48:43 -0700 Subject: [PATCH 08/13] Fix scanningHandlesLazyLists test --- .../java/radiography/test/compose/ComposeUiTest.kt | 10 +++++----- .../src/main/java/radiography/internal/ComposeViews.kt | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/compose-tests/src/androidTest/java/radiography/test/compose/ComposeUiTest.kt b/compose-tests/src/androidTest/java/radiography/test/compose/ComposeUiTest.kt index 099d0b4..b2a60a0 100644 --- a/compose-tests/src/androidTest/java/radiography/test/compose/ComposeUiTest.kt +++ b/compose-tests/src/androidTest/java/radiography/test/compose/ComposeUiTest.kt @@ -597,14 +597,14 @@ class ComposeUiTest { """ |CompositionLocalProvider: |${BLANK}CompositionLocalProvider { test-tag:"parent" } - |${BLANK}╰─LazyColumn { test-tag:"list", vertical-scroll-axis-range:"ScrollAxisRange(value=0.0, maxValue=Infinity)" } + |${BLANK}╰─LazyColumn { test-tag:"list", vertical-scroll-axis-range:"ScrollAxisRange(value=0.0, maxValue=0.0)" } |${BLANK} ├─ - |${BLANK} │ ╰─SaveableStateProvider { test-tag:"child:1" } + |${BLANK} │ ╰─SkippableItem { test-tag:"child:1" } |${BLANK} ├─ - |${BLANK} │ ├─SaveableStateProvider { test-tag:"child:2" } - |${BLANK} │ ╰─SaveableStateProvider { test-tag:"child:2 (even)" } + |${BLANK} │ ├─SkippableItem { test-tag:"child:2" } + |${BLANK} │ ╰─SkippableItem { test-tag:"child:2 (even)" } |${BLANK} ╰─ - |${BLANK} ╰─SaveableStateProvider { test-tag:"child:3" } + |${BLANK} ╰─SkippableItem { test-tag:"child:3" } | """.trimMargin() ) diff --git a/radiography/src/main/java/radiography/internal/ComposeViews.kt b/radiography/src/main/java/radiography/internal/ComposeViews.kt index 3f7ff33..61b08fe 100644 --- a/radiography/src/main/java/radiography/internal/ComposeViews.kt +++ b/radiography/src/main/java/radiography/internal/ComposeViews.kt @@ -8,7 +8,6 @@ import androidx.compose.runtime.Composition import androidx.compose.ui.node.RootForTest import androidx.compose.ui.tooling.data.UiToolingDataApi import androidx.compose.ui.tooling.data.asTree -import radiography.ExperimentalRadiographyComposeApi import radiography.ScannableView import radiography.ScannableView.ChildRenderingError import radiography.ScannableView.ComposeView From e8e1a2696012a1118921ce630cd4669413e6c503 Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Mon, 30 Oct 2023 21:02:44 -0700 Subject: [PATCH 09/13] Update changelog, fix "unsupported" tests, add param comment --- CHANGELOG.md | 15 +++++++++++++++ compose-unsupported-tests/build.gradle.kts | 4 ++-- .../radiography/internal/ComposeLayoutInfo.kt | 4 ++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5faa4f7..f01375d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,21 @@ Change Log ========== +Version 3.0.0 +------------- + +_2023-10-30_ + +Compose 1.5 is now supported. Due to breaking API changes within the Compose runtime, this version +is not compatible with earlier versions of Compose. If you need to use an earlier version of Compose, +use a 2.x version of Radiography. + +The ScannableView.ComposeView has a new property, `semanticsConfigurations`, which exposes SemanticsConfiguration objects +from both Modifiers and the new Semantics tree. In newer versions of Compose, SemanticsConfigurations cannot +be read from the Modifier list, and are present only in the Semantics tree, +so if you were previously using the `modifiers` property for this you should switch to +using `semanticsConfigurations` instead. + Version 2.4.1 ------------- diff --git a/compose-unsupported-tests/build.gradle.kts b/compose-unsupported-tests/build.gradle.kts index 4134648..b1fa86b 100644 --- a/compose-unsupported-tests/build.gradle.kts +++ b/compose-unsupported-tests/build.gradle.kts @@ -9,7 +9,7 @@ plugins { * Allows using a different version of Compose to validate that we degrade gracefully on apps * built with unsupported Compose versions. */ -val oldComposeVersion = "1.0.1" +val oldComposeVersion = "1.3.0" android { compileSdk = 34 @@ -31,7 +31,7 @@ android { } composeOptions { - kotlinCompilerExtensionVersion = oldComposeVersion + kotlinCompilerExtensionVersion = Versions.Compose } packaging { diff --git a/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt b/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt index 436b089..94813d0 100644 --- a/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt +++ b/radiography/src/main/java/radiography/internal/ComposeLayoutInfo.kt @@ -65,6 +65,10 @@ internal sealed class ComposeLayoutInfo { */ internal fun Group.computeLayoutInfos( parentName: String = "", + /** + * The semantics owner for this Group. This is used to look up the semantics nodes for each + * layout node. + */ semanticsOwner: SemanticsOwner? = null, ): Sequence { val name = parentName.ifBlank { this.name }.orEmpty() From a63c5d838c8cd29fab6402b03fdf3c102522a15f Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Wed, 1 Nov 2023 11:14:00 -0700 Subject: [PATCH 10/13] Update dokka --- buildSrc/src/main/java/Dependencies.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 42e0a7f..dd7599b 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -16,7 +16,7 @@ object Dependencies { val Kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.KotlinCompiler}" const val Ktlint = "org.jlleitschuh.gradle:ktlint-gradle:11.6.1" const val BinaryCompatibility = "org.jetbrains.kotlinx:binary-compatibility-validator:0.6.0" - const val Dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.5.0" + const val Dokka = "org.jetbrains.dokka:dokka-gradle-plugin:1.9.10" } const val AppCompat = "androidx.appcompat:appcompat:1.3.1" From 49f2d0729908441874b1fbd84d7239788772e031 Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Wed, 1 Nov 2023 11:15:04 -0700 Subject: [PATCH 11/13] Run github workflows on jdk 17 --- .github/workflows/android.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 7c2f7d9..ab08785 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -13,10 +13,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: set up JDK 11 + - name: set up JDK 17 uses: actions/setup-java@v1 with: - java-version: 11 + java-version: 17 - name: Build with Gradle run: ./gradlew build @@ -36,10 +36,10 @@ jobs: - 30 steps: - uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v1 with: - java-version: 11 + java-version: 17 - name: Instrumentation Tests uses: reactivecircus/android-emulator-runner@v2 From bd33a63b9ea0c14261b61fc4d05529078bb6873c Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Wed, 1 Nov 2023 11:39:31 -0700 Subject: [PATCH 12/13] Fix sample --- .../java/com/squareup/radiography/sample/MainActivity.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sample/src/main/java/com/squareup/radiography/sample/MainActivity.kt b/sample/src/main/java/com/squareup/radiography/sample/MainActivity.kt index 543248b..2c7146e 100644 --- a/sample/src/main/java/com/squareup/radiography/sample/MainActivity.kt +++ b/sample/src/main/java/com/squareup/radiography/sample/MainActivity.kt @@ -11,6 +11,7 @@ import android.widget.LinearLayout import android.widget.TextView import radiography.Radiography import radiography.ScanScopes.FocusedWindowScope +import radiography.ScannableView import radiography.ViewFilters.skipIdsViewFilter import radiography.ViewStateRenderers import radiography.ViewStateRenderers.DefaultsIncludingPii @@ -44,7 +45,9 @@ class MainActivity : Activity() { "Focused window and custom filter" to { Radiography.scan( scanScope = FocusedWindowScope, - viewFilter = { it !is LinearLayout } + viewFilter = { + (it as? ScannableView.AndroidView)?.view !is LinearLayout + } ) }, "Include PII" to { From a94ab3e0eceeeade49e8f4a65fc0d9daa800bd83 Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Wed, 1 Nov 2023 12:25:32 -0700 Subject: [PATCH 13/13] Fix cast warnings --- radiography/src/test/java/radiography/RadiographyTest.kt | 4 +++- .../squareup/radiography/sample/compose/ComposeSampleApp.kt | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/radiography/src/test/java/radiography/RadiographyTest.kt b/radiography/src/test/java/radiography/RadiographyTest.kt index 612f71e..e492b91 100644 --- a/radiography/src/test/java/radiography/RadiographyTest.kt +++ b/radiography/src/test/java/radiography/RadiographyTest.kt @@ -141,7 +141,9 @@ internal class RadiographyTest { }) layout.addView(EditText(context)) - val filter = skipIdsViewFilter(42) and ViewFilter { it !is EditText } + val filter = skipIdsViewFilter(42) and ViewFilter { + (it as? AndroidView)?.view !is EditText + } layout.scan(viewFilter = filter) .also { assertThat(it).contains("CheckBox") diff --git a/sample-compose/src/main/java/com/squareup/radiography/sample/compose/ComposeSampleApp.kt b/sample-compose/src/main/java/com/squareup/radiography/sample/compose/ComposeSampleApp.kt index 96b938a..7af5332 100644 --- a/sample-compose/src/main/java/com/squareup/radiography/sample/compose/ComposeSampleApp.kt +++ b/sample-compose/src/main/java/com/squareup/radiography/sample/compose/ComposeSampleApp.kt @@ -43,6 +43,7 @@ import androidx.compose.ui.viewinterop.AndroidView import radiography.ExperimentalRadiographyComposeApi import radiography.Radiography import radiography.ScanScopes.FocusedWindowScope +import radiography.ScannableView import radiography.ViewFilters.skipComposeTestTagsFilter import radiography.ViewStateRenderers.CheckableRenderer import radiography.ViewStateRenderers.DefaultsIncludingPii @@ -157,7 +158,8 @@ private fun showSelectionDialog(context: Context) { "Focused window and custom filter" to { Radiography.scan( scanScope = FocusedWindowScope, - viewFilter = { view -> view !is LinearLayout } + viewFilter = { view -> + (view as? ScannableView.AndroidView)?.view !is LinearLayout } ) }, "Include PII" to {