Handle 1080p in Windows Phone like a Pro!

The change log for Windows Phone 8 update 3 (also known as GDR3) has been known for a few weeks and one of the new features is the added

support for bigger, higher-resolution screens

This is obviously only for new devices, with 5” or 6” screens using 1080p resolution, like the amazing Nokia Lumia 1520!

Here’s the complete list of Windows Phone supported resolutions, divided by aspect ratio:

  • 15:9
    • WVGA (480x800, 1.0x scale factor) - this is the only resolution available in WP7
    • WXGA (768x1280, 1.6x scale factor)
  • 16:9
    • 720p (720x1280, 1.5x scale factor)
    • 1080p (1080x1920, 2.25x scale factor) - only supported in the new large screen devices with WP8 update 3

As a Windows Phone developer/designer, you don’t need to know this!

All you need to do is design the interface in XAML for the 480x800 resolution, and it will automatically scale up using a fixed scale factor! How cool is that? :)

Now if you really want to know what is the device scale factor (maybe to create different app resolution-aware layouts), you can read the Application.Current.Host.Content.ScaleFactor (note: this property will return the scale factor * 100).

But there’s a catch: for the new 1080p devices, the scale factor is returned as 1.5x, just as the 720p devices, instead of the correct 2.25x…

To get the real scale factor, you can use the following code snippet:

public int ScaleFactor
{
get
{
object physicalScreenResolutionObject;
if (DeviceExtendedProperties.TryGetValue("PhysicalScreenResolution", out physicalScreenResolutionObject))
{
var physicalScreenResolution = (Size)physicalScreenResolutionObject;
return (int)(physicalScreenResolution.Width / 4.8);
}
return Application.Current.Host.Content.ScaleFactor;
}
}

In WP8 update 3 you can use DeviceExtendedProperties.TryGetValue("PhysicalScreenResolution", out physicalScreenResolutionObject) to retrieve the screen Size resolution in pixels, take the Width of it and divide it by 4.8 to know the correct scale factor.

If the call to DeviceExtendedProperties.TryGetValue fails it just means you don’t have a WP8 GDR3 device, and as such the device is not a 1080p device and you can just fallback to use the Application.Current.Host.Content.ScaleFactor approach!

The Cimbalino Windows Phone Toolkit way

Previous versions of Cimbalino Windows Phone Toolkit already had the IScreenInfoService to help handling this, and since version 3.2.0, you can also count on the added 1080p support! :)

Cimbalino Windows Phone Toolkit Updated to v3.2.0

Version 3.2.0 of Cimbalino Windows Phone Toolkit is now available!

This release is mostly a bug/performance fix; here’s the change log:

  • Added the WriteableBitmapExtensions, which provides a high-performance & low memory impact SavePng() method!
  • Improved the IScreenInfoService and ResolutionAwareUriConverter to contemplate 1080p screens
  • The usual improvements and bug fixes

Windows Phone Week

Windows Phone Week

Directly from the official site:

Windows Phone Week is a series of events created for the developer community by Windows Phone Developer MVPs.

The events are in nine countries, encouraging developers from around the world to explore app and gaming development.

Each event has a unique agenda, format and registration process so please check the details at the location nearest you.

Although at this stage only 9 countries are participating, there are plans to expand to other territories, so stay tuned! ;)

Windows Phone URI association deep links and the ampersand

A few weeks ago I stumbled on an issue while using ampersand (&) in a URI association deep link with query string parameters!

Let’s start by assuming I have a Windows Phone app capable of handling deep links with “my-app:” moniker. Now take a look at the following sample link:

my-app://do/stuff/?param1=a%26b&param2=c

We can easily see a query string with two parameters, and after decoding their values, we get param1 = "a&b" and param2 = "c".

If we use the Launcher.LaunchUriAsync(uri) method to open the link, this is what will arrive in the internal UriMapper:

/Protocol?encodedLaunchUri=my-app%3A%2F%2Fdo%2Fstuff%2F%3Fparam1%3Da%2526b%26param2%3Dc

By retrieving and decoding the encodedLaunchUri from the previous link, the result will be "my-app://do/stuff/?param1=a%26b&param2=c", matching the original uri, as we would expect!

If we now use a web page with that link on it instead, open the page inside Internet Explorer on the phone and tap on the link, this is what will get to the app UriMapper:

/Protocol?encodedLaunchUri=my-app%3A%2F%2Fdo%2Fstuff%2F%3Fparam1%3Da%26b%26param2%3Dc

If we do as before and retrieve and decode the encodedLaunchUri, we will get "my-app://do/stuff/?param1=a&b&param2=c", which in this case, doesn’t match the original deep link!

This behavior is due to Internet Explorer in Windows Phone, as it seems to decode all links before trying to navigate to them, and when it can’t perform the navigation (e.g. when the link isn’t a http:// or https:// link) it just sends it to the platform to handle it, but by that time the link has already been wrongly re-encoded!

So far I haven’t been able to find any way of bypassing this issue, apart of simply not using the & in my apps deep links… and my advice to you is to proceed just like this!

Cimbalino Windows Phone Toolkit: AutoFocusBehavior

Most desktop applications use the Tab key to jump focus from one control to the next one, and this is expected behavior and common knowledge to most users.

On Android, the on-screen keyboard normally shows a “Next” key to - yes, you’ve guessed it! - go to the next field, and that is something really useful when filling long forms!

In truth, some native Windows Phone apps actually do this on some fields, where tapping the Enter key will have the same result, but unfortunately this is not the default behavior.

You could simulate this behavior using the TextBox.KeyUp or TextBox.KeyDown events, and then calling Control.Focus() on the next control you want to get focus, but I guess we can all agree that this is quite some work and if you change the fields order, you’d have to change the code accordingly.

The Cimbalino Windows Phone Toolkit way

Well, as of Cimbalino Windows Phone Toolkit version 3.1.0, all you need to do is add the AutoFocusBehavior to your Page and… relax! :)

Yes, that’s really all it takes, as the behavior contains the everything needed to manage TextBox/PasswordBox control focus changes on Enter key, with some added bonus:

  • TabIndex property value from controls will be taken into account and the order will be respected
  • Any control with IsEnabled = false, Visibility = Collapsed, or TabStop = false will be skipped
  • Any TextBox control with AcceptsEnter = true will just use the default expected behavior (tapping Enter will just add a new line)
  • The AutoFocusBehavior.CycleNavigation property controls whether focus will jump from last control to first one or just focus the full page
  • The AutoFocusBehavior.SelectAllOnFocus property controls whether the entire contents of a control will be selected on focus

There is also an AfterAutoFocus event and AfterAutoFocusCommand so you can easily add some extra behavior of yours to the current one! :)

Cimbalino Windows Phone Toolkit Updated to v3.1.0

Version 3.1.0 of Cimbalino Windows Phone Toolkit is now available!

Here’s the change-log for this release:

  • New MarketplaceInformationService (more info)
  • New MediaLibraryService
  • New FMRadioService
  • New LockScreenService
  • New AutoFocusBehavior (more info)
  • Various improvements and bug fixes

You can count on some articles around the new stuff for the next few days! :)

FMRadio vs. BackgroundAudioPlayer... fight!!

“The cat is out of the bag”…

…as Microsoft has confirmed that FM Radio is making a return in the next update to Windows Phone 8 (commonly known as GDR2)!

Obviously, updating your phone to GDR2 may not suffice, as the phone itself must have FM Radio tuning capability from factory!

Back when Windows Phone 7.x was king we could use the FMRadio class to control the device FM Radio, but given that no support for it was added to Windows Phone 8, accessing it in a WP8 device would just throw an exception… but that was before GDR2!

Mark Monster, Silverlight MVP, has written a really good article on how to safely use the FMRadio class across all versions of Windows Phone.

So what’s the problem?

Here’s the whole problem and how you can check it, step by step:

  • Preconditions
    • Use a real phone with Windows Phone updated to GDR2
    • Plug in your headphones to the phone (the phone uses them as an FM Radio antenna)
  • Steps to reproduce
    • Open Music+Videos hub
    • Tap the “radio” item to start the FM Radio tuner
    • Tune in a radio station and check that you can hear audio on the headphones
    • Open any app that uses the BackgroundAudioPlayer and start playback
  • Actual Results
    • You hear the FM Radio audio and the audio from the app… at the same time!!
  • Expected Results
    • FM Radio should stop and you should now be hearing the audio from the app

Basically, there seems to be some sort of issue where the FM Radio does not stop once the BackgroundAudioPlayer starts!

You can however easily bypass this issue: just ensure you stop the FM Radio playback before starting the BackgroundAudioPlayer or any other playback for that matter!

To make things easier, you can use the following code snippet:

using Microsoft.Devices.Radio;
public class FMRadioSafe
{
private static bool? _isAvailable;
public static bool IsAvailable
{
get
{
if (!_isAvailable.HasValue)
{
try
{
_isAvailable = FMRadio.Instance != null;
}
catch
{
_isAvailable = false;
}
}
return _isAvailable.Value;
}
}
public static void Stop()
{
if (IsAvailable)
{
FMRadio.Instance.PowerMode = RadioPowerMode.Off;
}
}
}

Just copy and past this to your app and call FMRadioSafe.Stop() before any audio output instruction and you’re done! :)

Update 20/08/2013: You can now use the FMRadioService from Cimbalino Windows Phone Toolkit version 3.0.0!

Checking for updates from inside a Windows Phone app

A few months ago, I started receiving some crash reports from one of my most successful apps, Geosense!

After fixing the issue and publishing an updated version of the app, until today I still get quite a few reports from the very same old version, but none from the updated one!

This has got me to think on the reason to why people don’t update their apps! Here are some reasons:

  • No constant internet connection
  • Removing the Store tile from the Home screen
  • Don’t care about updating apps!

The first one doesn’t make much sense to me, as the Windows Phone ecosystem makes a lot more sense as a “always online” system! Also, Geosense requires internet connection to work and crash reports can’t be done without internet connection, so this doesn’t seem to be the main reason in my case!

I don’t see the point in it, but not caring to check and update the apps in ones phone is just a matter of personal opinion!

That leaves the middle option: having the Store tile in the Home screen will enable users to get visual notification of updates (the number of updated apps appears in the tile); without it, the only other option is that the user actually opens the Store app from the applications menu.

Wouldn’t it be nice to just get the app to notify the user that an update is available?

Keeping this in mind, I opened Fiddler on my laptop, set my phone to use it as a proxy server, opened Geosense info from the store, and this is the request I could see going to Microsoft servers:

http://marketplaceedgeservice.windowsphone.com/v8/catalog/apps/7ca9cfea-1b92-4ca4-8559-269936d5361e?os=8.0.9903.0&cc=GB&oc=&lang=en-GB&hw=520170499&dm=RM-821_eu_euro1&oemId=NOKIA&moId=VOD-GB&cf=99-1

I can see in the above url the application ProductId (7ca9cfea-1b92-4ca4-8559-269936d5361e) the windows phone version (os=8.0.9903.0), the store territory (cc=GB), the language (lang=en-GB) and a bunch of other stuff related to the device brand, model and version.

The response is even more interesting, as it shows all the Store information about the app, including the latest available version and release date.

Given we are only interested in the version, after manually clearing up the response this is what we get:

<a:feed xmlns:a="http://www.w3.org/2005/Atom" xmlns:os="http://a9.com/-/spec/opensearch/1.1/" xmlns="http://schemas.zune.net/catalog/apps/2008/02">
<!-- other stuff -->
<a:entry>
<!-- other stuff -->
<version>1.10.1.8</version>
<!-- other stuff -->
</a:entry>
<!-- other stuff -->
</a:feed>

Well, we now know how to get the Store information about a particular app, we know what gets returned and how to read it, so let’s put that all together!

We will need the ProductID for the current running app, and for that we can just read it from the WMAppManifest.xml file like I shown in a previous article:

public static string GetManifestAttributeValue(string attributeName)
{
var xmlReaderSettings = new XmlReaderSettings
{
XmlResolver = new XmlXapResolver()
};
using (var xmlReader = XmlReader.Create("WMAppManifest.xml", xmlReaderSettings))
{
xmlReader.ReadToDescendant("App");
return xmlReader.GetAttribute(attributeName);
}
}

Given that there is no way in the current SDK to retrieve the Store territory, we will fallback to the CultureInfo.CurrentUICulture value for it and also for the language.

Here’s the complete async method to retrieve the latest version information from the Store:

private Task<Version> GetUpdatedVersion()
{
var cultureInfoName = CultureInfo.CurrentUICulture.Name;
var url = string.Format("http://marketplaceedgeservice.windowsphone.com/v8/catalog/apps/{0}?os={1}&cc={2}&oc=&lang={3}​",
GetManifestAttributeValue("ProductID"),
Environment.OSVersion.Version,
cultureInfoName.Substring(cultureInfoName.Length - 2).ToUpperInvariant(),
cultureInfoName);
var request = WebRequest.Create(url);
return Task.Factory.FromAsync(request.BeginGetResponse, result =>
{
var response = (HttpWebResponse)request.EndGetResponse(result);
if (response.StatusCode != HttpStatusCode.OK)
{
throw new WebException("Http Error: " + response.StatusCode);
}
using (var outputStream = response.GetResponseStream())
{
using (var reader = XmlReader.Create(outputStream))
{
reader.MoveToContent();
var aNamespace = reader.LookupNamespace("a");
reader.ReadToFollowing("entry", aNamespace);
reader.ReadToDescendant("version");
return new Version(reader.ReadElementContentAsString());
}
}
}, null);
}

All you now have to do is compare it to the active app version, like in this sample code:

private async void CheckForUpdatedVersion()
{
var currentVersion = new Version(GetManifestAttributeValue("Version"));
var updatedVersion = await GetUpdatedVersion();
if (updatedVersion > currentVersion
&& MessageBox.Show("Do you want to install the new version now?", "Update Available", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
{
new MarketplaceDetailTask().Show();
}
}

At startup, just call CheckForUpdatedVersion() and it will check if a new version is available, and if so, show a confirmation message box to the user and open the Marketplace details for the updated app.

If you’re using Cimbalino Windows Phone Toolkit, I’ve added the IMarketplaceInformationService that contains all the above logic to retrieve Store information for apps, with added bonus that will work not only for WP8 but also in WP7!

For the time being, this new service is only available in the 3.1.0-rc version of the toolkit, so make sure to install the pre-release version!