We have learned a lot about the Uno Platform in the first and second part of this series. In this article, we pick up right where we left off and continue implementing APIs of the
DisplayInformation class for Android and iOS. As I mentioned last time, I will not dive too much into platform specifics and will instead focus on Uno in general. Let’s dig in!
When required API does not exist
DiagonalSizeInInches properties are quite unusual in that they can be implemented on Android, but not on iOS.
All we need on Android is the
DisplayMetrics the instance we created last time using
On iOS, the situation is different. No API returns physical information about the display (except for native scaling and raw screen size as we saw earlier). How do we solve such a situation?
The common solution, in similar cases, would be to implement the property for Android only (by moving it into the Android-specific code file and protecting it using
#if __ANDROID__ directive). Doing this is not as bad as it sounds – Uno comes with a Roslyn analyzer which automatically indicates to the app developer that an API is not implemented on the platform they are targeting. This way they know the API must be handled with care and should use platform-specific code instead.
However, we must also remember, that Uno’s philosophy is to match UWP behavior first – and that is very helpful here. When we check the Remarks section of
RawDpiY documentation, we can find the following (emphasis mine):
This property can return 0 when the monitor doesn’t provide physical dimensions and when the user is in a clone or duplicate multiple-monitor setup.
This is exactly our case! iOS does not provide physical dimensions of the display and hence we can default the property value to
DiagonalSizeInInches (emphasis mine):
Returns the diagonal size of the display in inches. May return null when display size information is not available or undetermined (when connected to a projector, or displays are duplicated).
null is the appropriate solution here, too.
In my PR I have added a
<remarks> comment section to describe the reasoning behind the default values with a link using the
DisplayInformation has another interesting property –
StereoEnabled. Docs say:
Gets a value that indicates whether the device supports stereoscopic 3D.
I know iOS devices don’t support stereoscopic 3D. Android market is broad, and there are a few devices with a similar feature (see Wikipedia). Nonetheless, there is no support built into the OS, the feature is extremely niche and no clear API can tell us whether the device supports it. For now, I decided to keep things simple and return
false by default:
Handling orientation change on Android
While writing the second part of this blog post series, I noticed that I missed an important detail while implementing my PR. Originally I assumed that the
OrientationChanged event was already implemented for both iOS and Android, so I assumed the
CurrentOrientation property works and reports orientation correctly as it changes. But I was wrong. The
OrientationChanged event was implemented on iOS only and Android had set the
CurrentOrientation only during the initialization of the
Although I originally planned to implement only the properties of the
DisplayInformation class, the
OrientationChanged event is key and so is making sure
CurrentOrientation property reports reliable values.
On Android there is no event on orientation change. Instead, Android’s default behavior is to destroy and re-create the
Activity when the device orientation changes. Uno uses a single
Activity which derives from
Windows.UI.Xaml.AndroidActivity and this base class opts-out of the default behavior by handling the
[Activity] attribute in place, Android triggers the
OnConfigurationChanged method when either orientation or screen size changes.
I plugged in a call to (not yet existing)
We wouldn’t like to have the
public, but luckily we don’t need to. The
AssemblyInfo.cs file in the
Uno project contains the following:
If you are not familiar with the
System.Runtime.CompilerServices.InternalsVisibleToAttribute, it allows an assembly to state that another assembly should be allowed to access its
internal members. This is very useful when writing unit tests, but in this case, it is a very crucial feature as well. When we mark
HandleConfigurationChange internal, it will be available in the
Uno.UI projects, so it can be used when developing Uno, but it will not clutter the public interface, which is great indeed.
Last missing piece of the puzzle is implementing the
First I cache the
CurrentOrientation value in
previousOrientation variable and then re-run the
Initialize method of
DisplayInformation to update all its properties, as configuration change could also be a
ScreenSize change so it could affect more properties.
Finally, I compare the “new” current orientation with the cached value to see if the
OrientationChanged event should be invoked.
The remainder of the implementation is not as interesting from the Uno point of view, so I will omit it in this blog post. If you are interested, you can check it out the full changelog of my PR on GitHub.
Creating the pull request
Now that we have everything implemented, let’s create our pull request! When you push your branch to GitHub and browse the fork homepage, it will automatically suggest you to create a pull request from your branch. You can also do it using the New pull request button:
We first make sure to allow comparing across forks, select our fork and select Uno
master branch as target:
Uno provides a default pull request description template:
- GitHub Issue – provide the ID of the issue you were resolving. Once you start writing the number after
#character you should get useful autocomplete
- PR type – PR’s primary goal, in our case Feature
- What is the current behavior – describe behavior as is in the current master branch
- What is the new behavior – describe behavior in the branch you are merging
- PR Checklist – things to do before creating the pull request. Not all are applicable to all pull requests, but still serve as a nice reminder of what is expected. For example, it is easy to forget to update the Release Notes doc file, which can be found in the
docfolder of the cloned solution.
One everything is filled out properly, we can either create a Draft pull request, which signifies that the changes are not yet complete, but can be useful for work in progress for which you would like to get some feedback. If you are ready though, click the Create pull request button your PR will be ready for review!
Our pull request is out for review! We have walked through the whole process of contributing our first pull request in the Uno Platform in this three-part series. I hope you enjoyed the posts and got excited about Uno and its potential.youage you to contribute as well – you can help the project grow and you can learn plenty of new things in the process – and that’s always awesome!
I hope you enjoyed this series, you can expect more Uno content on this blog in the future as well. Subscribe to the newsletter, RSS or push notifications and see you next time!