You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[generator] Emit events for addListener(Listener,Handler) pattern (#458)
When [generating events][0], given a Java `Listener` interface and an
"add" method which takes the listener, `generator` will emit an event
for each method on the listener interface, and all method parameters
will become properties on a generated `EventArgs`. For example,
consider [`android.view.TextureView`][1]:
// Java
public class TextureView {
public interface SurfaceTextureListener {
void onSurfaceTextureAvailable (SurfaceTexture surface, int width, int height);
void onSurfaceTextureDestroyed (SurfaceTexture surface);
void onSurfaceTextureChanged (SurfaceTexture surface, int width, int height);
void onSurfaceTextureUpdated (SurfaceTexture surface);
}
public void setSurfaceTextureListener(SurfaceTextureListener listener);
}
`generator` will ["eventify" `TextureView` into][2]:
// C#
public partial class TextureView {
public interface ISurfaceTextureListener {
void OnSurfaceTextureAvailable (SurfaceTexture surface, int width, int height);
void OnSurfaceTextureDestroyed (SurfaceTexture surface);
void OnSurfaceTextureChanged (SurfaceTexture surface, int width, int height);
void OnSurfaceTextureUpdated (SurfaceTexture surface);
}
public partial class SurfaceTextureAvailableEventArgs {
public SurfaceTexture Surface {get;}
public int Width {get;}
pbulic int Height {get;}
}
public event EventHandler<SurfaceTextureAvailableEventArgs> SurfaceTextureAvailable;
public partial class SurfaceTextureDestroyedEventArgs {
public SurfaceTexture Surface {get;}
}
public event EventHandler<SurfaceTextureDestroyedEventArgs> SurfaceTextureDestroyed;
public partial class SurfaceTextureChangedEventArgs {
public SurfaceTexture Surface {get;}
public int Width {get;}
pbulic int Height {get;}
}
public event EventHandler<SurfaceTextureChangedEventArgs> SurfaceTextureChanged;
public partial class SurfaceTextureUpdatedEventArgs {
public SurfaceTexture Surface {get;}
}
public event EventHandler<SurfaceTextureUpdatedEventArgs> SurfaceTextureUpdated;
}
A requirement of the "event pattern" was that the "add" method must:
1. Start with `add` or `set`, e.g. `setSurfaceTextureListener()`.
2. Have a return type of `void`.
3. Have a *single* parameter which is an interface containing
`Listener` as a suffix.
As time has gone on, we've found a slight variation on this pattern
that we believe `generator` should natively support:
4. *Or*, the "add" method should have *two* parameters, the first
being an interface type with a `Listener` suffix, and the second
parameter is of type `Android.OS.Handler`.
When we encounter (4), we can emit a "Event_With_Handler_Helper"
method which calls the "add" method, passing `null` as the `Handler`
parameter.
The addition of (4) allows us to generate events for the
[`android.media.AudioRouting.OnRoutingChangedListener`][3]
interface on the [`android.media.AudioRecord`][4] type, which
provides the method:
// Java
class AudioRecord {
public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, Handler handler);
}
This would allow `generator` to emit an `AudioRecord.RoutingChanged`
event, a'la:
public event EventHandler<Android.Media.AudioRoutingOnRoutingChangedEventArgs> RoutingChanged {
add {
global::Java.Interop.EventHelper.AddEventHandler<Android.Media.IAudioRoutingOnRoutingChangedListener, Android.Media.IAudioRoutingOnRoutingChangedListenerImplementor>(
ref weak_implementor_AddOnRoutingChangedListener,
__CreateIAudioRoutingOnRoutingChangedListenerImplementor,
AddOnRoutingChangedListener_Event_With_Handler_Helper,
__h => __h.Handler += value);
}
remove {
global::Java.Interop.EventHelper.RemoveEventHandler<Android.Media.IAudioRoutingOnRoutingChangedListener, Android.Media.IAudioRoutingOnRoutingChangedListenerImplementor>(
ref weak_implementor_AddOnRoutingChangedListener,
Android.Media.IAudioRoutingOnRoutingChangedListenerImplementor.__IsEmpty,
__v => RemoveOnRoutingChangedListener (__v),
__h => __h.Handler -= value);
}
}
void AddOnRoutingChangedListener_Event_With_Handler_Helper (Android.Media.IAudioRoutingOnRoutingChangedListener value)
{
AddOnRoutingChangedListener (value, null);
}
Additionally, update `generate.sh` script to include API-29.
[0]: https://docs.microsoft.com/en-us/xamarin/android/internals/api-design#events-and-listeners
[1]: https://developer.android.com/reference/android/view/TextureView
[2]: https://docs.microsoft.com/en-us/dotnet/api/android.views.textureview?view=xamarin-android-sdk-9#events
[3]: https://developer.android.com/reference/android/media/AudioRouting.OnRoutingChangedListener.html
[4]: https://developer.android.com/reference/android/media/AudioRecord.html
[5]: https://developer.android.com/reference/android/media/AudioRecord.html#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener,%20android.os.Handler)
@@ -914,8 +922,11 @@ public void WriteInterfaceListenerEventOrProperty (InterfaceGen @interface, Meth
914
922
if(opt.GetSafeIdentifier(name)!=name){
915
923
Report.Warning(0,Report.WarningInterfaceGen+5,"event name for {0}.{1} is invalid. `eventName' or `argsType` can be used to assign a valid member name.",@interface.FullName,name);
Report.Warning(0,Report.WarningInterfaceGen+6,"event property name for {0}.{1} is invalid. `eventName' or `argsType` can be used to assign a valid member name.",@interface.FullName,name);
0 commit comments