-
Notifications
You must be signed in to change notification settings - Fork 565
[Mono.Android] Fix setColor (int) / setColor (long) issue. #6617
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
de43971 to
6ba9112
Compare
| <attr path="/api/package[@name='android.content.res']/class[@name='TypedArray']/method[@name='getColor']" name="return">Android.Graphics.Color</attr> | ||
| <attr path="/api/package[@name='android.graphics']/class[@name='Paint']/method[@name='getColor']" name="return">Android.Graphics.Color</attr> | ||
| <attr path="/api/package[@name='android.graphics']/class[@name='Paint']/method[@name='setColor']/parameter[position()=1]" name="type">Android.Graphics.Color</attr> | ||
| <attr path="/api/package[@name='android.graphics']/class[@name='Paint']/method[@name='setColor' and parameter[1][@type='int']]/parameter[position()=1]" name="type">Android.Graphics.Color</attr> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we update every expression which replaces int with Android.Graphics.Color to check for @type, not just this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
Note the changes all should be no-ops, as there does not currently exist a long version. But this will help ensure that if a long version is added we won't break.
Fixes: https://github.com/xamarin/xamarin-android/issues/6606
Before API-29, the [`android.graphics.Paint`][0] class had a "color"
property:
// Android Java
/* partial */ class Paint {
public int getColor();
public void setColor(int color);
}
These methods were bound into a C# `Paint.Color` property:
// API-28 C# Binding
partial class Paint {
public virtual Android.Graphics.Color Color {
[Register ("getColor", "()I", …)] get;
[Register ("setColor", "(I)V", …)] set;
}
}
In API-29 (bound in 936a09d1), a "colorLong" property was added via
[`Paint.getColorLong()`][1] and [`Paint.setColor(long)`][2]
// Android Java
/* partial */ class Paint {
public int getColor();
public void setColor(int color);
public long getColorLong();
public void setColor(long color);
}
Unfortunately, the "colorLong" property was mis-bound:
`Paint.setColor(long)` was "associated" with the existing `Color`
property, and `Paint.getColorLong()` was bound as a read-only property:
// API-29 C# Binding
partial class Paint {
public virtual Android.Graphics.Color Color {
[Register ("getColor", "()I", …)] get;
[Register ("setColor", "(I)V", ApiSince=29, …)] set;
}
public virtual long ColorLong {
[Register ("getColorLong", "()J", ApiSince=29, …)] get;
}
}
Note that the "association" was in the form of updating
`RegisterAttribute.ApiSince`, but it did *not* update the method
which was invoked; `Paint.setColor(int)` was still invoked.
Consequently, code attempting to use the `Paint.Color` setter would
get a [CA1416 warning][3] when building under .NET 6+:
partial class MyDrawable : ShapeDrawable {
public MyDrawable() : base (new RectShape())
{
Paint.Color = Color.Black;
// Warning CA1416 : This call site is reachable on: 'Android' 21.0 and later. 'Paint.Color.set' is only supported on: 'android' 29.0 and later.
}
}
The `Color` property was updated to "associate" (and ignore) the
`setColor(long)` method because `src/Mono.Android/metadata` only
checked parameter names and not parameter *types* when replacing
`int`s with `Color`s:
<attr
path="/api/package[@name='android.graphics']/class[@name='Paint']/method[@name='setColor']/parameter[position()=1]"
name="type"
>Android.Graphics.Color</attr>
Fix this by updating the above XPath expression to check the
parameter type:
<attr
path="/api/package[@name='android.graphics']/class[@name='Paint']/method[@name='setColor' and parameter[1][@type='int']]/parameter[position()=1]"
name="type"
>Android.Graphics.Color</attr>
and also add metadtata to state that `setColor(long)` should *not*
be associated with a property, by clearing the `propertyName` value:
<attr
api-since="29"
path="/api/package[@name='android.graphics']/class[@name='Paint']/method[@name='setColor' and count(parameter)=1 and parameter[1][@type='long']]"
name="propertyName"
></attr>
This results in the following C# binding:
// Fixed API-29 C# Binding
partial class Paint {
public virtual Android.Graphics.Color Color {
[Register ("getColor", "()I", …)] get;
[Register ("setColor", "(I)V", …)] set;
}
public virtual long ColorLong {
[Register ("getColorLong", "()J", ApiSince=29, …)] get;
}
[Register ("setColor", "(J)V", ApiSince=29, …)]
public virtual void SetColor (long color);
}
[0]: https://developer.android.com/reference/android/graphics/Paint
[1]: https://developer.android.com/reference/android/graphics/Paint#getColorLong()
[2]: https://developer.android.com/reference/android/graphics/Paint#setColor(long)
[3]: https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1416 |
|
Aside: this So, yay? |
|
@jpobst: another problem that comes to mind: I think this is (kinda) an API break, because it means existing code which does: partial class MyPaint : Paint {
public override long ColorLong => …
}will no longer compile, as it's missing the property setter in the override. I thus think we may want to de-propertify partial class Paint {
public virtual long ColorLong {get;}
public virtual void SetColor(long color);
} |
Updated. |
Fixes #6606
Android provides the following
Android.Graphics.Paint.Colorgetter/setter "pairs":We have
metadatawhich converts Android "Color-ints" intoAndroid.Drawing.Colorobjects, however in thesetColorcase it is only checking method name and not parameter types, so it is being applied to bothsetColoroverloads:Our annotation code then applies the "API-29+" data to both matching method signatures, and our Property combining code matches both of them, removing both methods and producing:
By updating metadata:
setColor (long)aslongsetColor (long)should not by "prop-ified"`we can get the desired results:
Note we have chosen not to add the
longsetter to the existing getter because the property isvirtual, and adding the setter would break users who have overridden the property.