1
1
using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Linq ;
2
4
using System . Text ;
3
- using System . Xml . Linq ;
4
5
using Android . Runtime ;
6
+ using Java . Interop . Tools . Cecil ;
5
7
using Java . Interop . Tools . Diagnostics ;
6
8
using Java . Interop . Tools . JavaCallableWrappers . CallableWrapperMembers ;
7
9
using Java . Interop . Tools . TypeNameMappings ;
@@ -18,25 +20,21 @@ public static CallableWrapperField CreateField (MethodDefinition method, string
18
20
?? throw new ArgumentException ( $ "Could not get JNI signature for method `{ method . Name } `", nameof ( method ) ) ;
19
21
var annotations = JavaCallableWrapperGenerator . GetAnnotationsString ( "\t " , method . CustomAttributes , resolver ) ;
20
22
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
+ } ;
28
28
}
29
29
30
30
// Temporary conversion function
31
31
public static CallableWrapperField CreateField ( JavaCallableWrapperGenerator . JavaFieldInfo field )
32
32
{
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
+ } ;
40
38
}
41
39
42
40
public static CallableWrapperMethod CreateMethod ( MethodDefinition method , RegisterAttribute register , IMetadataResolver cache , bool shouldBeDynamicallyRegistered = true )
@@ -190,21 +188,132 @@ public static CallableWrapperConstructor CreateConstructor (JavaCallableWrapperG
190
188
// Temporary conversion function
191
189
public static CallableWrapperType CreateType ( JavaCallableWrapperGenerator generator )
192
190
{
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 ) {
196
194
IsAbstract = generator . type . IsAbstract ,
197
195
ApplicationJavaClass = generator . ApplicationJavaClass ,
198
- Generator = generator ,
199
196
HasDynamicallyRegisteredMethods = generator . HasDynamicallyRegisteredMethods ,
200
197
GenerateOnCreateOverrides = generator . GenerateOnCreateOverrides ,
201
198
MonoRuntimeInitialization = generator . MonoRuntimeInitialization ,
199
+ IsApplication = JavaNativeTypeManager . IsApplication ( generator . type , generator . cache ) ,
200
+ IsInstrumentation = JavaNativeTypeManager . IsInstrumentation ( generator . type , generator . cache ) ,
202
201
} ;
203
202
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
204
250
if ( generator . children is not null )
205
251
foreach ( var nested in generator . children )
206
252
type . NestedTypes . Add ( CreateType ( nested ) ) ;
207
253
208
254
return type ;
209
255
}
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
+ }
210
319
}
0 commit comments