Skip to content

Commit 75a51fd

Browse files
authored
Fix R8 stripping BaseOnChangeListener/BaseOnSliderTouchListener in Release builds (#1502)
Instead of removing the base interfaces entirely (PR #1486), keep them intact with their methods so the binding generator produces Implementor ACW classes. These Java ACWs contain 'implements BaseOnChangeListener' which gives R8 a concrete Java reference — preventing it from stripping the types at link time. The implements chain from typed sub-interfaces (Slider.OnChangeListener etc.) to the base interfaces is still broken to prevent ACW erasure clash (#1482). The auto-generated add/remove methods on BaseSlider are still removed and replaced with hand-written typed overloads in Additions. This hybrid approach provides: - Typed API: AddOnChangeListener(Slider.IOnChangeListener) as Android recommends - No erasure clash: implements chain broken between typed and base interfaces - R8 safe: Implementor ACWs reference base types in Java — no ProGuard needed - Events: Change/StartTrackingTouch/StopTrackingTouch hand-written in Additions Fixes #1501
1 parent a29c286 commit 75a51fd

3 files changed

Lines changed: 58 additions & 22 deletions

File tree

config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3518,7 +3518,7 @@
35183518
"groupId": "com.google.android.material",
35193519
"artifactId": "material",
35203520
"version": "1.14.0",
3521-
"nugetVersion": "1.14.0.5",
3521+
"nugetVersion": "1.14.0.6",
35223522
"nugetId": "Xamarin.Google.Android.Material",
35233523
"comments": "Requires API-34"
35243524
},

source/com.google.android.material/material/PublicAPI/PublicAPI.Unshipped.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,10 +1978,20 @@ Google.Android.Material.SideSheet.SideSheetDialog
19781978
Google.Android.Material.SideSheet.SideSheetDialog.SideSheetDialog(Android.Content.Context! context) -> void
19791979
Google.Android.Material.SideSheet.SideSheetDialog.SideSheetDialog(Android.Content.Context! context, int theme) -> void
19801980
Google.Android.Material.SideSheet.SideSheetDialog.SideSheetDialog(nint javaReference, Android.Runtime.JniHandleOwnership transfer) -> void
1981+
Google.Android.Material.Slider.BaseOnChangeEventArgs
1982+
Google.Android.Material.Slider.BaseOnChangeEventArgs.BaseOnChangeEventArgs(Java.Lang.Object! p0, float p1, bool p2) -> void
1983+
Google.Android.Material.Slider.BaseOnChangeEventArgs.P0.get -> Java.Lang.Object!
1984+
Google.Android.Material.Slider.BaseOnChangeEventArgs.P1.get -> float
1985+
Google.Android.Material.Slider.BaseOnChangeEventArgs.P2.get -> bool
19811986
Google.Android.Material.Slider.BasicLabelFormatter
19821987
Google.Android.Material.Slider.BasicLabelFormatter.BasicLabelFormatter() -> void
19831988
Google.Android.Material.Slider.BasicLabelFormatter.GetFormattedValue(float value) -> string!
19841989
Google.Android.Material.Slider.BasicLabelFormatter.InterfaceConsts
1990+
Google.Android.Material.Slider.IBaseOnChangeListener
1991+
Google.Android.Material.Slider.IBaseOnChangeListener.OnValueChange(Java.Lang.Object! p0, float p1, bool p2) -> void
1992+
Google.Android.Material.Slider.IBaseOnSliderTouchListener
1993+
Google.Android.Material.Slider.IBaseOnSliderTouchListener.OnStartTrackingTouch(Java.Lang.Object! p0) -> void
1994+
Google.Android.Material.Slider.IBaseOnSliderTouchListener.OnStopTrackingTouch(Java.Lang.Object! p0) -> void
19851995
Google.Android.Material.Slider.ILabelFormatter
19861996
Google.Android.Material.Slider.ILabelFormatter.GetFormattedValue(float p0) -> string!
19871997
Google.Android.Material.Slider.ISliderOrientation
@@ -2047,6 +2057,12 @@ Google.Android.Material.Slider.Slider.StopTrackingTouchEventArgs.P0.get -> Googl
20472057
Google.Android.Material.Slider.Slider.StopTrackingTouchEventArgs.StopTrackingTouchEventArgs(Google.Android.Material.Slider.Slider! p0) -> void
20482058
Google.Android.Material.Slider.SliderOrientation
20492059
Google.Android.Material.Slider.SliderOrientationConsts
2060+
Google.Android.Material.Slider.StartTrackingTouchEventArgs
2061+
Google.Android.Material.Slider.StartTrackingTouchEventArgs.P0.get -> Java.Lang.Object!
2062+
Google.Android.Material.Slider.StartTrackingTouchEventArgs.StartTrackingTouchEventArgs(Java.Lang.Object! p0) -> void
2063+
Google.Android.Material.Slider.StopTrackingTouchEventArgs
2064+
Google.Android.Material.Slider.StopTrackingTouchEventArgs.P0.get -> Java.Lang.Object!
2065+
Google.Android.Material.Slider.StopTrackingTouchEventArgs.StopTrackingTouchEventArgs(Java.Lang.Object! p0) -> void
20502066
Google.Android.Material.Slider.TickVisibilityMode
20512067
Google.Android.Material.Slider.TickVisibilityModeAttribute
20522068
Google.Android.Material.Slider.TickVisibilityModeAttribute.TickVisibilityModeAttribute() -> void

source/com.google.android.material/material/Transforms/Metadata.xml

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -319,35 +319,55 @@
319319
com.google.android.material.appbar.AppBarLayout
320320
</attr>
321321

322-
<!-- Remove deprecated BaseOnChangeListener and BaseOnSliderTouchListener interfaces entirely.
323-
These base interfaces use erased generics that cause ACW type erasure clashes when
324-
implemented alongside their typed sub-interfaces (Slider.OnChangeListener, etc.).
325-
The binding generator creates Implementor Java classes for any interface referenced in
326-
add/removeListener pairs, but these implementors cannot satisfy the Java abstract method
327-
contracts because of the erasure. Removing the base interfaces eliminates the
328-
implementor generation (no interface type → no implementor). -->
329-
<remove-node
330-
path="/api/package[@name='com.google.android.material.slider']/interface[@name='BaseOnChangeListener']" />
331-
<remove-node
332-
path="/api/package[@name='com.google.android.material.slider']/interface[@name='BaseOnSliderTouchListener']" />
322+
<!-- Fix BaseSlider addOnChangeListener and removeOnChangeListener methods -->
323+
<attr
324+
path="/api/package[@name='com.google.android.material.slider']/class[@name='BaseSlider']/method[@name='addOnChangeListener' and count(parameter)=1 and parameter[1][@type='L']]/parameter[1]"
325+
name="type"
326+
>
327+
com.google.android.material.slider.BaseOnChangeListener
328+
</attr>
329+
<attr
330+
path="/api/package[@name='com.google.android.material.slider']/class[@name='BaseSlider']/method[@name='removeOnChangeListener' and count(parameter)=1 and parameter[1][@type='L']]/parameter[1]"
331+
name="type"
332+
>
333+
com.google.android.material.slider.BaseOnChangeListener
334+
</attr>
335+
336+
<!-- Fix BaseSlider addOnSliderTouchListener and removeOnSliderTouchListener methods -->
337+
<attr
338+
path="/api/package[@name='com.google.android.material.slider']/class[@name='BaseSlider']/method[@name='addOnSliderTouchListener' and count(parameter)=1 and parameter[1][@type='T']]/parameter[1]"
339+
name="type"
340+
>
341+
com.google.android.material.slider.BaseOnSliderTouchListener
342+
</attr>
343+
<attr
344+
path="/api/package[@name='com.google.android.material.slider']/class[@name='BaseSlider']/method[@name='removeOnSliderTouchListener' and count(parameter)=1 and parameter[1][@type='T']]/parameter[1]"
345+
name="type"
346+
>
347+
com.google.android.material.slider.BaseOnSliderTouchListener
348+
</attr>
333349

334-
<!-- Remove the 'implements BaseOnChangeListener/BaseOnSliderTouchListener' from the typed
335-
sub-interfaces so they don't reference the now-removed base types.
336-
This makes them standalone interfaces with just their typed methods. -->
350+
<!-- Break the implements chain from typed sub-interfaces to the @RestrictTo base interfaces.
351+
This prevents ACW erasure clash when users implement Slider.IOnChangeListener or
352+
Slider.IOnSliderTouchListener — without this, the ACW generates both onValueChange(Object)
353+
and onValueChange(Slider), which have the same Java erasure. (#1482)
354+
The base interfaces and their methods remain intact, so the Implementor ACWs compile
355+
and their Java references keep the types alive for R8. -->
337356
<remove-node
338357
path="/api/package[@name='com.google.android.material.slider']/interface[@name='Slider.OnChangeListener']/implements[@name='com.google.android.material.slider.BaseOnChangeListener']" />
339-
<remove-node
340-
path="/api/package[@name='com.google.android.material.slider']/interface[@name='Slider.OnSliderTouchListener']/implements[@name='com.google.android.material.slider.BaseOnSliderTouchListener']" />
341358
<remove-node
342359
path="/api/package[@name='com.google.android.material.slider']/interface[@name='RangeSlider.OnChangeListener']/implements[@name='com.google.android.material.slider.BaseOnChangeListener']" />
360+
<remove-node
361+
path="/api/package[@name='com.google.android.material.slider']/interface[@name='Slider.OnSliderTouchListener']/implements[@name='com.google.android.material.slider.BaseOnSliderTouchListener']" />
343362
<remove-node
344363
path="/api/package[@name='com.google.android.material.slider']/interface[@name='RangeSlider.OnSliderTouchListener']/implements[@name='com.google.android.material.slider.BaseOnSliderTouchListener']" />
345364

346-
<!-- Remove the add/remove listener methods from BaseSlider to prevent implementor generation.
347-
These methods reference the removed base interfaces as parameter types. We re-implement
348-
them manually in Additions with typed overloads (Slider.IOnChangeListener, etc.) that
349-
use the correct JNI signatures. This is a standard binding pattern: remove problematic
350-
auto-generated method, replace with hand-written Additions code. -->
365+
<!-- Remove the auto-generated add/remove listener methods from BaseSlider (which accept
366+
IBaseOnChangeListener/IBaseOnSliderTouchListener) and re-add them via hand-written
367+
Additions with typed params (Slider.IOnChangeListener etc.) for the Android-recommended API.
368+
Keeping the base interfaces intact ensures their Implementor ACWs generate Java code that
369+
references BaseOnChangeListener/BaseOnSliderTouchListener, preventing R8 from stripping
370+
the types at link time. -->
351371
<remove-node
352372
path="/api/package[@name='com.google.android.material.slider']/class[@name='BaseSlider']/method[@name='addOnChangeListener']" />
353373
<remove-node

0 commit comments

Comments
 (0)