The plugin's on-device proof (Mob.Plugin.SelfTest), run by
mix mob.selftest and mob_ci for every activated plugin.
touch_start/1 installs the observer for the calling process, the test
checks what comes back, and touch_stop/0 removes the observer again.
- Android: after
touch_start/1answers:ok, the test puts a synthetic finger down at (8, 8) dp with mob's in-process:mob_nif.press_down_xy/3, which dispatches realMotionEvents at the window's decor view (the path a finger takes throughWindow.Callback). The finger is never lifted: mob's bridge cancels it after 100 ms, or at once when no view consumed the down ({:error, :dispatch_failed}, the corner of a blank screen), so nothing on the host's screen is ever clicked. The test passes when the observer delivers{:touch, %{phase: :down}}and then:cancel(or:up) at those dp coordinates: the zig NIF is linked, the KotlinMobTouchBridgeregistered and has the Activity, its observer sits in the window's callback chain and thenativeDeliverTouchthunk reaches the BEAM in dp. The observer is installed asynchronously on the UI thread, so an injection that overtook the install is retried once before the test fails.{:error, :bridge_not_registered}from the NIF, or no touch for either injection, fails. When the host cannot inject (:not_loadedfrom a generatedMobBridge.ktolder than the held-press methods,:no_window,:timeout, a finger already held) the test cannot observe anything and skips, saying why. - iOS: mob has no in-process touch injection that reaches UIKit
(
press_down_xy/3answers{:error, :not_supported}), so the proof is the native round trip:touch_start/1andtouch_stop/0must both answer:okfrom the Objective-C NIF, which queues theUIGestureRecognizerinstall and removal on the main queue.
The host stub's nif_not_loaded is a failure. The observer follows the
last caller of touch_start/1, so a screen that was streaming touches
when the test ran stops receiving them until it calls MobTouch.start/2
again.