Merge "Correct handling of orientation." into androidx-main
diff --git a/glance/glance-appwidget/build.gradle b/glance/glance-appwidget/build.gradle
index 189616b..80123313 100644
--- a/glance/glance-appwidget/build.gradle
+++ b/glance/glance-appwidget/build.gradle
@@ -55,6 +55,7 @@
testImplementation(libs.truth)
testImplementation(libs.kotlinReflect)
+ androidTestImplementation("androidx.test.uiautomator:uiautomator:2.2.0")
androidTestImplementation(project(":test:screenshot:screenshot"))
androidTestImplementation(project(":core:core-ktx"))
androidTestImplementation(libs.espressoCore)
diff --git a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostRule.kt b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostRule.kt
index a7c8848..bdcb084 100644
--- a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostRule.kt
+++ b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostRule.kt
@@ -17,20 +17,29 @@
package androidx.glance.appwidget
import android.Manifest
+import android.app.Activity
import android.appwidget.AppWidgetHostView
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.pm.ActivityInfo
-import android.content.res.Configuration
+import android.os.Build
+import android.view.View
import android.view.ViewTreeObserver
import androidx.glance.unit.DpSize
import androidx.glance.unit.dp
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
-import androidx.test.espresso.Espresso.onIdle
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.UiController
+import androidx.test.espresso.ViewAction
+import androidx.test.espresso.matcher.ViewMatchers.isRoot
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry
+import androidx.test.runner.lifecycle.Stage
+import androidx.test.uiautomator.UiDevice
+import org.hamcrest.Matcher
import org.junit.rules.RuleChain
import org.junit.rules.TestRule
import org.junit.runner.Description
@@ -50,24 +59,22 @@
val landscapeSize: DpSize
get() = mLandscapeSize
- private val mUiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation
+ private val mInstrumentation = InstrumentationRegistry.getInstrumentation()
+ private val mUiAutomation = mInstrumentation.uiAutomation
private val mActivityRule: ActivityScenarioRule<AppWidgetHostTestActivity> =
ActivityScenarioRule(AppWidgetHostTestActivity::class.java)
+ private val mUiDevice = UiDevice.getInstance(mInstrumentation)
+
// Ensure the screen starts in portrait and restore the orientation on leaving
private val mOrientationRule = TestRule { base, _ ->
object : Statement() {
override fun evaluate() {
- var orientation: Int = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
- mScenario.onActivity {
- orientation = it.resources.configuration.orientation.toActivityInfoOrientation()
- it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
- }
+ mUiDevice.freezeRotation()
+ mUiDevice.setOrientationNatural()
base.evaluate()
- mScenario.onActivity {
- it.requestedOrientation = orientation
- }
+ mUiDevice.unfreezeRotation()
}
}
}
@@ -118,27 +125,14 @@
onHostActivity { block(mHostView) }
}
- /** Change the orientation to landscape using [setOrientation] .*/
+ /** Change the orientation to landscape.*/
fun setLandscapeOrientation() {
- setOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
+ onView(isRoot()).perform(orientationLandscape())
}
- /** Change the orientation to portrait using [setOrientation] .*/
+ /** Change the orientation to portrait.*/
fun setPortraitOrientation() {
- setOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
- }
-
- /**
- * Change the orientation of the screen, then update the view sizes and reapply the RemoteViews.
- */
- private fun setOrientation(orientation: Int) {
- mScenario.onActivity { it.requestedOrientation = orientation }
- onIdle()
- mScenario.onActivity {
- it.updateAllSizes()
- it.reapplyRemoteViews()
- }
- onIdle()
+ onView(isRoot()).perform(orientationPortrait())
}
/**
@@ -202,11 +196,46 @@
mHostView.childCount > 0
}
}
-}
-private fun Int.toActivityInfoOrientation(): Int =
- if (this == Configuration.ORIENTATION_PORTRAIT) {
- ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
- } else {
- ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
- }
\ No newline at end of file
+ private inner class OrientationChangeAction constructor(private val orientation: Int) :
+ ViewAction {
+ override fun getConstraints(): Matcher<View> = isRoot()
+
+ override fun getDescription() = "change orientation to $orientationName"
+
+ private val orientationName: String
+ get() =
+ if (orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
+ "landscape"
+ } else {
+ "portrait"
+ }
+
+ override fun perform(uiController: UiController, view: View) {
+ uiController.loopMainThreadUntilIdle()
+ mActivityRule.scenario.onActivity { it.requestedOrientation = orientation }
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
+ // Somehow, before Android S, changing the orientation doesn't trigger the
+ // onConfigurationChange
+ uiController.loopMainThreadUntilIdle()
+ mScenario.onActivity {
+ it.updateAllSizes(it.resources.configuration.orientation)
+ it.reapplyRemoteViews()
+ }
+ }
+ val resumedActivities: Collection<Activity> =
+ ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED)
+ if (resumedActivities.isEmpty()) {
+ throw RuntimeException("Could not change orientation")
+ }
+ }
+ }
+
+ private fun orientationLandscape(): ViewAction {
+ return OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
+ }
+
+ private fun orientationPortrait(): ViewAction {
+ return OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+ }
+}
diff --git a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostTestActivity.kt b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostTestActivity.kt
index 76e9f04..90e8cb8 100644
--- a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostTestActivity.kt
+++ b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/AppWidgetHostTestActivity.kt
@@ -34,13 +34,12 @@
import android.widget.FrameLayout
import android.widget.RemoteViews
import androidx.annotation.RequiresApi
-import androidx.core.text.layoutDirection
-import org.junit.Assert.fail
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
import androidx.glance.appwidget.test.R
import androidx.glance.unit.DpSize
+import org.junit.Assert.fail
import java.util.Locale
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
@RequiresApi(26)
class AppWidgetHostTestActivity : Activity() {
@@ -102,13 +101,14 @@
}
override fun onConfigurationChanged(newConfig: Configuration) {
+ Log.i("YOLO", "Changing configuration, orientation = ${newConfig.orientation}")
super.onConfigurationChanged(newConfig)
- updateAllSizes()
+ updateAllSizes(newConfig.orientation)
reapplyRemoteViews()
}
- fun updateAllSizes() {
- mHostViews.forEach { it.updateSize() }
+ fun updateAllSizes(orientation: Int) {
+ mHostViews.forEach { it.updateSize(orientation) }
}
fun reapplyRemoteViews() {
@@ -173,11 +173,11 @@
fun setSizes(portraitSize: DpSize, landscapeSize: DpSize) {
mPortraitSize = portraitSize
mLandscapeSize = landscapeSize
- updateSize()
+ updateSize(resources.configuration.orientation)
}
- fun updateSize() {
- val size = when (context.resources.configuration.orientation) {
+ fun updateSize(orientation: Int) {
+ val size = when (orientation) {
Configuration.ORIENTATION_LANDSCAPE -> mLandscapeSize
Configuration.ORIENTATION_PORTRAIT -> mPortraitSize
else -> error("Unknown orientation ${context.resources.configuration.orientation}")