Wednesday, December 12, 2012

Robot Work - Reducing the Windows Phone Localization Friction a bit

Windows Phone 8 now supports 3 different screen resolutions which is very nice since there are some great high resolution devices out there and the user has the choice and isn't forced into a one fits all model. However  there's also a downside for Windows Phone developers since now also 3 times the amount of screenshots have to be submitted to the Store. If an app has localized versions this adds up very quickly. For example, Pictures Lab supports 11 languages and the soon-to-released v5 update for WP8 also all 3 resolutions: 11 x 3 x 8 screenshots = 264! That's a crazy amount of mindless click-through work to take all those screenshots, not to mention the Dev Center submission process.
Unfortunately there is no automated way or better support by the tools, so one has to do this ridiculous amount of manual work.  In a future version of the tools I'd really love to see some kind of macro recorder which records certain steps including screenshot actions and can then use the recorded steps to play this for all supported app languages and generate the remaining screenshots automatically.

In this quick post I want to share some practices I used in order to reduce the work at least a bit for the Pictures Lab v5 update:
  1. Only create screenshots for the 720p (720 x 1280) and the WXGA (768 x 1280) resolution. The WVGA (480 x 800) screenshots can be generated from the WXGA images by scaling those down by 1.6. In contrast to upscaling, are the downscaling artifacts hardly visible if a good algorithm is used. I used my favorite image viewer IrfanView and its batch processing feature which can scale down by the longest side, rename by a pattern, convert, etc.



  2. Add some code to easily switch between UI languages in your app so you don't only rely on the system language and need to reboot the emulator to switch languages. An app's UI language can be set globally by using
    System.Threading.Thread.CurrentThread.CurrentUICulture
    For example:
    System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE");
    in the App.xaml.cs Launching event.

  3. Use a macro recorder / scripting to save a bit time with the repetitive tasks of taking screenshots only with different UI languages. I used a little free tool called Mouse Recorder Pro. This tool records your mouse and keyboard actions and can then play it back also with up to 40% faster playback speed. Of course this doesn't work for all apps and only when using the emulators, esp. uncontrollable live content would likely not work, but it worked for my scenario quite well and saved me from creating all 264 screenshots manually. In fact I watched the magic ghost mouse do its job most of the time and worked on other stuff.
    A few gotchas when using the Mouse Recorder Pro with the WP emulators:

    1. Don't click on Pivot headers and rather use the swipe gesture to change between Pivot items. The header texts will have different lengths in different languages.

    2. Try to avoid the bounce effect of the ScrollViewer, it would result in random offsets and the Mouse Recorder playback will then have non-matching offsets recorded.

    3. Do a dummy save in the destination folder for the screenshots before each playback so the playback will save the files to the right folder. This will avoid file name collisions which would need manual input.
Of course there's a lot of room for improvements, but maybe the described practices help to reduce the friction that comes with localization at least a bit until a better solution is known.


Thursday, November 1, 2012

WACK ARM

If you are developing Windows 8 Store apps you should really test those on low-powered x86 and ARM devices. The difference to your high-end x64 developer machine can be dramatically, esp. if you use a non-default design.
Testing on ARM is important and Tim Heuer wrote a nice post which shows how to remotely deploy, debug and profile on ARM devices right from Visual Studio 2012. Another nice thing which performs a couple of automated tests is the Windows App Certification Kit (WACK). Unfortunately is the WACK tool for ARM hidden inside the Windows 8 SDK, but here's how to find it:

  1. Download the Windows 8 SDK web setup from here and run it.
  2. Choose to download the SDK files for offline usage.
  3. On the "Select the features you want to download" screen it's enough if you only select the "Windows App Certification Kit" checkbox.
  4. After the download is finished, you will find an "Installers" subfolder in the download target folder.
  5. Copy the "Windows App Certification Kit arm-arm_en-us.msi" from the "Installers" folder to an USB key or SkyDrive.
  6. Open the "Windows App Certification Kit arm-arm_en-us.msi" on your ARM device and install the WACK on it. 
  7. Search for "Windows App Cert Kit" on your ARM device using the Search Charm and run the WACK.

Tuesday, October 30, 2012

Faster! - WriteableBitmapEx for Windows Phone 8 and WinRT Updated

The Windows Phone 8 SDK is now available and with that WriteableBitmapEx was updated too. The performance of the WinRT XAML version was also improved dramatically and an update is highly recommended.
WriteableBitmapEx is available for 4 platforms: Windows Phone 8 and 7, WPF, Silverlight and Windows Store WinRT .NET XAML.
You can download the binaries here or via the NuGet packageThe packages contain the WriteableBitmapEx binaries. As usual all samples and the source code can be found in the repository.

Sunday, October 28, 2012

Know Your Users - Windows 8 Store App System Info

This is just a quick a post to provide a little class for Windows 8 Store app development. The SystemInformation class gathers some useful information about the current system and can dump those as a string. I usually have such a class for all the platforms I work on and it's very helpful for logging and error analysis, but it also serves as a list of all available system information which are scattered in different APIs. The info can also be used to dynamically adapt the app, etc.

Here's the code I have so far, you can also download the complete class here.

public static async Task Dump(bool shouldDumpCompleteDeviceInfos = false)
{
   var builder = new StringBuilder();
   var packageId = Windows.ApplicationModel.Package.Current.Id;
   var clientDeviceInformation = new EasClientDeviceInformation();
    
   // Get hardware Id
   var token = HardwareIdentification.GetPackageSpecificToken(null);
   var stream = token.Id.AsStream();
   string hardwareId;
   using (var reader = new BinaryReader(stream))
   {
      var bytes = reader.ReadBytes((int)stream.Length);
      hardwareId = BitConverter.ToString(bytes);
   }

   builder.AppendLine("***** System Infos *****");
   builder.AppendLine();
#if DEBUG
   builder.AppendLine("DEBUG");
   builder.AppendLine();
#endif
   builder.AppendFormat("Time: {0}", DateTime.Now.ToUniversalTime().ToString("r"));
   builder.AppendLine();
   builder.AppendFormat("App Name: {0}", packageId.Name);
   builder.AppendLine();
   builder.AppendFormat("App Version: {0}.{1}.{2}.{3}", packageId.Version.Major, packageId.Version.Minor, packageId.Version.Build, packageId.Version.Revision);
   builder.AppendLine();
   builder.AppendFormat("App Publisher: {0}", packageId.Publisher);
   builder.AppendLine();
   builder.AppendFormat("Supported Package Architecture: {0}", packageId.Architecture);
   builder.AppendLine();
   builder.AppendFormat("Installed Location: {0}", Windows.ApplicationModel.Package.Current.InstalledLocation.Path);
   builder.AppendLine();
   builder.AppendFormat("Store App Id: {0}", CurrentApp.AppId);
   builder.AppendLine();
   if (CurrentApp.LicenseInformation.IsActive)
   {
      var listingInformation = await CurrentApp.LoadListingInformationAsync();
      builder.AppendFormat("Store Current Market: {0}", listingInformation.CurrentMarket);
      builder.AppendLine();
   }
   builder.AppendFormat("Culture: {0}", CultureInfo.CurrentCulture);
   builder.AppendLine();
   builder.AppendFormat("OS: {0}", clientDeviceInformation.OperatingSystem);
   builder.AppendLine(); 
   builder.AppendFormat("System Manufacturer: {0}", clientDeviceInformation.SystemManufacturer);
   builder.AppendLine();
   builder.AppendFormat("System Product Name: {0}", clientDeviceInformation.SystemProductName);
   builder.AppendLine();
   builder.AppendFormat("System Sku: {0}", clientDeviceInformation.SystemSku);
   builder.AppendLine();
   builder.AppendFormat("System Name: {0}", clientDeviceInformation.FriendlyName);
   builder.AppendLine();
   builder.AppendFormat("System ID: {0}", clientDeviceInformation.Id);
   builder.AppendLine();
   builder.AppendFormat("Hardware ID: {0}", hardwareId);
   builder.AppendLine();
   builder.AppendFormat("User Display Name: {0}", await UserInformation.GetDisplayNameAsync());
   builder.AppendLine();
   builder.AppendFormat("Window Bounds w x h: {0} x {1}", Window.Current.Bounds.Width, Window.Current.Bounds.Height);
   builder.AppendLine();
   builder.AppendFormat("Current Orientation: {0}", DisplayProperties.CurrentOrientation);
   builder.AppendLine();
   builder.AppendFormat("Native Orientation: {0}", DisplayProperties.NativeOrientation);
   builder.AppendLine();
   builder.AppendFormat("Logical DPI: {0}", DisplayProperties.LogicalDpi);
   builder.AppendLine();
   builder.AppendFormat("Resolution Scale: {0}", DisplayProperties.ResolutionScale);
   builder.AppendLine();
   builder.AppendFormat("Is Stereo Enabled: {0}", DisplayProperties.StereoEnabled);
   builder.AppendLine();
   builder.AppendFormat("Supports Keyboard: {0}", IsKeyboardPresent());
   builder.AppendLine();
   builder.AppendFormat("Supports Mouse: {0}", IsMousePresent());
   builder.AppendLine();
   builder.AppendFormat("Supports Touch (contacts): {0} ({1})", IsTouchPresent(), new TouchCapabilities().Contacts);
   builder.AppendLine();
   builder.AppendFormat("Is Network Available: {0}", NetworkInterface.GetIsNetworkAvailable());
   builder.AppendLine();
   builder.AppendFormat("Is Internet Connection Available: {0}", NetworkInformation.GetInternetConnectionProfile() != null);
   builder.AppendLine();
   builder.AppendFormat("Network Host Names: ");
   foreach (var hostName in NetworkInformation.GetHostNames())
   {
      builder.AppendFormat("{0} ({1}), ", hostName.DisplayName, hostName.Type);
   }
   builder.AppendLine();
   builder.AppendFormat("Current Memory Usage: {0:f3} MB", GC.GetTotalMemory(false) / 1024f / 1024f);
   builder.AppendLine();
   builder.AppendFormat("App Temp  Folder: {0}", ApplicationData.Current.TemporaryFolder.Path);
   builder.AppendLine();
   builder.AppendFormat("App Local Folder: {0}", ApplicationData.Current.LocalFolder.Path);
   builder.AppendLine();
   builder.AppendFormat("App Roam  Folder: {0}", ApplicationData.Current.RoamingFolder.Path);
   builder.AppendLine();
   builder.AppendLine();

   if (shouldDumpCompleteDeviceInfos)
   {
      var devInfos = await DeviceInformation.FindAllAsync();
      builder.AppendLine();
      builder.AppendLine("Complete Device Infos:");
      foreach (var devInfo in devInfos)
      {
         builder.AppendFormat("Name: {0} Id: {1} - Properties: ", devInfo.Name, devInfo.Id);
         foreach (var pair in devInfo.Properties)
         {
            builder.AppendFormat("{0} = {1}, ", pair.Key, pair.Value);
         }
         builder.AppendLine();
      }
   }

   return builder.ToString();
}

public static bool IsTouchPresent()
{
 return new TouchCapabilities().TouchPresent == 1;
}

public static bool IsMousePresent()
{
 return new MouseCapabilities().MousePresent == 1;
}

public static bool IsKeyboardPresent()
{
 return new KeyboardCapabilities().KeyboardPresent == 1;
}


On my system it provides the following info (anonymized):
***** System Infos *****

DEBUG

Time: Sun, 28 Oct 2012 07:51:11 GMT
App Name: MyApp
App Version: 1.0.0.5
App Publisher: CN=A8E2F0B1-4749-48AE-AE18-C7FFB5B30272
Supported Package Architecture: Neutral
Installed Location: D:\Development\MyApp\bin\Debug\AppX
Store App Id: 00000000-0000-0000-0000-000000000000
Culture: en-US
OS: WINDOWS
System Manufacturer: Dell Inc.
System Product Name: Precision M6600
System Sku: 
System Name: MYLAPTOP
System ID: 18a2e8c6-cc7d-8546-1e9e-56a12ffb32fd
Hardware ID: 03-00-D2-41-03-00-AA-72-08-00-EF-AD-05-AA-B6-4F-06-00-01-01-04-00-31-1B-04-00-0C-48-04-00-D2-55-04-00-D3-66-01-00-0E-D6-02-00-E4-7F-09-00-56-47
User Display Name: Rene Schulte
Window Bounds w x h: 1920 x 1080
Current Orientation: Landscape
Native Orientation: Landscape
Logical DPI: 96
Resolution Scale: Scale100Percent
Is Stereo Enabled: False
Supports Keyboard: True
Supports Mouse: True
Supports Touch (contacts): False (0)
Is Network Available: True
Is Internet Connection Available: True
Network Host Names: mylaptop (DomainName), mylaptop.local (DomainName), 169.254.85.85 (Ipv4), 192.168.2.148 (Ipv4), 
Current Memory Usage: 0.451 MB
App Temp  Folder: C:\Users\Rene\AppData\Local\Packages\MyApp\TempState
App Local Folder: C:\Users\Rene\AppData\Local\Packages\MyApp\LocalState
App Roam  Folder: C:\Users\Rene\AppData\Local\Packages\MyApp\RoamingState

If you know more system information Windows 8 APIs that listing is missing, please add a comment.

Wednesday, August 29, 2012

Update WriteableBitmapEx for WinRT RTM, WPF, Windows Phone and Silverlight


The RTM version of Windows 8 is now available and with that WriteableBitmapEx was updated too. WriteableBitmapEx is now available for 4 platforms: WPF, Silverlight, Silverlight for Windows Phone and Windows Store Style WinRT .NET.
You can download the binaries here or via the NuGet packageThe packages contain the WriteableBitmapEx binaries. As usual all samples and the source code can be found in the repository.



Since the last WinRT release preview version, a couple of bugs were fixed and a new FromStrean method was added which loads an image stream into a WriteableBitmap. The project was also updated for the Windows 8 RTM version. Please read this blog post for more details about the WinRT version.

Tuesday, June 19, 2012

Moving on

Today was my last day at Schleupen AG. I worked there for 5 years as an enterprise developer mainly on back end and algorithmic topics, but also on the front end with .NET, Silverlight and more. We developed some really nice things there and I'm esp. proud of the parallel data processing pipeline which even works with .NET 2.
My co-workers were a great bunch of people, some became my friends and even the godfather of my youngest daughter and I became a godfather too. I thank them all for what I've learned and the great time we had. I wish them nothing less than the best for their future.

I started at Schleupen AG right after my studies and my diploma thesis "Parallelization and Optimization of an OpenGL CAD / CAM Application". I was always a computer graphics aficionado and passionate about physical simulation, image processing, computer vision, real-time computer graphics in general and interactive UIs with a great UX. Just for fun I started to work on some side projects, like this open source OpenGL fluid simulation in 2007, created a few open source libraries and also developed quite popular  Windows Phone apps such as Pictures Lab, Funny Faces, Helium Voice, Cloud Recorder and more. 

It's an exciting time to be a developer with so much things happening in this industry at the moment. Microsoft's own Surface tablets is just one piece we as software developers can leverage to shape the future. For me it's good fun to use these great new technologies like Windows Phone, Windows 8, WinRT, .NET, DirectX, XBox, Kinect, etc. to create nice experiences and I love to work on this all the time.
few months ago I got an offer from IdentityMine and if you know their work, you can imagine that it was a no-brainer to accept this nice offer they made meI'm really looking forward to work with state of the art technologies on exciting projects with experts like Laurent Bugnion and more great people. Another nice aspect of my new gig: I will work from my home office and will be closer to my 3 lovely daughters and wife. I will also be here during the last phase of my wife's pregnancy and can hopefully support her better. And yes, we're expecting our fourth child in September. :-)


Now I will enjoy a couple of days off with my family until I start my new job as Senior Interactive Developer at IdentityMine on July 2nd.

Thursday, June 14, 2012

It's Alive! - WriteableBitmapEx 1.0 for WinRT Metro Style, WPF, Windows Phone and Silverlight

After a few preview versions, I'm happy to announce that the final version of WriteableBitmapEx 1.0 is now available.
A couple of weeks ago we added official WPF support and WinRT Metro Style support. With that WriteableBitmapEx is now available for 4 platforms: WPF, Silverlight, Silverlight for Windows Phone and Metro Style WinRT .NET.
You can download the binaries here or via the NuGet package. The packages contain the WriteableBitmapEx binaries. All samples and the source code can be found in the repository.


Since the last WinRT preview version, a new WinRT sample was added, a couple of bugs were fixed and a new FromStrean method was added which loads an image stream into a WriteableBitmap. The project was also updated for the Windows 8 Release Preview. Please read this blog post for more details (about the WinRT version).

Monday, May 7, 2012

One Bitmap to Rule Them All - WriteableBitmapEx for WinRT Metro Style

A couple of weeks ago we added official WPF support to  WriteableBitmapEx. Today I'm happy to announce that WriteableBitmapEx now also officially supports Windows 8 Metro Stlye WinRT .NET XAML. With that WriteableBitmapEx is now available for 4 platforms: WPF, Silverlight, Silverlight for Windows Phone and Metro Style WinRT .NET.
Although Direct2D is the best solution for fast 2D graphics with Windows 8 Metro Style, I think there are scenarios where the WriteableBitmapEx could be helpful, esp. when using C# with XAML. I also know that some devs were waiting for this to port their Windows Phone apps to Windows 8 Metro Style.

WinRT Differences
Unlike the Silverlight WriteableBitmap, the Metro Style WriteableBitmap doesn't provide the pixel data directly. Its IBuffer PixelBuffer property doesn't have an interface to get the color information. Fortunately there are a few C# extension methods available which provide the pixel data as byte array or stream in the BGRA pixel format. Yes, BGRA and not like all the other platforms supported by WriteableBitmapEx as ARGB. The BGRA format is mainly used by Direct2D, which might be the reason for this hidden, but important difference of the Metro Style WriteableBitmap.
The WriteableBitmapEx algorithms are written for the ARGB pixel format. Fortunately I was able to keep the details away from the library user by leveraging the BitmapContext concept we introduced with the WPF support. This approach makes it possible to share almost the same code for all 4 platforms without being cluttered with #if directives all over place.  Actually the most significant WinRT adaptation inside the WriteableBitmapEx methods was done in the FromContent method, which loads an image from the app content and provides it as WriteableBitmap. See this StackOverflow question I answered if you're interested in the details.
Nothing comes for free, but if the BitmapContext is used the right way, the performance hit won't be that much thanks to an internal reference counting WriteableBitmapEx' BitmapContext uses. No worries, you don't have to change all your WriteableBitmapEx calls, just wrap your calls in a simple using(writeableBmp.GetBitmapContext()) and you will only have one buffer conversion instead of one for each draw call.
It's really simple to use:

private void Draw()
{
   // Wrap updates in a GetContext call, to prevent invalidation overhead
   using (writeableBmp.GetBitmapContext())
   {
      writeableBmp.Clear();
      DrawPoints();
      DrawBeziers();
  
   } // Invalidates on exit of using block
}

private void DrawPoints()
{
   foreach (var p in points)
   {
      DrawPoint(p, Colors.Green, PointVisualSizeHalf);
   }
}

private void DrawPoint(ControlPoint p, Color color, int halfSizeOfPoint)
{
   var x1 = p.X - halfSizeOfPoint;
   var y1 = p.Y - halfSizeOfPoint;
   var x2 = p.X + halfSizeOfPoint;
   var y2 = p.Y + halfSizeOfPoint;
   writeableBmp.DrawRectangle(x1, y1, x2, y2, color);
}

private void DrawBeziers()
{
   if (points.Count > 3)
   {
      writeableBmp.DrawBeziers(GetPointArray(), Colors.Yellow);
   }
}

Screenshot WinRT Metro Style sample running in the simulator

All samples were tested with the new version, but due to the refactoring more testing is needed. Please test this version with your projects and report the bugs you encounter. You can download the binaries here. Note that this package only contains the WriteableBitmapEx binaries for Silverlight, Windows Phone, WinRT Metro Style .NET and WPF. All the samples can be found in the source code repository in the branch "WBX_1.0_BitmapContext". If all goes well, this branch will become the trunk and the 1.0 RTM in a few weeks.

WinMD / Windows Runtime Component
There's also a WinMD version available which makes it possible to consume the WriteableBitmapEx library from all the WinRT Metro Style projections, although only C# and C++ XAML make actually sense.
I had to move some parts and leave some functionality like the ForEach out, but it contains 99% of the library's features. Unfortunately the C++ sample I created crashes when the WriteableBitmapExWinMD library is loaded. So for now this WinMD version can be found in a separate branch "WBX_1.0_WinMD" in the source code repository and it won't be part of the trunk and release until it works with the sample. I'm a bit running out of time and don't know where to look for, since it seems all is wired up correctly and compiles fine. If you are a WinMD wizard and have a few minutes, I'd appreciate if you could look into the WinMD version.

Friday, January 13, 2012

Breakdown of Windows Phone App Download Statistics

Line Graph by Scott Lewis, Noun
In this blog post I want to share the download graph of my quite successful Windows Phone app Pictures Lab and my conclusions. Some of you might have seen a similar graph already on Twitter or on Facebook, but I thought an update and a bit more explanation might probably make sense.





The graph below shows the download statistics of my Pictures Lab app during the last 9 months. The green line represents the daily downloads and the orange are the accumulated downloads. I blurred the numbers at the scales, since I don't release the download number for various reasons. Please note, Pictures Lab offers a trial mode which means users can try the app for free. Therefore the download numbers aren't equal to the number of sold licenses! Although the app has a pretty good conversion rate from trial-to-paid of ~32% worldwide average and in December it even was 97% in Norway! I noticed that all the Scandinavian countries seem to have a great conversion rate in general. Worst seems to be Hong Kong, but that's a story for a different blog post. Just to be clear, Pictures Lab provides me with a solid extra income each month and the trend is positive, but it's not enough to make a living out of that yet.
The absolute download numbers actually don't matter that much for this blog post. The important part of the graph are the text labels I manually added. Those labels mark events I tracked and noted at that time and are usually followed by a download peak.

Pictures Lab download graph from 04-01-2011 to 01-07-2012 (click on the image for the original size).

My conclusions
  1. Steadily releasing updates with new functionality and being featured at the Windows Phone sites has a big impact on the downloads. Keep in mind the major Pictures Lab updates were featured at least at 3-5 of the top Windows Phone sites.
  2. Being featured at the Marketplace also has a significant positive impact on downloads. Of course this depends on how big the local Marketplace is. Unfortunately does the AppHub not provide the information when an app has been featured. There is the Distimo service which tracks that too, but that service needs your live id credentials and I won't give a 3rd party site my live id to store it in their database. Fortunately some of my friends ping me when they see my apps being featured in their local marketplace. I think it's pretty much safe to say that all the graph peaks without a label nearby are related to a Marketplace feature.  
  3. The base line increased not only after the 3.0, but also after the peak of the 4.0 update. The 4.0 update brought the multi-language support with 10 languages. The steady download jump after 4.0 is a pretty good indication that localization can help to increase downloads.
  4. The price drop to $0.99 was followed by the highest peak in the graph, but after that it went down pretty quickly. I think the price point is the hardest thing to get right and it largely varies for different kind of apps, so the above Pictures Lab pricing information shouldn't be generalized.   
  5. Of course Christmas, the holidays and New Year also resulted in nice peaks. Customers have time to browse the marketplace or just want to fill up their brand new Windows Phones with some apps.

What about the Windows Phone 7.5?
The first Windows Phone 7.5 (previously known as Mango) devices and Nokia hit the market in October and November 2011. This fact also needs to be considered when interpreting the graph. Although from looking at the statistics of my other apps I see that Windows Phone 7.5 didn't have such a huge impact like the updates had. The downloads definitely increased due to the Windows Phone 7.5 launch, but the tracked events align very well with the peaks in the graph and the increase of the base line after.
Let me try to clarify this and my conclusion #3 with the graphs of my successful Helium Voice Free app and my not so successful Benchmark Free app.

Helium Voice Free got a nice update in November, but I didn't inform the Windows Phone sites, so there are no peaks in the graph. You can see that the release of Windows Phone 7.5 slightly increased the downloads and the downward trend turned into an upward trend.

Helium Voice Free graph from 04-01-2011 to 01-07-2012 (click on the image for the original size to see numbers).

















In the Benchmark Free download graph there's also this small increase of the average downloads around the Windows Phone 7.5 device launch, but it's not as much as after the updates of Pictures Lab.

Benchmark Free graph from 04-01-2011 to 01-07-2012 (click on the image for the original size).


















Considering all that information, I think this means the Windows Phone 7.5 launch of course raised the downloads base line, but the Pictures Lab updates had a bigger impact on the downloads and it's not only the Windows Phone 7.5 launch which raised the average downloads of Pictures Lab.
Keep in mind that such a statistical analysis isn't bullet-proof at all, esp. when there's not all the information available like the date of all marketplace features and more. Please also note not all apps are the same and things that work for Pictures Lab or Helium Voice Free don't necessarily need to be valid for other apps.

Makes sense?
What are your conclusions?
What is your experience?


Thank you!
I would like to thank all the users of the app, the great group of translators who helped me to translate Pictures Lab, the beta testers and not at last all the great Windows Phone sites which keep us informed about all the things happening around Windows Phone and help us developers by informing the world about our apps. Keep it up!

Thursday, January 5, 2012

Let me out - Facebook Logout in a Windows Phone App

A while ago I implemented the Facebook photo endpoint into my Windows Phone Pictures Lab app. The implementation of the login was quite straightforward thanks to OAuth 2.0. Only the logout was way harder than one might expect. This post describes how to logout from Facebook using the Facebook API.






In my Pictures Lab app you can edit photos, make them look awesome and then save or share those with your friends at Twitter or Facebook. The Windows Phone Mango API provides the ShareLinkTask and the ShareStatusTask which can be used by an app to share an URL or text using the social services the user has connected the device to. Unfortunately there's no built-in SharePhotoTask to share a photo using the services the user has already authorized. That's why I had to implement it in a custom way where the user has to authorize again. This blog post by my mate Nick Randolph describes very well how to login to Facebook from a Windows Phone app.

For some situations it might make sense to allow the user to logout from within the app. One might think this can't be hard and in most cases it's pretty easy. Logging out from Twitter is very easy for example. You just have to start the authorization process again. However, logging out from Facebook is way harder since they store a cookie and the WebBrowser control doesn't provide a way to clear the cookies, so just starting the authorization process again doesn't work.
One way to log out from Facebook uses a special Uri that contains a part of the access token which was queried during the app authorization process.

Here's the snippet I use in Pictures Lab to split the access token to get the session key which is then used to build the custom Uri:


public Uri GetLogoutUri(FacebookCredentials credentials)
{
   var sessionkey = ExtractSessionKeyFromAccessToken(credentials.AccessToken);
   var url = String.Format("http://facebook.com/logout.php?app_key={0}&session_key={1}&next={2}", EndpointData.FacebookAppId, sessionkey, EndpointData.FacebookLogoutCallbackUrl);
   return new Uri(url);
}

private static string ExtractSessionKeyFromAccessToken(string accessToken)
{
   if (!String.IsNullOrEmpty(accessToken))
   {
      var parts = accessToken.Split('|');
      if (parts.Length > 2)
      { 
         return parts[1];
      }
   }
   return String.Empty;
}

That logout Uri is then used to navigate the WebBrowser control to it which then correctly triggers the log out process.

Browser.Navigate(FacebookService.GetLogoutUri(EndpointData.Settings.Facebook));

That's it. You just have to know their trick. Hope this helps.

SLARToolkit Samples Updated

The samples of my open source Windows Phone and Silverlight Augmented Reality Toolkit were updated to the latest version of the WP 7.1 and Silverlight 5 SDKs.
Please note the changed security model in Silverlight 5, which is a big bummer. My Silverlight MVP friend Morten wrote a few true words about it here.
As usual you can find a list of the samples on the project site and also get the code there.