ViewRootImpl$CalledFromWrongThreadException when verifying Toast messages with androidx.test:core:1.5.0
Quantamm opened this issue · comments
Description
We're getting ViewRootImpl$CalledFromWrongThreadException exceptions when trying to verify Toast messages with androidx.test:core:1.5.0. 1.4.0 does not exhibit the issue. 1.6.0-alpha01 does.
Steps to Reproduce
On an Android 9 emulator, I use this ToastMatcher:
import android.view.WindowManager
import androidx.test.espresso.Root
import org.hamcrest.Description
import org.hamcrest.TypeSafeMatcher
class ToastMatcher : TypeSafeMatcher<Root>() {
override fun describeTo(description: Description) {
description.appendText("is toast")
}
override fun matchesSafely(root: Root) =
root.windowLayoutParams.get().type == WindowManager.LayoutParams.TYPE_TOAST
&& root.decorView.windowToken === root.decorView.applicationWindowToken
}
with this line of code:
onView(withText("message")).inRoot(new ToastMatcher()).check(matches(isDisplayed()));
Expected Results
Using androidx.test:core:1.4.0, the matcher finds the Toast and the test passes.
Actual Results
using androidx.test:core:1.5.0, the test fails with:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7753)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:1268)
at android.view.ViewRootImpl.invalidateChild(ViewRootImpl.java:1263)
at android.view.View.invalidateInternal(View.java:16434)
at android.view.View.invalidate(View.java:16398)
at android.view.View.invalidate(View.java:16381)
at androidx.test.core.view.ViewCapture.forceRedraw(ViewCapture.kt:113)
at androidx.test.core.app.DeviceCapture$forceRedrawGlobalWindowViews$1.run(DeviceCapture.kt:172)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
AndroidX Test and Android OS Versions
androidx.test.core:1.5.0
androidx.arch.core:core-testing:2.2.0
Link to a public git repo demonstrating the problem:
I created a minimal project with the above code, but it doesn't reproduce the problem. I can't share the real project that's experiencing the issue, but I'm happy to answer any questions about our setup.
This stack trace is likely from when Espresso's error handler tries to take a screenshot from an already failing check. There is probably an earlier failure that is getting obscured.
Is your code under test inflating UI outside the main thread?
Is your code under test inflating UI outside the main thread?
Thank you for the sanity check. Since this issue only occurred with the upgrade of the library, I (falsely) assumed that it must be caused by the library. It turns out that one of the other devs apparently thought that calling Looper.prepare() on a background thread was the same thing as using the UI thread. I've fixed it and now we no longer have any issue.
Glad to hear you solved it!
It does sound like there is a legitimate debuggability issue with the new espresso library though if the root cause was not immediately apparent. Was the original stack trace the one reported as the cause of the failed test?
Was the original stack trace the one reported as the cause of the failed test?
I believe so. Here's the logcat from the check for the Toast message to the ViewRootImpl exception:
09-01 14:56:54.604 19119 19119 I ViewInteraction: Checking 'MatchesViewAssertion{viewMatcher=(view has effective visibility <VISIBLE> and view.getGlobalVisibleRect() to return non-empty rectangle)}' assertion on view an instance of android.widget.TextView and view.getText() with or without transformation to match: is "Toast message."
09-01 14:56:54.611 19119 19173 D cucumber-android: I should see the Launcher
09-01 14:56:54.619 19119 19119 I ViewInteraction: Checking 'MatchesViewAssertion{viewMatcher=(view has effective visibility <VISIBLE> and view.getGlobalVisibleRect() to return non-empty rectangle)}' assertion on view (view.getId() is <2131297314/com.my.package:id/primary_text> and an instance of android.widget.TextView and view.getText() equals string from resource id: <2131886629> [app_name] value: My App)
09-01 14:56:54.623 19119 19119 I ViewInteraction: Checking 'MatchesViewAssertion{viewMatcher=(view has effective visibility <VISIBLE> and view.getGlobalVisibleRect() to return non-empty rectangle)}' assertion on view view.getId() is <2131297511/com.my.package:id/status_layout>
09-01 14:56:54.627 19119 19173 V com.my.package.test.common.TestLogger.echoToAppLogger:427: java.lang
09-01 14:56:55.183 19119 19173 V com.my.package.notes.common.AppLoggerWrapper.trace:25: Added 137 smime certificates, 0 of which are user-provided
09-01 14:56:55.226 19119 19173 W Settings: Setting airplane_mode_on has moved from android.provider.Settings.System to android.provider.Settings.Global, returning read-only value.
09-01 14:56:55.229 1966 1998 D AutofillManagerService: Close system dialogs
09-01 14:56:55.231 19119 19173 V com.my.package.android.common.AuthenticationLockout.clearAuthenticationErrorNotificatENTRY
09-01 14:56:55.232 19119 19173 V com.my.package.android.common.AuthenticationLockout.clearAuthenticationErrorNotificatEXIT
09-01 14:56:55.233 2104 2104 V StatusBar: mStatusBarWindow: com.android.systemui.statusbar.phone.StatusBarWindowView{4a537ae V.ED..... ........ 0,0-1440,84} canPanelBeCollapsed(): false
09-01 14:56:55.234 2104 2104 V StatusBar: mStatusBarWindow: com.android.systemui.statusbar.phone.StatusBarWindowView{4a537ae V.ED..... ........ 0,0-1440,84} canPanelBeCollapsed(): false
09-01 14:56:55.236 19119 19173 V com.my.package.client.CalendarStore.instance:158: Using existing CalendarStore instance for account UUID = cb1c3f9d-b428-407a-ada1-d03246837b4f
09-01 14:56:55.237 19119 19173 V com.my.package.test.common.TestLogger.echoToAppLogger:427: java.lang
09-01 14:56:55.237 2104 2104 I vol.Events: writeEvent dismiss_dialog volume_controller
09-01 14:56:55.237 2104 2104 I vol.Events: writeEvent dismiss_dialog volume_controller
09-01 14:56:55.238 19119 19173 V com.my.package.test.common.TestLogger.echoToAppLogger:427: java.lang
09-01 14:56:55.243 19119 19119 I ViewInteraction: Performing 'send keyCode: 4, metaState: 0 key event' action on view view.getRootView() to equal view
09-01 14:56:55.250 19119 19119 V com.my.package.android.common.TravelerActivity.onBackPressed:174: ActivityClass=StatusActivity FragmentClasses=<empty>
09-01 14:56:55.250 19119 19119 V com.my.package.android.common.TravelerActivity.closedOpenDrawer:210: ActivityClass=StatusActivity FragmentClasses=<empty>
09-01 14:56:55.256 19119 19119 V com.my.package.android.common.TravelerActivity.onSafePause:612: ActivityClass=StatusActivity FragmentClasses=<empty>
09-01 14:56:55.257 19119 19119 D LifecycleMonitor: Lifecycle status change: com.my.package.StatusActivity@46cbb93 in: PAUSED
09-01 14:56:55.267 1966 1989 E memtrack: Couldn't load memtrack module
09-01 14:56:55.267 1966 1989 W android.os.Debug: failed to get memory consumption info: -1
09-01 14:56:55.313 1637 1699 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.323 1637 1698 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.329 1637 1699 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.337 1799 1799 D SurfaceFlinger: duplicate layer name: changing com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity to com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity#1
09-01 14:56:55.358 1637 1699 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.359 1637 1698 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.365 1637 1699 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.368 2840 3012 D EGL_emulation: eglMakeCurrent: 0x7e8aa9c398e0: ver 3 1 (tinfo 0x7e8aa9c891a0)
09-01 14:56:55.371 2095 2095 I GoogleInputMethod: onFinishInput() : Dummy InputConnection bound
09-01 14:56:55.377 2095 2095 I GoogleInputMethod: onStartInput() : Dummy InputConnection bound
09-01 14:56:55.401 2871 3210 D HostConnection: HostConnection::get() New Host Connection established 0xe55b3ba0, tid 3210
09-01 14:56:55.403 2871 3210 D HostConnection: HostComposition ext ANDROID_EMU_CHECKSUM_HELPER_v1 ANDROID_EMU_native_sync_v2 ANDROID_EMU_native_sync_v3 ANDROID_EMU_native_sync_v4 ANDROID_EMU_dma_v1 ANDROID_EMU_YUV420_888_to_NV21 ANDROID_EMU_YUV_Cache ANDROID_EMU_sync_buffer_data GL_OES_EGL_image_external_essl3 GL_OES_vertex_array_object GL_KHR_texture_compression_astc_ldr ANDROID_EMU_host_side_tracing ANDROID_EMU_gles_max_version_3_1
09-01 14:56:55.406 2104 2424 D EGL_emulation: eglMakeCurrent: 0x7e8a96254220: ver 3 1 (tinfo 0x7e8aa823fe80)
09-01 14:56:55.412 2871 3210 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
09-01 14:56:55.412 2871 3210 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
09-01 14:56:55.412 2871 3210 I OpenGLRenderer: Initialized EGL, version 1.4
09-01 14:56:55.413 2871 3210 D OpenGLRenderer: Swap behavior 1
09-01 14:56:55.413 2871 3210 W OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
09-01 14:56:55.413 2871 3210 D OpenGLRenderer: Swap behavior 0
09-01 14:56:55.425 2871 3210 D eglCodecCommon: setVertexArrayObject: set vao to 0 (0) 0 0
09-01 14:56:55.426 2871 3210 D EGL_emulation: eglCreateContext: 0xcc645d20: maj 3 min 1 rcv 4
09-01 14:56:55.428 2104 2424 D EGL_emulation: eglMakeCurrent: 0x7e8a96254220: ver 3 1 (tinfo 0x7e8aa823fe80)
09-01 14:56:55.428 2871 3210 D EGL_emulation: eglMakeCurrent: 0xcc645d20: ver 3 1 (tinfo 0xcc6082d0)
09-01 14:56:55.430 2871 3210 E eglCodecCommon: glUtilsParamSize: unknow param 0x000082da
09-01 14:56:55.430 2871 3210 E eglCodecCommon: glUtilsParamSize: unknow param 0x000082da
09-01 14:56:55.475 2871 3210 D EGL_emulation: eglMakeCurrent: 0xcc645d20: ver 3 1 (tinfo 0xcc6082d0)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: Error inserting period=7071000 preferred_charging_state=1 preferred_network_type=1 target_class=com.google.android.gms.measurement.PackageMeasurementTaskService required_network_type=0 runtime=1693598215472 required_idleness_state=0 source=16 service_kind=0 target_package=com.google.android.gms persistence_level=1 source_version=202414000 last_runtime=0 user_id=0 job_id=-1 requires_charging=0 tag=Measurement.PackageMeasurementTaskService.UPLOAD_TASK_TAG flex_time=3535000 task_type=0 retry_strategy={"maximum_backoff_seconds":{"3600":0},"initial_backoff_seconds":{"30":0},"retry_policy":{"0":0}}
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: pending_ops.tag, pending_ops.target_class, pending_ops.target_package, pending_ops.user_id (code 2067 SQLITE_CONSTRAINT_UNIQUE)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:796)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1564)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1433)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at aqui.a(:com.google.android.gms@202414023@20.24.14 (040800-319035315):175)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at aqtk.a(:com.google.android.gms@202414023@20.24.14 (040800-319035315):182)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at aqtk.a(:com.google.android.gms@202414023@20.24.14 (040800-319035315):23)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at aqtk.a(:com.google.android.gms@202414023@20.24.14 (040800-319035315):177)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at aqpu.run(:com.google.android.gms@202414023@20.24.14 (040800-319035315):9)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at soy.b(:com.google.android.gms@202414023@20.24.14 (040800-319035315):12)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at soy.run(:com.google.android.gms@202414023@20.24.14 (040800-319035315):8)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at sux.run(:com.google.android.gms@202414023@20.24.14 (040800-319035315):0)
09-01 14:56:55.482 2491 14635 E SQLiteDatabase: at java.lang.Thread.run(Thread.java:764)
09-01 14:56:55.492 1637 1699 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 14749696
09-01 14:56:55.533 1966 2385 I GnssLocationProvider: WakeLock acquired by sendMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@864851a)
09-01 14:56:55.534 1966 1989 I GnssLocationProvider: WakeLock released by handleMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@864851a)
09-01 14:56:55.561 19119 19119 V com.my.package.android.common.TravelerActivity.onSafeStop:621: ActivityClass=StatusActivity FragmentClasses=<empty>
09-01 14:56:55.561 19119 19119 V com.my.package.android.common.TravelerActivity.hideProgressBarIcon:353: Hide syncProgressBar icon without delay
09-01 14:56:55.562 19119 19119 V com.my.package.common.ui.ThumbnailRetrievalQueue.clearQueue:101: THUMBPROVIDER: clearing retrieval queue, task count=0
09-01 14:56:55.563 1966 5369 D HostConnection: HostConnection::get() New Host Connection established 0x7e8a8c5b5c20, tid 5369
09-01 14:56:55.564 19119 19119 D LifecycleMonitor: Lifecycle status change: com.my.package.StatusActivity@46cbb93 in: STOPPED
09-01 14:56:55.565 1966 5369 D HostConnection: HostComposition ext ANDROID_EMU_CHECKSUM_HELPER_v1 ANDROID_EMU_native_sync_v2 ANDROID_EMU_native_sync_v3 ANDROID_EMU_native_sync_v4 ANDROID_EMU_dma_v1 ANDROID_EMU_YUV420_888_to_NV21 ANDROID_EMU_YUV_Cache ANDROID_EMU_sync_buffer_data GL_OES_EGL_image_external_essl3 GL_OES_vertex_array_object GL_KHR_texture_compression_astc_ldr ANDROID_EMU_host_side_tracing ANDROID_EMU_gles_max_version_3_1
09-01 14:56:55.571 1966 5369 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
09-01 14:56:55.571 1966 5369 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
09-01 14:56:55.571 1966 5369 I OpenGLRenderer: Initialized EGL, version 1.4
09-01 14:56:55.571 1966 5369 D OpenGLRenderer: Swap behavior 1
09-01 14:56:55.571 1966 5369 W OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
09-01 14:56:55.571 1966 5369 D OpenGLRenderer: Swap behavior 0
09-01 14:56:55.586 2840 2855 I s.nexuslaunche: NativeAlloc concurrent copying GC freed 3982(315KB) AllocSpace objects, 3(256KB) LOS objects, 49% free, 3MB/7MB, paused 9.791ms total 50.014ms
09-01 14:56:55.589 1966 5369 D eglCodecCommon: setVertexArrayObject: set vao to 0 (0) 0 0
09-01 14:56:55.589 1966 5369 D EGL_emulation: eglCreateContext: 0x7e8a92bbd760: maj 3 min 1 rcv 4
09-01 14:56:55.607 1966 5369 D EGL_emulation: eglMakeCurrent: 0x7e8a92bbd760: ver 3 1 (tinfo 0x7e8a8c497240)
09-01 14:56:55.610 1966 5369 E eglCodecCommon: glUtilsParamSize: unknow param 0x000082da
09-01 14:56:55.610 1966 5369 E eglCodecCommon: glUtilsParamSize: unknow param 0x000082da
09-01 14:56:55.617 2104 2119 I ndroid.systemu: NativeAlloc concurrent copying GC freed 21657(1281KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 5MB/11MB, paused 16.745ms total 69.365ms
09-01 14:56:55.618 19119 19119 D LifecycleMonitor: Lifecycle status change: com.my.package.StatusActivity@46cbb93 in: DESTROYED
09-01 14:56:55.640 1966 5369 D eglCodecCommon: setVertexArrayObject: set vao to 0 (0) 1 2
09-01 14:56:55.666 2871 2871 W SessionLifecycleManager: Handover failed. Creating new session controller.
09-01 14:56:55.232 1966 1998 D AutofillManagerService: Close system dialogs
09-01 14:56:55.716 1966 1966 V SettingsProvider: Notifying for 0: content://settings/secure/accessibility_enabled
09-01 14:56:55.737 19119 19119 D AndroidRuntime: Shutting down VM
09-01 14:56:55.741 19119 19119 E AndroidRuntime: FATAL EXCEPTION: main
09-01 14:56:55.741 19119 19119 E AndroidRuntime: Process: com.my.package, PID: 19119
09-01 14:56:55.741 19119 19119 E AndroidRuntime: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7753)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:1268)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at android.view.ViewRootImpl.invalidateChild(ViewRootImpl.java:1263)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at android.view.View.invalidateInternal(View.java:16434)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at android.view.View.invalidate(View.java:16398)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at android.view.View.invalidate(View.java:16381)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at androidx.test.core.view.ViewCapture.forceRedraw(ViewCapture.kt:109)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at androidx.test.core.app.DeviceCapture$forceRedrawGlobalWindowViews$1.run(DeviceCapture.kt:165)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:873)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:99)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at android.os.Looper.loop(Looper.java:193)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6669)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
09-01 14:56:55.741 19119 19119 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)