Add test artifact to support testing
Add test artifact to support testing.
Add EmptyWindowLayoutInfoRule to always produce an empty set of features
Relnote: Add test artifact for WindowManager Jetpack Library.
Bug: 184266682
Test: ./gradlew window:window-test:cAT
Change-Id: I57f66ad83498ff5e09d0a1d1c9cda0554c2c04e1
diff --git a/window/window-testing/api/current.txt b/window/window-testing/api/current.txt
new file mode 100644
index 0000000..e0d15ce
--- /dev/null
+++ b/window/window-testing/api/current.txt
@@ -0,0 +1,11 @@
+// Signature format: 4.0
+package androidx.window.test {
+
+ public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
+ ctor public WindowLayoutInfoPublisherRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void overrideWindowLayoutInfo(androidx.window.WindowLayoutInfo info);
+ }
+
+}
+
diff --git a/window/window-testing/api/public_plus_experimental_current.txt b/window/window-testing/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..f00e796
--- /dev/null
+++ b/window/window-testing/api/public_plus_experimental_current.txt
@@ -0,0 +1,11 @@
+// Signature format: 4.0
+package androidx.window.test {
+
+ public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
+ ctor public WindowLayoutInfoPublisherRule();
+ method @kotlinx.coroutines.ExperimentalCoroutinesApi public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void overrideWindowLayoutInfo(androidx.window.WindowLayoutInfo info);
+ }
+
+}
+
diff --git a/window/window-testing/api/res-current.txt b/window/window-testing/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/window/window-testing/api/res-current.txt
diff --git a/window/window-testing/api/restricted_current.txt b/window/window-testing/api/restricted_current.txt
new file mode 100644
index 0000000..e0d15ce
--- /dev/null
+++ b/window/window-testing/api/restricted_current.txt
@@ -0,0 +1,11 @@
+// Signature format: 4.0
+package androidx.window.test {
+
+ public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
+ ctor public WindowLayoutInfoPublisherRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void overrideWindowLayoutInfo(androidx.window.WindowLayoutInfo info);
+ }
+
+}
+
diff --git a/window/window-testing/build.gradle b/window/window-testing/build.gradle
new file mode 100644
index 0000000..5a706af
--- /dev/null
+++ b/window/window-testing/build.gradle
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryType
+import androidx.build.LibraryVersions
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+
+android {
+ defaultConfig {
+ multiDexEnabled = true
+ }
+}
+
+dependencies {
+ api(KOTLIN_STDLIB)
+ api(project(":window:window"))
+ api(JUNIT)
+ implementation("androidx.core:core:1.3.2")
+
+ androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
+ androidTestImplementation(ANDROIDX_TEST_RUNNER)
+ androidTestImplementation(ANDROIDX_TEST_RULES)
+ androidTestImplementation(KOTLIN_COROUTINES_TEST)
+ androidTestImplementation(MULTIDEX)
+ androidTestImplementation(TRUTH)
+}
+
+androidx {
+ name = "WindowManager Test Library"
+ type = LibraryType.PUBLISHED_LIBRARY
+ mavenVersion = LibraryVersions.WINDOW
+ mavenGroup = LibraryGroups.WINDOW
+ inceptionYear = "2021"
+ description = "WindowManager Test Library"
+}
+
+// Allow usage of Kotlin's @OptIn.
+tasks.withType(KotlinCompile).configureEach {
+ kotlinOptions {
+ freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn"]
+ }
+}
\ No newline at end of file
diff --git a/window/window-testing/src/androidTest/AndroidManifest.xml b/window/window-testing/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..7d587da
--- /dev/null
+++ b/window/window-testing/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="androidx.window.test">
+ <application>
+ <activity android:name="TestActivity"/>
+ </application>
+</manifest>
diff --git a/window/window-testing/src/androidTest/java/androidx/window/test/TestActivity.kt b/window/window-testing/src/androidTest/java/androidx/window/test/TestActivity.kt
new file mode 100644
index 0000000..3d934fd
--- /dev/null
+++ b/window/window-testing/src/androidTest/java/androidx/window/test/TestActivity.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2021 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.window.test
+
+import android.app.Activity
+
+/**
+ * A test [Activity] for testing purposes.
+ */
+public class TestActivity : Activity()
\ No newline at end of file
diff --git a/window/window-testing/src/androidTest/java/androidx/window/test/WindowLayoutInfoPublisherRuleTest.kt b/window/window-testing/src/androidTest/java/androidx/window/test/WindowLayoutInfoPublisherRuleTest.kt
new file mode 100644
index 0000000..a93682b
--- /dev/null
+++ b/window/window-testing/src/androidTest/java/androidx/window/test/WindowLayoutInfoPublisherRuleTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2021 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.window.test
+
+import android.graphics.Rect
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.window.DisplayFeature
+import androidx.window.WindowLayoutInfo
+import androidx.window.windowInfoRepository
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.async
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.take
+import kotlinx.coroutines.flow.toCollection
+import kotlinx.coroutines.test.runBlockingTest
+import org.junit.Assert.assertEquals
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+public class WindowLayoutInfoPublisherRuleTest {
+
+ private val activityRule = ActivityScenarioRule(TestActivity::class.java)
+ private val publisherRule = WindowLayoutInfoPublisherRule()
+
+ @get:Rule
+ public val testRule: TestRule
+
+ init {
+ testRule = RuleChain.outerRule(publisherRule).around(activityRule)
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ public fun testWindowLayoutInfo_relayValue(): Unit = runBlockingTest {
+ val expected = WindowLayoutInfo.Builder().setDisplayFeatures(emptyList()).build()
+ activityRule.scenario.onActivity { activity ->
+ val value = async {
+ activity.windowInfoRepository().windowLayoutInfo.first()
+ }
+ publisherRule.overrideWindowLayoutInfo(expected)
+ runBlockingTest {
+ val actual = value.await()
+ assertEquals(expected, actual)
+ }
+ }
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ public fun testWindowLayoutInfo_multipleValues(): Unit = runBlockingTest {
+ val feature1 = object : DisplayFeature {
+ override val bounds: Rect
+ get() = Rect()
+ }
+ val feature2 = object : DisplayFeature {
+ override val bounds: Rect
+ get() = Rect()
+ }
+ val expected1 = WindowLayoutInfo.Builder().setDisplayFeatures(listOf(feature1)).build()
+ val expected2 = WindowLayoutInfo.Builder().setDisplayFeatures(listOf(feature2)).build()
+ activityRule.scenario.onActivity { activity ->
+ val values = mutableListOf<WindowLayoutInfo>()
+ val value = async {
+ activity.windowInfoRepository().windowLayoutInfo.take(4).toCollection(values)
+ }
+ publisherRule.overrideWindowLayoutInfo(expected1)
+ publisherRule.overrideWindowLayoutInfo(expected2)
+ publisherRule.overrideWindowLayoutInfo(expected1)
+ publisherRule.overrideWindowLayoutInfo(expected2)
+ runBlockingTest {
+ assertEquals(
+ listOf(expected1, expected2, expected1, expected2),
+ value.await().toList()
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/window/window-testing/src/main/AndroidManifest.xml b/window/window-testing/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..4bd698f
--- /dev/null
+++ b/window/window-testing/src/main/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2021 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="androidx.window.test">
+</manifest>
\ No newline at end of file
diff --git a/window/window-testing/src/main/java/androidx/window/test/PublishLayoutInfoRepo.kt b/window/window-testing/src/main/java/androidx/window/test/PublishLayoutInfoRepo.kt
new file mode 100644
index 0000000..b3591df
--- /dev/null
+++ b/window/window-testing/src/main/java/androidx/window/test/PublishLayoutInfoRepo.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 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.window.test
+
+import androidx.window.WindowInfoRepo
+import androidx.window.WindowLayoutInfo
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+
+internal class PublishLayoutInfoRepo(
+ private val core: WindowInfoRepo,
+ private val flow: MutableSharedFlow<WindowLayoutInfo>
+) : WindowInfoRepo by core {
+ override val windowLayoutInfo: Flow<WindowLayoutInfo>
+ get() = flow
+}
\ No newline at end of file
diff --git a/window/window-testing/src/main/java/androidx/window/test/PublishWindowInfoRepoDecorator.kt b/window/window-testing/src/main/java/androidx/window/test/PublishWindowInfoRepoDecorator.kt
new file mode 100644
index 0000000..7cf34ba
--- /dev/null
+++ b/window/window-testing/src/main/java/androidx/window/test/PublishWindowInfoRepoDecorator.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 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.window.test
+
+import androidx.window.WindowInfoRepo
+import androidx.window.WindowInfoRepoDecorator
+import androidx.window.WindowLayoutInfo
+import kotlinx.coroutines.flow.MutableSharedFlow
+
+internal class PublishWindowInfoRepoDecorator(
+ private val flow: MutableSharedFlow<WindowLayoutInfo>
+) : WindowInfoRepoDecorator {
+ override fun decorate(repo: WindowInfoRepo): WindowInfoRepo {
+ return PublishLayoutInfoRepo(repo, flow)
+ }
+}
\ No newline at end of file
diff --git a/window/window-testing/src/main/java/androidx/window/test/WindowLayoutInfoPublisher.kt b/window/window-testing/src/main/java/androidx/window/test/WindowLayoutInfoPublisher.kt
new file mode 100644
index 0000000..2261e68
--- /dev/null
+++ b/window/window-testing/src/main/java/androidx/window/test/WindowLayoutInfoPublisher.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021 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.window.test
+
+import androidx.window.WindowInfoRepo
+import androidx.window.WindowLayoutInfo
+import androidx.window.WindowMetrics
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+
+internal class WindowLayoutInfoPublisher(
+ private val core: WindowInfoRepo,
+ private val flow: StateFlow<WindowLayoutInfo>
+) : WindowInfoRepo {
+
+ override val currentWindowMetrics: WindowMetrics
+ get() {
+ return core.currentWindowMetrics
+ }
+
+ override val maximumWindowMetrics: WindowMetrics
+ get() {
+ return core.maximumWindowMetrics
+ }
+
+ override val windowLayoutInfo: Flow<WindowLayoutInfo>
+ get() {
+ return flow
+ }
+}
\ No newline at end of file
diff --git a/window/window-testing/src/main/java/androidx/window/test/WindowLayoutInfoPublisherRule.kt b/window/window-testing/src/main/java/androidx/window/test/WindowLayoutInfoPublisherRule.kt
new file mode 100644
index 0000000..f9e92fc
--- /dev/null
+++ b/window/window-testing/src/main/java/androidx/window/test/WindowLayoutInfoPublisherRule.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2021 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.window.test
+
+import androidx.window.WindowInfoRepo
+import androidx.window.WindowLayoutInfo
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.BufferOverflow.DROP_OLDEST
+import kotlinx.coroutines.flow.MutableSharedFlow
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * A [TestRule] to help test consuming a stream of [WindowLayoutInfo] values.
+ * [WindowLayoutInfoPublisherRule] allows you to push through different [WindowLayoutInfo] values
+ * on demand.
+ *
+ * Here are some recommended testing scenarios.
+ *
+ * To test the scenario where no [WindowLayoutInfo] is ever emitted. Just set the rule as a
+ * standard rule.
+ *
+ * To test sending a generic feature build your own [WindowLayoutInfo] and publish it through the
+ * method [WindowLayoutInfoPublisherRule.overrideWindowLayoutInfo].
+ *
+ * Some helper methods are provided to test the following scenarios.
+ * <ul>
+ * <li>A fold in the middle and the dimension matches the shortest window dimension.</li>
+ * <li>A fold in the middle and the dimension matches the longest window dimension.</li>
+ * <li>A fold in the middle and has vertical orientation.</li>
+ * <li>A fold in the middle and has horizontal orientation.</li>
+ * </ul>
+ */
+public class WindowLayoutInfoPublisherRule() : TestRule {
+
+ private val flow = MutableSharedFlow<WindowLayoutInfo>(
+ extraBufferCapacity = 1,
+ onBufferOverflow = DROP_OLDEST
+ )
+ private val overrideServices = PublishWindowInfoRepoDecorator(flow)
+
+ @ExperimentalCoroutinesApi
+ override fun apply(base: Statement, description: Description): Statement {
+ return object : Statement() {
+ override fun evaluate() {
+ WindowInfoRepo.overrideDecorator(overrideServices)
+ base.evaluate()
+ WindowInfoRepo.reset()
+ }
+ }
+ }
+
+ /**
+ * Send an arbitrary [WindowLayoutInfo] through
+ * [androidx.window.WindowInfoRepo.windowLayoutInfo]. Each event is sent only once.
+ */
+ public fun overrideWindowLayoutInfo(info: WindowLayoutInfo) {
+ flow.tryEmit(info)
+ }
+}
\ No newline at end of file