Adding AndroidCraneViewTest with autofill tests
Bug: 139314168
Test: Ran the tests on emulators for API levels < 26 and > 26.
Change-Id: Ia388e448ffb1106e33a958a37f681e748dc67d5b
diff --git a/ui/ui-material/build.gradle b/ui/ui-material/build.gradle
index a6cacda..00174b8 100644
--- a/ui/ui-material/build.gradle
+++ b/ui/ui-material/build.gradle
@@ -55,6 +55,7 @@
androidTestImplementation project(":ui:ui-material:integration-tests:samples")
androidTestImplementation project(":ui:ui-test")
+ androidTestApi project(":ui:ui-platform")
androidTestImplementation(ANDROIDX_TEST_RULES)
androidTestImplementation(ANDROIDX_TEST_RUNNER)
diff --git a/ui/ui-platform/build.gradle b/ui/ui-platform/build.gradle
index 651fc72..f0f2b38 100644
--- a/ui/ui-platform/build.gradle
+++ b/ui/ui-platform/build.gradle
@@ -40,22 +40,27 @@
testImplementation(ANDROIDX_TEST_RULES)
testImplementation(ANDROIDX_TEST_RUNNER)
testImplementation(JUNIT)
+ testImplementation(ROBOLECTRIC)
testImplementation(MOCKITO_CORE)
testImplementation(TRUTH)
testImplementation MOCKITO_KOTLIN, {
exclude group: 'org.mockito' // to keep control on the mockito version
}
+ testImplementation project(":ui:ui-test")
+
androidTestImplementation(ANDROIDX_TEST_RULES)
androidTestImplementation(ANDROIDX_TEST_RUNNER)
androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation(JUNIT)
+ androidTestImplementation(TRUTH)
androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation MOCKITO_KOTLIN, {
exclude group: 'org.mockito' // to keep control on the mockito version
}
- implementation "androidx.core:core:1.0.0"
+ androidTestImplementation project(":ui:ui-test")
+
}
androidx {
@@ -66,3 +71,11 @@
inceptionYear = "2019"
description = "Contains internal implementation that allows separation of android implementation from host-side tests."
}
+
+android {
+ testOptions {
+ unitTests {
+ includeAndroidResources = true
+ }
+ }
+}
diff --git a/ui/ui-platform/src/androidTest/AndroidManifest.xml b/ui/ui-platform/src/androidTest/AndroidManifest.xml
index f086f11..ce716e4 100644
--- a/ui/ui-platform/src/androidTest/AndroidManifest.xml
+++ b/ui/ui-platform/src/androidTest/AndroidManifest.xml
@@ -14,9 +14,9 @@
limitations under the License.
-->
<manifest package="androidx.ui.platform" xmlns:android="http://schemas.android.com/apk/res/android">
-
<application>
- <activity android:name="androidx.ui.platform.test.TestActivity" android:theme="@android:style/Theme.Material.NoActionBar.Fullscreen"/>
+ <activity android:name="android.app.Activity"
+ android:theme="@android:style/Theme.Material.NoActionBar.Fullscreen"/>
</application>
</manifest>
diff --git a/ui/ui-platform/src/androidTest/java/androidx/ui/core/AndroidCraneViewTest.kt b/ui/ui-platform/src/androidTest/java/androidx/ui/core/AndroidCraneViewTest.kt
new file mode 100644
index 0000000..09cec49
--- /dev/null
+++ b/ui/ui-platform/src/androidTest/java/androidx/ui/core/AndroidCraneViewTest.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui.core
+
+import android.app.Activity
+import android.graphics.Rect
+import android.util.SparseArray
+import android.view.View
+import android.view.ViewStructure
+import android.view.autofill.AutofillValue
+import androidx.test.filters.SdkSuppress
+import androidx.test.rule.ActivityTestRule
+import androidx.ui.autofill.AndroidAutofill
+import androidx.ui.autofill.AutofillNode
+import androidx.ui.autofill.AutofillType
+import androidx.ui.test.android.fake.FakeViewStructure
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+class AndroidCraneViewTest {
+ @get:Rule
+ val activityTestRule = ActivityTestRule<Activity>(Activity::class.java)
+
+ private val PACKAGE_NAME = "androidx.ui.platform.test"
+ private lateinit var craneView: AndroidCraneView
+
+ @Before
+ fun setup() {
+ craneView = AndroidCraneView(activityTestRule.activity)
+ }
+
+ @SdkSuppress(maxSdkVersion = 25)
+ @Test
+ fun autofillAmbient_belowApi26_isNull() {
+ assertThat(craneView.autofill).isNull()
+ }
+
+ @SdkSuppress(minSdkVersion = 26)
+ @Test
+ fun autofillAmbient_isNotNull() {
+ assertThat(craneView.autofill).isNotNull()
+ }
+
+ @SdkSuppress(minSdkVersion = 26)
+ @Test
+ fun autofillAmbient_returnsAnInstanceOfAndroidAutofill() {
+ assertThat(craneView.autofill).isInstanceOf(AndroidAutofill::class.java)
+ }
+
+ @SdkSuppress(minSdkVersion = 26)
+ @Test
+ fun onProvideAutofillVirtualStructure_populatesViewStructure() {
+ // Arrange.
+ val viewStructure: ViewStructure = FakeViewStructure()
+ val autofillNode = AutofillNode(
+ >
+ autofillTypes = listOf(AutofillType.Name),
+ boundingBox = Rect(0, 0, 0, 0)
+ )
+ craneView.autofillTree += autofillNode
+
+ // Act.
+ craneView.onProvideAutofillVirtualStructure(viewStructure, 0)
+
+ // Assert.
+ assertThat(viewStructure).isEqualTo(FakeViewStructure().apply {
+ children.add(FakeViewStructure().apply {
+ virtualId = autofillNode.id
+ packageName = PACKAGE_NAME
+ setAutofillType(View.AUTOFILL_TYPE_TEXT)
+ setAutofillHints(arrayOf(View.AUTOFILL_HINT_NAME))
+ setDimens(0, 0, 0, 0, 0, 0)
+ })
+ })
+ }
+
+ @SdkSuppress(minSdkVersion = 26)
+ @Test
+ fun autofill_triggersOnFill() {
+ // Arrange.
+ val expectedValue = "Name"
+ var autofilledValue = ""
+ val autofillNode = AutofillNode(
+ autofilledValue = it },
+ autofillTypes = listOf(AutofillType.Name),
+ boundingBox = Rect(0, 0, 0, 0)
+ )
+ val autofillValues = SparseArray<AutofillValue>().apply {
+ append(autofillNode.id, AutofillValue.forText(expectedValue))
+ }
+ craneView.autofillTree += autofillNode
+
+ // Act.
+ craneView.autofill(autofillValues)
+
+ // Assert.
+ assertThat(autofilledValue).isEqualTo(expectedValue)
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt b/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt
index 456c958..fe51144 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt
@@ -81,8 +81,8 @@
// Map from model to LayoutNodes that *only* need layout and not measure
private val relayoutOnly = ObserverMap<Any, LayoutNode>()
- // TODO: Replace with SemanticsTree.
- // This is a temporary hack until we have a semantics tree implemented.
+ // Used by components that want to provide autofill semantic information.
+ // TODO: Replace with SemanticsTree: Temporary hack until we have a semantics tree implemented.
val autofillTree = AutofillTree()
// RepaintBoundaryNodes that have had their boundary changed. When using Views,
@@ -101,7 +101,7 @@
var constraints = Constraints.tightConstraints(width = IntPx.Zero, height = IntPx.Zero)
// TODO(mount): reinstate when coroutines are supported by IR compiler
-// private val ownerScope = CoroutineScope(Dispatchers.Main.immediate + Job())
+ // private val ownerScope = CoroutineScope(Dispatchers.Main.immediate + Job())
// Used for tracking which nodes a frame read is applied to
internal var currentNode: ComponentNode? = null
@@ -112,6 +112,8 @@
var configurationChangeObserver: () -> Unit = {}
private val _autofill = if (autofillSupported()) AndroidAutofill(this, autofillTree) else null
+
+ // Used as an ambient for performing autofill.
val autofill: Autofill? get() = _autofill
override var measureIteration: Long = 1L
@@ -179,17 +181,17 @@
override fun onInvalidate(drawNode: DrawNode) {
// TODO(mount): use ownerScope. This isn't supported by IR compiler yet
-// ownerScope.launch {
+ // ownerScope.launch {
invalidateRepaintBoundary(drawNode)
-// }
+ // }
}
override fun onSizeChange(layoutNode: LayoutNode) {
// TODO(mount): use ownerScope. This isn't supported by IR compiler yet
-// ownerScope.launch {
+ // ownerScope.launch {
layoutNode.visitChildren(::collectChildrenRepaintBoundaries)
invalidateRepaintBoundary(layoutNode)
-// }
+ // }
}
/**
@@ -213,9 +215,9 @@
override fun onPositionChange(layoutNode: LayoutNode) {
// TODO(mount): use ownerScope. This isn't supported by IR compiler yet
-// ownerScope.launch {
+ // ownerScope.launch {
invalidateRepaintBoundary(layoutNode)
-// }
+ // }
}
override fun onRepaintBoundaryParamsChange(repaintBoundaryNode: RepaintBoundaryNode) {
diff --git a/ui/ui-platform/src/test/java/androidx/ui/ComposeUiRobolectricTestRunner.kt b/ui/ui-platform/src/test/java/androidx/ui/ComposeUiRobolectricTestRunner.kt
new file mode 100644
index 0000000..32f660f
--- /dev/null
+++ b/ui/ui-platform/src/test/java/androidx/ui/ComposeUiRobolectricTestRunner.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui
+
+import org.junit.runners.model.FrameworkMethod
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.internal.bytecode.InstrumentationConfiguration
+
+/**
+ * A [RobolectricTestRunner] for [androidx.ui].
+ *
+ * It has instrumentation turned off for the [androidx.ui] package.
+ *
+ * Robolectric tries to instrument Kotlin classes, and it throws errors when it encounters
+ * companion objects and constructors with default values for parameters. We don't need
+ * shadowing of our classes because we want to use the actual objects in our tests.
+ *
+ * We can also make the argument that no external developer should shadow any of androidx.ui, as
+ * they shouldn't be testing library code. This concern is being tracked by b/139828620 which will
+ * make a change to Robolectric code to prevent instrumentation of all classes under [androidx.ui].
+ */
+class ComposeUiRobolectricTestRunner(testClass: Class<*>) : RobolectricTestRunner(testClass) {
+ override fun createClassLoaderConfig(method: FrameworkMethod?): InstrumentationConfiguration {
+ val builder = InstrumentationConfiguration.Builder(super.createClassLoaderConfig(method))
+ builder.doNotInstrumentPackage("androidx.ui")
+ return builder.build()
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidAutofillTest.kt b/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidAutofillTest.kt
index a135080..553974f 100644
--- a/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidAutofillTest.kt
+++ b/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidAutofillTest.kt
@@ -16,65 +16,72 @@
package androidx.ui.autofill
-import android.content.Context
+import android.app.Activity
import android.graphics.Rect
import android.view.View
import android.view.autofill.AutofillManager
import androidx.test.filters.SmallTest
-import com.nhaarman.mockitokotlin2.eq
-import com.nhaarman.mockitokotlin2.mock
-import com.nhaarman.mockitokotlin2.whenever
-import com.nhaarman.mockitokotlin2.times
-import com.nhaarman.mockitokotlin2.verify
+import androidx.ui.ComposeUiRobolectricTestRunner
+import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
+import org.robolectric.Robolectric
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.Implementation
+import org.robolectric.annotation.Implements
+import org.robolectric.shadow.api.Shadow
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(ComposeUiRobolectricTestRunner::class)
+@Config(
+ manifest = Config.NONE,
+ shadows = [ShadowAutofillManager::class],
+ minSdk = 26
+)
class AndroidAutofillTest {
@get:Rule
val expectedException = ExpectedException.none()!!
private lateinit var androidAutofill: AndroidAutofill
- private lateinit var autofillManager: AutofillManager
+ private lateinit var autofillManager: ShadowAutofillManager
private lateinit var view: View
private val autofillTree = AutofillTree()
@Before
fun setup() {
- autofillManager = mock()
+ val activity = Robolectric.setupActivity(Activity::class.java)
+ view = View(activity)
+ activity.setContentView(view)
- val context: Context = mock()
- whenever(context.getSystemService(eq(AutofillManager::class.java)))
- .thenReturn(autofillManager)
-
- view = mock()
- whenever(view.context).thenReturn(context)
+ autofillManager = Shadow.extract<ShadowAutofillManager>(
+ activity.getSystemService(AutofillManager::class.java)
+ )
androidAutofill = AndroidAutofill(view, autofillTree)
}
@Test
fun importantForAutofill_is_yes() {
- verify(view).setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_YES)
+ assertThat(view.importantForAutofill).isEqualTo(View.IMPORTANT_FOR_AUTOFILL_YES)
}
@Test
fun requestAutofillForNode_calls_notifyViewEntered() {
// Arrange.
- val autofillNode = AutofillNode( boundingBox = Rect(0, 0, 0, 0))
+ val bounds = Rect(0, 0, 0, 0)
+ val autofillNode = AutofillNode( boundingBox = bounds)
// Act.
androidAutofill.requestAutofillForNode(autofillNode)
// Assert.
- verify(autofillManager, times(1))
- .notifyViewEntered(view, autofillNode.id, autofillNode.boundingBox!!)
+ assertThat(autofillManager.viewEnteredStats).containsExactly(
+ ShadowAutofillManager.NotifyViewEntered(view, autofillNode.id, bounds)
+ )
}
@Test
@@ -98,6 +105,27 @@
androidAutofill.cancelAutofillForNode(autofillNode)
// Assert.
- verify(autofillManager, times(1)).notifyViewExited(view, autofillNode.id)
+ assertThat(autofillManager.viewExitedStats).containsExactly(
+ ShadowAutofillManager.NotifyViewExited(view, autofillNode.id)
+ )
+ }
+}
+
+@Implements(value = AutofillManager::class, minSdk = 26)
+internal class ShadowAutofillManager {
+ data class NotifyViewEntered(val view: View, val virtualId: Int, val rect: Rect)
+ data class NotifyViewExited(val view: View, val virtualId: Int)
+
+ val viewEnteredStats = mutableListOf<NotifyViewEntered>()
+ val viewExitedStats = mutableListOf<NotifyViewExited>()
+
+ @Implementation
+ fun notifyViewEntered(view: View, virtualId: Int, rect: Rect) {
+ viewEnteredStats += NotifyViewEntered(view, virtualId, rect)
+ }
+
+ @Implementation
+ fun notifyViewExited(view: View, virtualId: Int) {
+ viewExitedStats += NotifyViewExited(view, virtualId)
}
}
\ No newline at end of file
diff --git a/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidPerformAutofillTest.kt b/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidPerformAutofillTest.kt
index 6acec9c..f559223 100644
--- a/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidPerformAutofillTest.kt
+++ b/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidPerformAutofillTest.kt
@@ -16,38 +16,34 @@
package androidx.ui.autofill
-import android.content.Context
+import android.app.Activity
import android.graphics.Rect
+import android.util.SparseArray
import android.view.View
-import android.view.autofill.AutofillManager
import android.view.autofill.AutofillValue
import androidx.test.filters.SmallTest
-import com.nhaarman.mockitokotlin2.eq
-import com.nhaarman.mockitokotlin2.mock
-import com.nhaarman.mockitokotlin2.times
-import com.nhaarman.mockitokotlin2.verify
-import com.nhaarman.mockitokotlin2.whenever
+import androidx.ui.ComposeUiRobolectricTestRunner
+import com.google.common.truth.Truth
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
+import org.robolectric.Robolectric
+import org.robolectric.annotation.Config
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(ComposeUiRobolectricTestRunner::class)
+@Config(
+ manifest = Config.NONE,
+ minSdk = 26)
class AndroidPerformAutofillTest {
private val autofillTree = AutofillTree()
private lateinit var androidAutofill: AndroidAutofill
@Before
fun setup() {
- val autofillManager: AutofillManager = mock()
-
- val context: Context = mock()
- whenever(context.getSystemService(eq(AutofillManager::class.java)))
- .thenReturn(autofillManager)
-
- val view: View = mock()
- whenever(view.context).thenReturn(context)
+ val activity = Robolectric.setupActivity(Activity::class.java)
+ val view = View(activity)
+ activity.setContentView(view)
androidAutofill = AndroidAutofill(view, autofillTree)
}
@@ -55,48 +51,44 @@
@Test
fun performAutofill_name() {
// Arrange.
- val onFill: (String) -> Unit = mock()
+ val expectedValue = "First Name"
+ var autofilledValue = ""
val autofillNode = AutofillNode(
- >
+ autofilledValue = it },
autofillTypes = listOf(AutofillType.Name),
boundingBox = Rect(0, 0, 0, 0)
)
autofillTree += autofillNode
- val autofillValue: AutofillValue = mock()
- whenever(autofillValue.isText).thenReturn(true)
- whenever(autofillValue.textValue).thenReturn("First Name")
-
- val autofillValues = FakeSparseArray().apply { append(autofillNode.id, autofillValue) }
+ val autofillValues = SparseArray<AutofillValue>()
+ .apply { append(autofillNode.id, AutofillValue.forText(expectedValue)) }
// Act.
androidAutofill.performAutofill(autofillValues)
// Assert.
- verify(onFill, times(1)).invoke("First Name")
+ Truth.assertThat(autofilledValue).isEqualTo(expectedValue)
}
@Test
fun performAutofill_email() {
// Arrange.
- val onFill: (String) -> Unit = mock()
+ val expectedValue = "email@google.com"
+ var autofilledValue = ""
val autofillNode = AutofillNode(
- >
+ autofilledValue = it },
autofillTypes = listOf(AutofillType.EmailAddress),
boundingBox = Rect(0, 0, 0, 0)
)
autofillTree += autofillNode
- val autofillValue: AutofillValue = mock()
- whenever(autofillValue.isText).thenReturn(true)
- whenever(autofillValue.textValue).thenReturn("email@google.com")
-
- val autofillValues = FakeSparseArray().apply { append(autofillNode.id, autofillValue) }
+ val autofillValues = SparseArray<AutofillValue>()
+ .apply { append(autofillNode.id, AutofillValue.forText(expectedValue)) }
// Act.
androidAutofill.performAutofill(autofillValues)
// Assert.
- verify(onFill, times(1)).invoke("email@google.com")
+ Truth.assertThat(autofilledValue).isEqualTo(expectedValue)
}
}
\ No newline at end of file
diff --git a/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidPopulateViewStructureTest.kt b/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidPopulateViewStructureTest.kt
index db8c641..9071352 100644
--- a/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidPopulateViewStructureTest.kt
+++ b/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidPopulateViewStructureTest.kt
@@ -16,38 +16,35 @@
package androidx.ui.autofill
-import android.content.Context
+import android.app.Activity
import android.graphics.Rect
import android.view.View
import android.view.ViewStructure
-import android.view.autofill.AutofillManager
import androidx.test.filters.SmallTest
+import androidx.ui.ComposeUiRobolectricTestRunner
+import androidx.ui.test.android.fake.FakeViewStructure
import com.google.common.truth.Truth.assertThat
-import com.nhaarman.mockitokotlin2.eq
-import com.nhaarman.mockitokotlin2.mock
-import com.nhaarman.mockitokotlin2.whenever
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
+import org.robolectric.Robolectric
+import org.robolectric.annotation.Config
@SmallTest
-@RunWith(JUnit4::class)
+@RunWith(ComposeUiRobolectricTestRunner::class)
+@Config(
+ manifest = Config.NONE,
+ minSdk = 26)
class AndroidPopulateViewStructureTest {
+ private val PACKAGE_NAME = "androidx.ui.platform.test"
private val autofillTree = AutofillTree()
private lateinit var androidAutofill: AndroidAutofill
@Before
fun setup() {
- val autofillManager: AutofillManager = mock()
-
- val context: Context = mock()
- whenever(context.getSystemService(eq(AutofillManager::class.java)))
- .thenReturn(autofillManager)
- whenever(context.packageName).thenReturn("com.google.testpackage")
-
- val view: View = mock()
- whenever(view.context).thenReturn(context)
+ val activity = Robolectric.setupActivity(Activity::class.java)
+ val view = View(activity)
+ activity.setContentView(view)
androidAutofill = AndroidAutofill(view, autofillTree)
}
@@ -82,7 +79,7 @@
assertThat(viewStructure).isEqualTo(FakeViewStructure().apply {
children.add(FakeViewStructure().apply {
virtualId = autofillNode.id
- packageName = "com.google.testpackage"
+ packageName = PACKAGE_NAME
setAutofillType(View.AUTOFILL_TYPE_TEXT)
setAutofillHints(arrayOf(View.AUTOFILL_HINT_NAME))
setDimens(0, 0, 0, 0, 0, 0)
@@ -115,14 +112,14 @@
assertThat(viewStructure).isEqualTo(FakeViewStructure().apply {
children.add(FakeViewStructure().apply {
virtualId = nameAutofillNode.id
- packageName = "com.google.testpackage"
+ packageName = PACKAGE_NAME
setAutofillType(View.AUTOFILL_TYPE_TEXT)
setAutofillHints(arrayOf(View.AUTOFILL_HINT_NAME))
setDimens(0, 0, 0, 0, 0, 0)
})
children.add(FakeViewStructure().apply {
virtualId = emailAutofillNode.id
- packageName = "com.google.testpackage"
+ packageName = PACKAGE_NAME
setAutofillType(View.AUTOFILL_TYPE_TEXT)
setAutofillHints(arrayOf(View.AUTOFILL_HINT_EMAIL_ADDRESS))
setDimens(0, 0, 0, 0, 0, 0)
diff --git a/ui/ui-test/api/1.0.0-alpha01.txt b/ui/ui-test/api/1.0.0-alpha01.txt
index 3d54f9f..0cc2bc2 100644
--- a/ui/ui-test/api/1.0.0-alpha01.txt
+++ b/ui/ui-test/api/1.0.0-alpha01.txt
@@ -133,3 +133,11 @@
}
+package androidx.ui.test.android.fake {
+
+ public final class FakeViewStructureKt {
+ ctor public FakeViewStructureKt();
+ }
+
+}
+
diff --git a/ui/ui-test/api/current.txt b/ui/ui-test/api/current.txt
index 3d54f9f..0cc2bc2 100644
--- a/ui/ui-test/api/current.txt
+++ b/ui/ui-test/api/current.txt
@@ -133,3 +133,11 @@
}
+package androidx.ui.test.android.fake {
+
+ public final class FakeViewStructureKt {
+ ctor public FakeViewStructureKt();
+ }
+
+}
+
diff --git a/ui/ui-test/api/restricted_1.0.0-alpha01.txt b/ui/ui-test/api/restricted_1.0.0-alpha01.txt
index 3d54f9f..0cc2bc2 100644
--- a/ui/ui-test/api/restricted_1.0.0-alpha01.txt
+++ b/ui/ui-test/api/restricted_1.0.0-alpha01.txt
@@ -133,3 +133,11 @@
}
+package androidx.ui.test.android.fake {
+
+ public final class FakeViewStructureKt {
+ ctor public FakeViewStructureKt();
+ }
+
+}
+
diff --git a/ui/ui-test/api/restricted_current.txt b/ui/ui-test/api/restricted_current.txt
index 3d54f9f..0cc2bc2 100644
--- a/ui/ui-test/api/restricted_current.txt
+++ b/ui/ui-test/api/restricted_current.txt
@@ -133,3 +133,11 @@
}
+package androidx.ui.test.android.fake {
+
+ public final class FakeViewStructureKt {
+ ctor public FakeViewStructureKt();
+ }
+
+}
+
diff --git a/ui/ui-test/build.gradle b/ui/ui-test/build.gradle
index c936fdc..a9fafbe5 100644
--- a/ui/ui-test/build.gradle
+++ b/ui/ui-test/build.gradle
@@ -32,20 +32,18 @@
kotlinPlugin project(path: ":compose:compose-compiler", configuration: "embeddablePlugin")
implementation(KOTLIN_COMPOSE_STDLIB)
-
implementation(ANDROIDX_TEST_RULES)
implementation(ANDROIDX_TEST_RUNNER)
implementation(ESPRESSO_CORE)
implementation(JUNIT)
- api project(":ui:ui-platform")
-
implementation project(":compose:compose-runtime")
implementation project(":ui:ui-animation")
implementation project(":ui:ui-core")
implementation project(":ui:ui-foundation")
implementation project(":ui:ui-framework")
implementation project(":ui:ui-layout")
+ implementation project(":ui:ui-platform")
testImplementation(TRUTH)
diff --git a/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidFakes.kt b/ui/ui-test/src/main/java/androidx/ui/test/android/fake/FakeViewStructure.kt
similarity index 82%
rename from ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidFakes.kt
rename to ui/ui-test/src/main/java/androidx/ui/test/android/fake/FakeViewStructure.kt
index 0d539e3..24fe108 100644
--- a/ui/ui-platform/src/test/java/androidx/ui/autofill/AndroidFakes.kt
+++ b/ui/ui-test/src/main/java/androidx/ui/test/android/fake/FakeViewStructure.kt
@@ -14,56 +14,60 @@
* limitations under the License.
*/
-package androidx.ui.autofill
+package androidx.ui.test.android.fake
import android.graphics.Matrix
import android.graphics.Rect
+import android.os.Build
import android.os.Bundle
import android.os.LocaleList
-import android.util.SparseArray
+import android.os.Parcel
import android.view.View
import android.view.ViewStructure
import android.view.autofill.AutofillId
import android.view.autofill.AutofillValue
-import com.nhaarman.mockitokotlin2.mock
+import androidx.annotation.GuardedBy
+import androidx.annotation.RequiresApi
/**
- * A fake implementation of { SparseArray } to use in tests.
+ * A fake implementation of [ViewStructure] to use in tests.
+ *
+ * @hide
*/
-internal class FakeSparseArray : SparseArray<AutofillValue>() {
-
- private val map = mutableMapOf<Int, AutofillValue>()
-
- override fun append(key: Int, value: AutofillValue?) {
- value?.let { map.putIfAbsent(key, it) }
- }
-
- override fun size() = map.count()
-
- override fun keyAt(index: Int) = map.asSequence().elementAt(index).component1()
-
- override fun get(key: Int) = map[key] ?: error("no element for the specified key")
-}
-
-/**
- * A fake implementation of { ViewStructure } to use in tests.
- */
-internal data class FakeViewStructure(
+@RequiresApi(Build.VERSION_CODES.O)
+data class FakeViewStructure(
var virtualId: Int = 0,
var packageName: String? = null,
var typeName: String? = null,
var entryName: String? = null,
var children: MutableList<FakeViewStructure> = mutableListOf(),
var bounds: Rect? = null,
- private val autofillId: AutofillId? = mock(),
+ private val autofillId: AutofillId? = generateAutofillId(),
private var autofillType: Int = View.AUTOFILL_TYPE_NONE,
private var autofillHints: Array<out String> = arrayOf()
) : ViewStructure() {
+ internal companion object {
+ @GuardedBy("this")
+ private var previousId = 0
+ private val NO_SESSION = 0
+
+ @Synchronized
+ private fun generateAutofillId(): AutofillId {
+ var autofillId: AutofillId? = null
+ useParcel { parcel ->
+ parcel.writeInt(++previousId) // View Id.
+ parcel.writeInt(NO_SESSION) // Flag.
+ autofillId = AutofillId.CREATOR.createFromParcel(parcel)
+ }
+ return autofillId ?: error("Could not generate autofill id")
+ }
+ }
+
override fun getChildCount() = children.count()
override fun addChildCount(childCount: Int): Int {
- repeat(childCount) { children.add(FakeViewStructure()) }
+ repeat(childCount) { children.add(FakeViewStructure(autofillId = autofillId)) }
return children.count() - childCount
}
@@ -206,4 +210,15 @@
other.right == right &&
other.bottom == bottom &&
other.top == top
+}
+
+/** Obtains a parcel and then recycles it correctly whether an exception is thrown or not. */
+private fun useParcel(block: (Parcel) -> Unit) {
+ var parcel: Parcel? = null
+ try {
+ parcel = Parcel.obtain()
+ block(parcel)
+ } finally {
+ parcel?.recycle()
+ }
}
\ No newline at end of file