11using System ;
2+ using System . Collections . Generic ;
3+ using System . Linq ;
24using System . Text ;
3- using System . Xml . Linq ;
45using Android . Runtime ;
6+ using Java . Interop . Tools . Cecil ;
57using Java . Interop . Tools . Diagnostics ;
68using Java . Interop . Tools . JavaCallableWrappers . CallableWrapperMembers ;
79using Java . Interop . Tools . TypeNameMappings ;
@@ -18,25 +20,21 @@ public static CallableWrapperField CreateField (MethodDefinition method, string
1820 ?? throw new ArgumentException ( $ "Could not get JNI signature for method `{ method . Name } `", nameof ( method ) ) ;
1921 var annotations = JavaCallableWrapperGenerator . GetAnnotationsString ( "\t " , method . CustomAttributes , resolver ) ;
2022
21- return new CallableWrapperField (
22- fieldName : fieldName ,
23- typeName : type_name ,
24- visibility : visibility ,
25- isStatic : method . IsStatic ,
26- initializerName : method . Name ,
27- annotations : annotations ) ;
23+ return new CallableWrapperField ( fieldName , type_name , visibility ) {
24+ IsStatic = method . IsStatic ,
25+ InitializerName = method . Name ,
26+ Annotations = annotations
27+ } ;
2828 }
2929
3030 // Temporary conversion function
3131 public static CallableWrapperField CreateField ( JavaCallableWrapperGenerator . JavaFieldInfo field )
3232 {
33- return new CallableWrapperField (
34- fieldName : field . FieldName ,
35- typeName : field . TypeName ,
36- visibility : field . GetJavaAccess ( ) ,
37- isStatic : field . IsStatic ,
38- initializerName : field . InitializerName ,
39- annotations : field . Annotations ) ;
33+ return new CallableWrapperField ( field . FieldName , field . TypeName , field . GetJavaAccess ( ) ) {
34+ IsStatic = field . IsStatic ,
35+ InitializerName = field . InitializerName ,
36+ Annotations = field . Annotations
37+ } ;
4038 }
4139
4240 public static CallableWrapperMethod CreateMethod ( MethodDefinition method , RegisterAttribute register , IMetadataResolver cache , bool shouldBeDynamicallyRegistered = true )
@@ -190,21 +188,132 @@ public static CallableWrapperConstructor CreateConstructor (JavaCallableWrapperG
190188 // Temporary conversion function
191189 public static CallableWrapperType CreateType ( JavaCallableWrapperGenerator generator )
192190 {
193- var type = new CallableWrapperType ( generator . name , generator . package ) {
194- Type = generator . type ,
195- Cache = generator . cache ,
191+ var partial_assembly_qualified_name = generator . type . GetPartialAssemblyQualifiedName ( generator . cache ) ;
192+
193+ var type = new CallableWrapperType ( generator . name , generator . package , partial_assembly_qualified_name ) {
196194 IsAbstract = generator . type . IsAbstract ,
197195 ApplicationJavaClass = generator . ApplicationJavaClass ,
198- Generator = generator ,
199196 HasDynamicallyRegisteredMethods = generator . HasDynamicallyRegisteredMethods ,
200197 GenerateOnCreateOverrides = generator . GenerateOnCreateOverrides ,
201198 MonoRuntimeInitialization = generator . MonoRuntimeInitialization ,
199+ IsApplication = JavaNativeTypeManager . IsApplication ( generator . type , generator . cache ) ,
200+ IsInstrumentation = JavaNativeTypeManager . IsInstrumentation ( generator . type , generator . cache ) ,
202201 } ;
203202
203+ type . Annotations . AddRange ( CreateTypeAnnotations ( generator . type , generator . cache ) ) ;
204+
205+ // Extends
206+ var extendsType = GetJavaTypeName ( generator . type . BaseType , generator . cache ) ;
207+
208+ if ( extendsType == "android.app.Application" && generator . ApplicationJavaClass != null && ! string . IsNullOrEmpty ( generator . ApplicationJavaClass ) )
209+ extendsType = generator . ApplicationJavaClass ;
210+
211+ type . ExtendsType = extendsType ;
212+
213+ // Implemented interfaces
214+ foreach ( var ifaceInfo in generator . type . Interfaces ) {
215+ var iface = generator . cache . Resolve ( ifaceInfo . InterfaceType ) ;
216+
217+ if ( ! JavaCallableWrapperGenerator . GetTypeRegistrationAttributes ( iface ) . Any ( ) )
218+ continue ;
219+
220+ type . ImplementedInterfaces . Add ( GetJavaTypeName ( iface , generator . cache ) ) ;
221+ }
222+
223+ // Type constructors
224+ foreach ( var ctor in generator . ctors ) {
225+ if ( string . IsNullOrEmpty ( ctor . Params ) && type . IsApplication )
226+ continue ;
227+
228+ var ct = CreateConstructor ( ctor ) ;
229+
230+ ct . Name = type . Name ;
231+ ct . CannotRegisterInStaticConstructor = type . CannotRegisterInStaticConstructor ;
232+ ct . PartialAssemblyQualifiedName = type . PartialAssemblyQualifiedName ;
233+
234+ type . Constructors . Add ( ct ) ;
235+ }
236+
237+ // Application constructor
238+ if ( CreateApplicationConstructor ( type . Name , generator . type , generator . cache ) is CallableWrapperApplicationConstructor app_ctor )
239+ type . ApplicationConstructor = app_ctor ;
240+
241+ // Exported fields
242+ foreach ( var field in generator . exported_fields )
243+ type . Fields . Add ( CreateField ( field ) ) ;
244+
245+ // Methods
246+ foreach ( var method in generator . methods )
247+ type . Methods . Add ( CreateMethod ( method ) ) ;
248+
249+ // Nested types
204250 if ( generator . children is not null )
205251 foreach ( var nested in generator . children )
206252 type . NestedTypes . Add ( CreateType ( nested ) ) ;
207253
208254 return type ;
209255 }
256+
257+ static string GetJavaTypeName ( TypeReference r , IMetadataResolver cache )
258+ {
259+ TypeDefinition d = cache . Resolve ( r ) ;
260+ string ? jniName = JavaNativeTypeManager . ToJniName ( d , cache ) ;
261+ if ( jniName == null ) {
262+ Diagnostic . Error ( 4201 , Localization . Resources . JavaCallableWrappers_XA4201 , r . FullName ) ;
263+ throw new InvalidOperationException ( "--nrt:jniName-- Should not be reached" ) ;
264+ }
265+ return jniName . Replace ( '/' , '.' ) . Replace ( '$' , '.' ) ;
266+ }
267+
268+ public static IEnumerable < CallableWrapperTypeAnnotation > CreateTypeAnnotations ( TypeDefinition type , IMetadataResolver resolver )
269+ {
270+ foreach ( var ca in type . CustomAttributes ) {
271+ var annotation = CreateTypeAnnotation ( ca , resolver ) ;
272+
273+ if ( annotation is not null )
274+ yield return annotation ;
275+ }
276+ }
277+
278+ public static CallableWrapperTypeAnnotation ? CreateTypeAnnotation ( CustomAttribute ca , IMetadataResolver resolver )
279+ {
280+ var catype = resolver . Resolve ( ca . AttributeType ) ;
281+ var tca = catype . CustomAttributes . FirstOrDefault ( a => a . AttributeType . FullName == "Android.Runtime.AnnotationAttribute" ) ;
282+
283+ if ( tca is null )
284+ return null ;
285+
286+ var name_object = tca . ConstructorArguments [ 0 ] . Value ;
287+
288+ // Should never be hit
289+ if ( name_object is not string name )
290+ throw new ArgumentException ( $ "Expected a string for the first argument of the { nameof ( RegisterAttribute ) } constructor.", nameof ( ca ) ) ;
291+
292+ var annotation = new CallableWrapperTypeAnnotation ( name ) ;
293+
294+ foreach ( var p in ca . Properties ) {
295+ var pd = catype . Properties . FirstOrDefault ( pp => pp . Name == p . Name ) ;
296+ var reg = pd != null ? pd . CustomAttributes . FirstOrDefault ( pdca => pdca . AttributeType . FullName == "Android.Runtime.RegisterAttribute" ) : null ;
297+
298+ var key = reg != null ? ( string ) reg . ConstructorArguments [ 0 ] . Value : p . Name ;
299+ var value = ManagedValueToJavaSource ( p . Argument . Value ) ;
300+
301+ annotation . Properties . Add ( new System . Collections . Generic . KeyValuePair < string , string > ( key , value ) ) ;
302+ }
303+
304+ return annotation ;
305+ }
306+
307+ // FIXME: this is hacky. Is there any existing code for value to source conversion?
308+ static string ManagedValueToJavaSource ( object value )
309+ {
310+ if ( value is string )
311+ return "\" " + value . ToString ( ) . Replace ( "\" " , "\" \" " ) + '"' ;
312+ else if ( value . GetType ( ) . FullName == "Java.Lang.Class" )
313+ return value . ToString ( ) + ".class" ;
314+ else if ( value is bool )
315+ return ( ( bool ) value ) ? "true" : "false" ;
316+ else
317+ return value . ToString ( ) ;
318+ }
210319}
0 commit comments