0 Comments

Windows Phone 7 has a anonymous user ID property called ANID. Windows Phone 8 replaced that with ANID2. The difference is that ANID2 is dependent on the app's publisher ID. With ANID and ANID2 you can identify your user. This is helpful for example if you want to store some of her app data in a cloud.

The problem

The problem is that if a user upgrades her phone from WP7 to WP8, her ANID changes. Before, her ANID was same in all of her apps. Now, as the publisher ID is part of the ANID2, her ANID2 will be the same in different apps only if the apps are from the same publisher.

The solution

If you use ANID to identify your users, it maybe useful to always convert the ANID to ANID2. This way, even if your user upgrades her phone, you can still identify her. It’s possible to convert from ANID to ANID2.  Microsoft has released a C++ sample on how to do the conversion and this post shows the same algorithm in C#, with a big help from SO.

The code

To do the conversion from ANID to ANID2, you have to have your publisher id (GUID). Also, the WP7 ANID must be in “full” format. Some example code on net shows how you take a substring from the ANID and use that as an ID. Don’t do that. You need the whole ANID (in theory, at least).

Here’s the code which does the conversion:

        public static string GetAnid2FromAnid(string anid, Guid publisherId)
        {
            var anidAsBytes = System.Text.Encoding.Unicode.GetBytes(anid);
            var publisherAsBytes = publisherId.ToByteArray();

            var macObject = new HMACSHA256(anidAsBytes.Take(anidAsBytes.Length / 2).ToArray());
            var hashedBytes = macObject.ComputeHash(publisherAsBytes);

            var result = Convert.ToBase64String(hashedBytes);

            return result;
        }

12 Comments

As we all know, Windows Phone 7 doesn’t have support for in-app purchases. The support was added in Windows Phone 8. This isn’t a huge deal in most countries as WP7 phones weren’t that popular. Except here in Finland. The big problem is that if your app targets Finnish users and you want to provide some content as in-app purchases, you really can’t skip the WP7 users or you’re going to miss a big part of your market. How big you may ask? Over half:

image

The Lumia 800 was really popular here. And it still is as it has been sold with big discounts in the past few months:

image

I’ve been battling with the problem recently as I’ve added some in-app products to an app which targets Finnish users only. And I’m quite happy with the outcome. Here’s first some features of the implementation and then some more details on how it is done:

Features

One XAP

The app only has one XAP (which targets Windows Phone 7.1). The same XAP gets deployed to both WP8 and WP7 phones.

In-app purchases are managed through Dev Center

The in-app purchases are managed through the Dev Center, just like when we are targeting Windows Phone 8 only:

image

One codebase

There’s no “if platform wp 8 then else” code. The product purchase is initiated with the following code:

var license = await store.RequestProductPurchaseAsync("live2013", true);

Native on Windows Phone 8

If the app is run on Windows Phone 8, it uses the native in-app purchase features:

image

Custom code on Windows Phone 7

If the app is run on Windows Phone 7, it uses custom code which mimics the in-app purchase experience of WP8:

image

Note: The WP7 version gets the product details (price etc.) from the Dev Center.

PayPal on Windows Phone 7

User is taken to PayPal’s mobile checkout site when she decides to purchase the product (on Windows Phone 7):

image

On Windows Phone 8 the user can select from any of her payment methods. Remember, the app uses the native in-app purchase functionality on WP8 device.

And that’s about it on the feature side.The best part is that I don’t have to worry about if the user has Windows Phone 7 or 8 device as the same code works on both platforms. Biggest limitation is that the WP7 side is currently PayPal only.

Implementation details

Client

The idea behind the implementation was taken from the code sample “WP8 Store Wrapper for IAP”. The original code sample shows how it is possible to wrap the WP8 store so that it can be used when a WP7 app is run on a WP8 device.

I used a similar wrapping mechanism but in addition I implemented a custom store which is used on WP7 devices. Here’s a StoreFactory-class which decides what store to use:

public static class StoreFactory 
{ 
    public static StoreBase Create() 
    { 
        StoreBase store = null;

        if (Environment.OSVersion.Version.Major >= 8) 
        { 
            store = StoreLauncher.GetStoreInterface("WP8StoreWrapper.Store, WP8StoreWrapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); 
        } 
        else 
        { 
            store = StoreLauncher.GetStoreInterface("CustomStore.MyCustomStore, CustomStore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"); 
        }

        return store; 
    } 
}

Here’s an example which shows how to check if the user owns product “myproduct”:

var ownsProduct = store.LicenseInformation.ProductLicenses.ContainsKey("myproduct");

Without the wrapper, using directly the Windows Phone 8 SDK, the above code would be written like this:

var ownsProduct = CurrentApp.LicenseInformation.ProductLicenses.ContainsKey("myproduct");

The custom store includes the product details page. The page is similar to WP8’s page, showing the product’s price with the buy and cancel buttons.

Service

The custom store isn’t just a client side thing. There’s a service which the client uses to get the product details and to communicate with the PayPal. The whole thing could be implemented without a service but in that case, if the user changes her phone, the purchase would be lost. With the help of the service, user can install her previously purchased products on a new phone.

The service itself is just a ASP.NET MVC site, which returns the product details to client in JSON format, communicates with PayPal using their old WebService interface and stores the receipts for purchases.

Code

Code isn’t yet available as it needs some fine tuning. But if you’re interested, just give me a shout and can provide more details about the implementation.

0 Comments

We have one Windows Phone app which we have designed to have white background even when the phone’s theme is set to black.

image

The app uses Telerik’s RadPhoneApplicationFrame which provides nice transitions (similar to Navigation Transitions in Windows Phone Toolkit) when a user moves from a page to page.

The problem was that during the transition, the app’s background was shown on black (using the phone’s theme). As we had two pages with white backgrounds but a black transition between them, navigating between the pages provided an irritating experience. It was “flashing”. Here’s a screenshot taken from the app during a transition. Notice the black background:

image

Fortunately the fix was easy: We only had to set the background color of the frame to white:

        protected override PhoneApplicationFrame CreatePhoneApplicationFrame()
        {
            return new RadPhoneApplicationFrame() { Transition = new RadContinuumAndSlideTransition(), Background = new SolidColorBrush(Colors.White) };
        }

0 Comments
  •   Posted in: 
  • UWP

The regional settings still misbehave in Windows 8.1 XAML apps. They misbehaved already in Windows 8 and they continue to misbehave in apps written with a newer WinRT. Some may say that they work as designed. To them I say the design is wrong.

The previous post about this subject contains more info, but here’s a short introduction to the problem.

Scenario:A Finnish users starts my Windows 8 XAML app. The app displays dates and times. The app isn’t localized to any language. I want the app to show the dates and times in Finnish format as that’s how she has configured her regional settings:

The problem:The app doesn’t respect her settings. Instead, all the dates and times are formatted using the US settings:

Capture

Other frameworks: Windows Forms, Console Applications, WPF, Silverlight and ASP.NET all handle this correctly: Dates and times are formatted using the regional settings:

image

The workaround: It’s possible to get the dates and times formatted correctly in WinRT apps. It’s just requires a lot of code. I call this a workaround until the WinRT XAML apps start behaving as they should:

            var usersLanguage = Windows.Globalization.Language.CurrentInputMethodLanguageTag;

            var dateFormatter = new DateTimeFormatter("shortdate", new[] { usersLanguage }).Patterns[0];
            var timeFormatter = new DateTimeFormatter("shorttime", new[] { usersLanguage }).Patterns[0];
            var fullFormatter = new DateTimeFormatter(dateFormatter + " " + timeFormatter);

            this.MyDate.Text = fullFormatter.Format(DateTime.Now);

image

Update 4.7.2013:

It seems I can get the behavior similar to Silverlight and other frameworks by setting the Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride on application startup (App.xaml.cs). For example:

        public App()
        {
            Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = Windows.Globalization.Language.CurrentInputMethodLanguageTag;
            this.InitializeComponent();
            this.Suspending += OnSuspending;
        }

 

4 Comments
  •   Posted in: 
  • UWP

screenshot_06272013_100012

In this tutorial we’re going to create a simple XAML app using the new Hub control. The tutorial is also going to show how SemanticZoom can be used with the Hub.

The Hub control is one of the new additions in Windows 8.1 XAML SDK and as described by the MSDN, Hub is “a new control for XAML that lets you easily create the hub design pattern that reflects the proper design guidelines and behavior”.

Why to use Hub control?

The MSDN again does a great job of summing up the reasoning behind a hub page and the hub control:

Hub pages are the user''s entry point to your app. They display content in a rich, panning view that lets users get a glimpse of what''s new and exciting, and then dig deeper into your app''s content. The hub displays different categories of content, each of which maps to your app''s section pages. Each section should bubble up content or functionality. The Hub should offer a lot of visual variety, engage users, and draw them in to different parts of the app.

For example the Weather and the Travel apps use hub pages as their starting points:

image

Getting started

In this tutorial we’re going to start from the “Blank App (XAML)” template. The aim is to create a hub page for a movie app using the new control.

screenshot_06272013_100012

So let’s start by creating the new app from the Blank App template. The template contains only a single empty page, MainPage.xaml, which we’re going to start editing:

image

As a test, if we insert the Hub control inside the Grid and set it’s background to Red, we can see that the new control fills the whole layout container:

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">

        <Hub Background="Red"></Hub>

    </Grid>

image

As we have a working Hub control, it’s time to add some content to it. Let’s start from the header.

Setting the header

The header in Hub control is visible all the time, even when the user scrolls horizontally. It usually includes the app’s name but it can also contain other controls like the back button. The header can be configured using the Header-property:

        <Hub Background="Red">

            <Hub.Header>
                <Grid>

                </Grid>
            </Hub.Header>

        </Hub>

In this tutorial we only want to show the app’s name inside the header:

            <Hub.Header>
                <Grid>
                    <TextBlock Text="The Movie App" />
                </Grid>
            </Hub.Header>

image

As we can see, there’s no need to define style for the TextBlock. The header automatically sets the font’s size and weight and also the padding. Because the only thing we need in the header is the app’s name, we can configure the header even more easily:

        <Hub Background="Red" Header="The Movie App">

        </Hub>

Now that we have the header configured, it’s time add some actual content into the hub.

Adding content into Hub control: The HubSection control

The Hub control itself only shows the header. We need to add HubSection controls inside the Hub control to add the actual content.  This is similar to the Windows Phone app’s, where we have the Panorama and the PanoramaItem controls.

In our app, we want to display four hub sections:

  • The second section just displays a static image from a movie
  • The first section shows pictures of the most popular movies
  • The third section list some movies near you
  • The last section provides movie trailers

Let’s add these sections now:

        <Hub Background="Red" Header="The Movie App">
            <HubSection Header="Popular"></HubSection>

            <HubSection></HubSection>

            <HubSection Header="Near You"></HubSection>

            <HubSection Header="Trailers"></HubSection>
        </Hub>

And here’s the result:

image

Let’s add some content into the HubSections, starting from the second one (the one which displays the static movie image).

Full height image in HubSection

We want to display an image in the HubSection. And we want it to use all the available space. If we add the image as a content, this is what happens:

image

The image doesn’t use the whole space. The trick is to set the image as the background of the HubSection:

        <Hub Background="Red" Header="The Movie App">
            <HubSection Header="Popular"></HubSection>

            <HubSection Width="500">
                <HubSection.Background>
                    <ImageBrush ImageSource="/Assets/poster.jpg" Stretch="UniformToFill"/>
                </HubSection.Background>
            </HubSection>

            <HubSection Header="Near You"></HubSection>

            <HubSection Header="Trailers"></HubSection>
        </Hub>

Also notice that we set the Width of the HubSection. Here’s the result:

image

Now it looks much better. One HubSection down, three to go.

Adding content to HubSection

We still have three empty HubSections. But filling them is easy, as we can use the standard GridView and ListView controls. A HubSection can contain any content you like: Buttons, UserControls, Grids, StackPanels etc. But what is little peculiar is that the HubControl doesn’t have a Content-property: You set the content by setting its DataTemplate. Here’s a small example:

            <HubSection Header="Popular">
                <DataTemplate>
                    <StackPanel>
                        <Button Content="Button inside a HubSection"/>
                    </StackPanel>
                </DataTemplate>
            </HubSection>

image

Filling the remaining HubSections with GridViews and ListViews is outside the scope if this tutorial, but the source code shows how it’s done. One important point though: A control which is inside a HubSection cannot be directly accessed from code-behind!

For example, here’s a HubSection which contains a single ListView:

            <HubSection Header="Trailers">
                <DataTemplate>
                    <ListView x:Name="MovieTrailers">

                    </ListView>
                </DataTemplate>
            </HubSection>

Even though we’ve given the ListView a name, we cannot access it from the code-behind:

image

This is because the control is inside a DataTemplate. One easy way to get around this limitation is to hook into the ListView’s Loaded-event. Here’s the XAML:

                    <ListView x:Name="MovieTrailers" Loaded="MovieTrailers_Loaded">

                    </ListView>

And the code behind:

        private void MovieTrailers_Loaded(object sender, RoutedEventArgs e)
        {
            var listView = (ListView)sender;
            listView.ItemsSource = trailers;
        }

Header navigation

Our hub page only shows few trailers so the actual app probably has a dedicated page for the trailers. We want to enable the navigation so that the user can click the “Trailers” header to move forward. This feature is built into the Hub control.

First thing we need to to is to enable the header clicking for the HubSection, by setting its IsHeaderInteractive property to true:

            <HubSection Header="Trailers" Width="550" IsHeaderInteractive="True" >
                <DataTemplate>
                    <ListView Loaded="MovieTrailers_Loaded" 
                              SelectionMode="None" 
                              ItemTemplate="{StaticResource Standard130ItemTemplate}"/>
                </DataTemplate>
            </HubSection>

What’s great is that this automatically adds the navigation indicator to the header:

image

Now to handle the click, we must attach to Hub’s (not HubSection’s) SectionHeaderClick-event:

<Hub Header="The Movie App" Background="{StaticResource BackgroundBrush}" SectionHeaderClick="Hub_SectionHeaderClick">

The clicked HubSection can be read from the event’s arguments:

        private void Hub_SectionHeaderClick(object sender, HubSectionHeaderClickEventArgs e)
        {
            var clickedSection = e.Section;
            if (clickedSection.Name == "TrailersSection")
            {
                // Add navigation logic
            }
        }

Semantic zoom

Last thing we’re going to add to the hub is semantic zoom. The Hub control supports semantic zoom, meaning it can be used as a Zoomed in view.

First thing we need to do is to add the SemanticZoom control to the page:

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <SemanticZoom x:Name="Zoom">
            <SemanticZoom.ZoomedInView></SemanticZoom.ZoomedInView>

            <SemanticZoom.ZoomedOutView></SemanticZoom.ZoomedOutView>
        </SemanticZoom>

        <Hub x:Name="Hub" Header="The Movie App" Background="{StaticResource BackgroundBrush}" SectionHeaderClick="Hub_SectionHeaderClick">

Then we move the whole Hub inside the ZoomedInView:

image

Also we need a ZoomedOutView. For that, let’s create a simple GridView:

            <SemanticZoom.ZoomedOutView>

                <GridView VerticalAlignment="Center" Margin="200,0,0,0" Loaded="GridView_Loaded">
                    <GridView.ItemTemplate>
                        <DataTemplate>
                            <StackPanel >
                                <TextBlock HorizontalAlignment="Center" Text="{Binding}" Style="{StaticResource SubheaderTextBlockStyle}" />
                            </StackPanel>
                        </DataTemplate>
                    </GridView.ItemTemplate>

                    <GridView.ItemContainerStyle>
                        <Style TargetType="GridViewItem">
                            <Setter Property="Margin" Value="4" />
                            <Setter Property="Padding" Value="5" />
                            <Setter Property="HorizontalContentAlignment" Value="Left" />
                            <Setter Property="VerticalContentAlignment" Value="Center" />
                        </Style>
                    </GridView.ItemContainerStyle>

                    <GridView.ItemsPanel>
                        <ItemsPanelTemplate>
                            <WrapGrid ItemWidth="400" ItemHeight="70" Orientation="Horizontal" VerticalChildrenAlignment="Center" MaximumRowsOrColumns="3"></WrapGrid>
                        </ItemsPanelTemplate>
                    </GridView.ItemsPanel>
                </GridView>

            </SemanticZoom.ZoomedOutView>

Only one small thing left: We have to provide some items for this GridView. We do that in the GridView_Loaded:

        private void GridView_Loaded(object sender, RoutedEventArgs e)
        {
            var sections = this.Hub.Sections;
            var headers = new List<string>();

            foreach(var item in sections)
            {
                var section = (HubSection)item;
                var header = (string)section.Header;
                if (string.IsNullOrWhiteSpace(header))
                    continue;

                headers.Add(header);
            }

            ((GridView)this.Zoom.ZoomedOutView).ItemsSource = headers;
        }

The code loops through all the HubSections. It takes the sections header from each of them and add its to the “headers”-list. This list is then set as the ItemsSource for our ZoomedOutView’s GridView. And that’s it. We can now zoom out:

image

And click any of the items to zoom into that section.

Final touches and the source code

At this point we’ve realized that the app looks better if we put the static picture as the first HubSection. Also, the red background can be replaced with a little less stressful color.

Full source code for the tutorial is available from GitHub (folder hubcontrol-getting-started). The app works with the preview release of Visual Studio 2013 and Windows 8.1.