From fef5a1aa54b3ca5de5d35d22cf2c4a893f5aee65 Mon Sep 17 00:00:00 2001 From: Phillip Davis Date: Wed, 8 Apr 2026 12:56:58 -0400 Subject: [PATCH] add SafeViewPager to guard ViewPager crash Android's ViewPager caches the active pointer id from ACTION_DOWN and later calls findPointerIndex(mActivePointerId) on MOVE events. When the OS delivers a MOVE whose pointer set no longer contains that id (a known multi-touch race), findPointerIndex returns -1 and getX(-1) throws IllegalArgumentException from native code, crashing the app: java.lang.IllegalArgumentException: invalid pointerIndex -1 for MotionEvent { action=MOVE, ... } at android.view.MotionEvent.nativeGetAxisValue(Native Method) at android.view.MotionEvent.getX(MotionEvent.java:2655) at androidx.viewpager.widget.ViewPager.onInterceptTouchEvent(ViewPager.java:2087) SafeViewPager wraps onInterceptTouchEvent and onTouchEvent in a try/catch and returns false on the exception, letting children handle the event and letting the pager recover on the next clean DOWN. Subsequent commits route the three ViewPager instances in the app through this class. A couple of places have implemented basically this exact workaround, e.g., https://github.com/signalapp/Signal-Android/blob/main/app/src/main/java/org/thoughtcrime/securesms/components/viewpager/HackyViewPager.java --- .../com/cheogram/android/SafeViewPager.java | 39 +++++++++++++++++++ .../android/WebviewAwareViewPager.java | 2 +- src/cheogram/res/layout/activity_welcome.xml | 4 +- .../layout/activity_start_conversation.xml | 4 +- 4 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 src/cheogram/java/com/cheogram/android/SafeViewPager.java diff --git a/src/cheogram/java/com/cheogram/android/SafeViewPager.java b/src/cheogram/java/com/cheogram/android/SafeViewPager.java new file mode 100644 index 0000000000000000000000000000000000000000..218e669844431ccf5ba0a561834b4b306a610991 --- /dev/null +++ b/src/cheogram/java/com/cheogram/android/SafeViewPager.java @@ -0,0 +1,39 @@ +package com.cheogram.android; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; + +// Works around a long-standing Android bug where ViewPager's onInterceptTouchEvent / +// onTouchEvent can trip over a stale mActivePointerId: a MOVE arrives whose pointer +// set no longer contains the id cached from the earlier DOWN, so findPointerIndex +// returns -1 and getX(-1) throws IllegalArgumentException from native code. Returning +// false means "not intercepting / not consuming", which lets children handle the +// event and lets the pager recover on the next clean DOWN. +public class SafeViewPager extends androidx.viewpager.widget.ViewPager { + public SafeViewPager(Context context) { + super(context); + } + + public SafeViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + try { + return super.onInterceptTouchEvent(ev); + } catch (IllegalArgumentException e) { + return false; + } + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + try { + return super.onTouchEvent(ev); + } catch (IllegalArgumentException e) { + return false; + } + } +} diff --git a/src/cheogram/java/com/cheogram/android/WebviewAwareViewPager.java b/src/cheogram/java/com/cheogram/android/WebviewAwareViewPager.java index 1d261541ca09aebd7d0229fe3b84e7ef8784523b..f60479eef71548864c92c41605342f670cf57969 100644 --- a/src/cheogram/java/com/cheogram/android/WebviewAwareViewPager.java +++ b/src/cheogram/java/com/cheogram/android/WebviewAwareViewPager.java @@ -5,7 +5,7 @@ import android.util.AttributeSet; import android.view.View; import android.webkit.WebView; -public class WebviewAwareViewPager extends androidx.viewpager.widget.ViewPager { +public class WebviewAwareViewPager extends SafeViewPager { public WebviewAwareViewPager(Context context) { super(context); } diff --git a/src/cheogram/res/layout/activity_welcome.xml b/src/cheogram/res/layout/activity_welcome.xml index a12023f683f1c4d5337448157a992f5a7458315e..7ac0fabcea76d996c880f53c5604dc413eab5b68 100644 --- a/src/cheogram/res/layout/activity_welcome.xml +++ b/src/cheogram/res/layout/activity_welcome.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - + - - +