[mono-android] Problem with WindowManager

Jonathan Pryor jpryor at novell.com
Tue Mar 15 13:04:09 EDT 2011


On Mar 15, 2011, at 11:23 AM, Narcís Calvet wrote:
> I’m trying to get the display size using the code below in an Activity.
>  
>       Java.Lang.Object windowService = this.GetSystemService(Android.Content.Context.WindowService);
>       Android.Views.IWindowManager windowManager = windowService as Android.Views.IWindowManager;
>       Android.Views.Display display = windowManager.DefaultDisplay;
>       String str = display.Width.ToString() + " x " + display.Height.ToString();
>  
> I’d bet this worked last week.

Much as the mailing list is currently blaming Preview 14 for breakage...  I doubt it. :-)  (The relevant code hasn't changed in ages.)

> Has there been any change in this field in preview 14? Do I miss anything? The line where the code fails is when casting the windowService object to Android.Views.IWindowManager. The debugger says it’s a android.view.Window$LocalWindowManager but this type is not available.

The fix is to use Extensions.JavaCast<T>() [0]:

	var windowService = this.GetSystemService(Android.Content.Context.WindowService);
	var windowManager = windowService.JavaCast<Android.Views.IWindowManager>();
	// ...

The problem is that there are two type systems involved in Mono for Android, the Android/Java type system, and the Mono type system. Mono for Android attempts to bridge the two separate runtimes, but occasionally it breaks down, and this is one such circumstance.

What's happening is that GetSystemService(Android.Content.Context.WindowService) is returning an undocumented, internal, Java type (android.view.Window$LocalWindowManager). Because this type is undocumented, we don't (and can't) generate a managed wrapper for the type. Consequently, when Java.Lang.Object.GetObject<T>(IntPtr,bool) tries to find the "most derived" wrapper type, all it can find is Java.Lang.Object [1], and thus `windowService.GetType().FullName` is Java.Lang.Object.

Java.Lang.Object can't be cast to an IWindowManager interface, which is why your `as IWindowManager` returns null.

The correct fix is to use the Extensions.JavaCast<T>() extension method, which will perform a runtime Java-VM check to see if the instance can be cast to the IWindowManager interface, and then construct an appropriate proxy if the runtime check succeeds.

 - Jon

[0] http://docs.mono-android.net/index.aspx?link=M%3aAndroid.Runtime.Extensions.JavaCast``1(Android.Runtime.IJavaObject)

[1] This is arguably a bug, as it currently only checks for types and not implemented interfaces, but this behavior won't be changing anytime soon, either.



More information about the Monodroid mailing list