ailon's DevBlog: Development related stuff in my life

The State of Worldwide WP7 Publishing after MIX11

4/26/2011 10:11:58 AM

I’m back from MIX11 and a short vacation after that. It is now beside the point to write anything about general topics from MIX, but as I took on a duty of advocating expansion of Windows Phone marketplace accessibility, I’d like to address what was announced and changed after MIX11.

In this post I’ll talk about developer (publishing) accessibility.

8 (9?) new countries in more than a year. Really!?

image

I was still operating in moderate optimism mode (aka stupidity) before MIX. Hoping a lot of new developer countries will be announced (including Lithuania). I’ve got a couple hints that this won’t be the case and it wasn’t.

In more than a year Microsoft has managed to add support for 8 (or is it 9? (see below)) new developer countries. I’m pretty sure a single full time employee working on that could do more in a year, but oh, well. It’s clear now that this sort of expansion is not a priority for Microsoft or they are just waiting for Nokia to bring that part to the table.

Fortunately they at least did something to mitigate the issue.

Global Publishing Partners

image

Earlier this year MS announced Yalla Apps as their first official global publishing partner (aka proxy) for Middle East and Africa. I’ve seen different reactions to this – from awe to someone calling it a spit in the face of developers.

I consider it to be what it actually is – a workaround. Something that gets the job done in civilized, but not very elegant manner.

Now they’ve announced additional partners to cover a total of 102 countries. Each has some “focus” countries but actually accepts developers from all over the world (except for officially supported countries).

image

The funny part is that no one can tell what that “focus” really means. I’ve got some vague answers that it has something to do with partner using locally preferred payment methods, operating in closer time zone (for better support), etc. But Yalla Apps (which doesn’t “focus” on Lithuania) uses PayPal for payments (which is fine with me) and is located 1 timezone away from me, when our suggested partner (APPA Market) is 2 timezones away. So that “focus” aspect doesn’t seem all that important.

What really pissed me off during the session was this:

image

Paid updates are bad for EVERYONE

When APPA Market was announced I immediately went to their web site and saw a price table which had (and still has) this bullet point:

  • Application update £15

Yalla Apps had a similar (yet slightly cheaper) structure. I expressed my concerns to Todd Brix after the session and tweeted this

image

and to my surprise when I checked Yalla Apps prices yesterday they were like this:

image

(1 credit <= $1). Now 1 credit is not totally free but is negligibly cheap. Kudos to Yalla Apps for listening to the community. APPA Market is still where it was on April 14th.

I understand that these publishing partners are for-profit organizations and aren’t supposed to do charity work or something like that, but being an official partner already gives them way more exposure and business than they would get otherwise. On the other hand they let Microsoft be lazy in this area, so MS could chip in a little or make the process for partners as easy as possible (good APIs to publish updates automatically, etc.).

Paid updates are bad for …

  • Microsoft and Windows Phone ecosystem in general. Developers won’t publish minor updates or even critical updates for non-profit (or no profit) apps if it costs them 15 pounds for each typo. This would result in lower quality apps in the marketplace and is very bad for the ecosystem.
  • Global Publishing Partners. On paper it looks like partners would be making money with paid updates but in reality I think it would result in less developers joining them based on such fee structure and of those who joined fewer will be actually posting the updates. Speaking for myself I decided not to join any of them when I saw that fee structure.
  • Developers. Well, this is obvious. And it even more depressing when you see 1st class “citizens” not only getting direct service but paying incomparably less for it.

Conclusion

Based on what I saw I was planning to turn my back on actual WP7 development for another cycle and further concentrate on my related projects (AdDuplex and amCharts). But now, with updated Yalla Apps pricing, I’m seriously considering joining them. I’ll wait till APPA Market launches on May 1st and if their pricing doesn’t change I’ll go with Yalla even though they are not my “focus” partner.

Tags: , ,

See You at MIX11!

4/8/2011 9:14:02 AM

Yesterday I’ve wrapped up my main work stuff. Today I’m doing my final travel preparations. Packing my bags on Saturday. Sunday is the trip day – Vilnius –> Kiev –> New York –> Las Vegas. MIX11 starts on Monday.

I’ll be attending HTML5 and jQuery bootcamps on Monday. With 11 TBA (to be announced) Windows Phone sessions I decided not to plan any session schedule upfront and decide what to attend on the spot. I would love to go on the WP7 track but I have doubts Microsoft is going to make it easier for us in Eastern Europe to do WP7 development and publishing. This cripples my interest a lot.

Open Source Fest

On Monday I’ll represent amCharts Quick Charts during the Open Source Fest – an event with more than 50 open source projects. If there was an award for the longest project name I’d be a winner already.

Anyway, if you want to chat about any amCharts products come to the amCharts table and we’ll talk. I’ll be wearing this t-shirt (unless my luggage is lost):

WP_000163

And don’t forget to leave some chips in my jar (or whatever they give me)!

Silverlight MIXer

WP_000157

I won an invitation to the l33t Silverlight party (organized by the awesome John Papa) with this work of modern art (pictured above). Looking forward to meeting (almost) all of the coolest people in Silverlight community.

Let’s talk

Let’s meet and talk about WP7, Silverlight, WPF, amCharts, AdDuplex … anything. I’ve learned from my mistakes last year and I’m bringing identifiable wardrobe to MIX11. So I should be easy enough to spot.

WP_000153WP_000155WP_000161WP_000162

OK. Back to last minute things…

See You at MIX11

Tags:

Obstruction Detection in Silverlight for Windows Phone

4/3/2011 1:12:14 PM

image

AdDuplex Silverlight control is used quite often as a fallback for other networks. As a result it could be obstructed by the other network’s control at times. Problem is that in general case we can’t rely on developers always collapsing AdDuplex control when it’s not visible or informing it about this state in any way.

The other problem is that some of the other network controls (namely Microsoft’s pubCenter) don’t collapse when they have no ad to show, but rather either collapse some internal elements or just make them transparent. This allows underlying elements to show through but they still don’t get the touch events.

So I decided to solve this programmatically. It sounded really easy, but as usual there are some small things that stand in the way.

Meet ObstructionDetector

I’ve created a class with some helper methods that could be useful both in the above scenario and probably some other. You can find it in full at the end of this post.

The “title” method of this class is IsElementObstructed:

public static bool IsElementObstructed(FrameworkElement target)
{
var page = GetPage(target);
var frame = GetFrame(target);
var transform = target.TransformToVisual(frame);
var rect = TransformBoundsToPortrait(transform.TransformBounds(new Rect(0, 0, target.ActualWidth, target.ActualHeight)), page);
var covers = VisualTreeHelper.FindElementsInHostCoordinates(rect, page);

if (covers != null && covers.Count() > 0)
{
return !IsElementChildOf(covers.First(), target);
}

return false;
}

You just pass an element in question to it and it returns true if there’s something in the way of user’s eyes or fingers in front of this element.

The key technique is to use VisualTreeHelper.FindElementsInHostCoordinates() method. It returns elements residing in the same rectangle on the screen as our target. The elements are returned in the descending z-index order. So what’s left to do is to check if the first element in returned collection belongs to (is a child of) our target. If so, then there’s nothing in the way.

A few gocthas

Everything is portrait to VisualTreeHelper.FindElementsInHostCoordinates()

I’ve spent quite some time trying to figure out why the code worked fine in Portrait pages but didn’t work in Landscape. Turns out FindElementsInHostCoordinates() considers everything as portrait oriented even when other parts operate correctly. Apparently this is “by design”. So we need to adjust to this “feature”. For that I’ve added TransformBoundsToPortrait() method.

Get PhoneApplicationPage by going up the visual tree

It’s tempting to use Application.Current.RootVisual and assume it’s child is our PhoneApplicationPage, but it’s not the case in some cases (like page transitions in Silverlight Toolkit). So it’s safer to just go up the visual tree until we find the page.

Account for SystemTray

We need to create a transform based on PhoneApplicationFrame (not Page) since transforming from PhoneApplicationPage doesn’t include optional SystemTray and can result in offset in the results.

Known Issues

  • VisualTreeHelper.FindElementsInHostCoordinates() doesn’t return elements with IsHitTestVisible set to false. So if someone creates a cover for your control and set this property to false it won’t be detected. Any ideas?

Feedback

I know this code is far from perfect, but it’s what I’ve got so far. I would really appreciated your feedback on how to improve it. The class is too small for a separate OS project or something like that, but I’d be happy if someone included it in some WP7 toolkit and improved on it.

The code

using System.Windows;
using System.Windows.Media;
using System.Linq;
using Microsoft.Phone.Controls;
 
namespace Ailon.Phone.Tools
{
    public static class ObstructionDetector
    {
        public static PhoneApplicationPage GetPage(DependencyObject target)
        {
            var parent = VisualTreeHelper.GetParent(target);
            while (parent != null && !(parent is PhoneApplicationPage))
            {
                parent = VisualTreeHelper.GetParent(parent);
            }
 
            return (parent as PhoneApplicationPage);
        }
 
        public static PhoneApplicationFrame GetFrame(DependencyObject target)
        {
            var parent = VisualTreeHelper.GetParent(target);
            while (parent != null && !(parent is PhoneApplicationFrame))
            {
                parent = VisualTreeHelper.GetParent(parent);
            }
 
            return (parent as PhoneApplicationFrame);
        }
 
        public static Rect TransformBoundsToPortrait(Rect bounds, PhoneApplicationPage page)
        {
            if ((page.Orientation & PageOrientation.Portrait) > 0)
            {
                return bounds;
            }
            else
            {
                Rect result;
 
                if (page.Orientation == PageOrientation.LandscapeLeft)
                {
                    result = new Rect(bounds.Y, bounds.X, bounds.Height, bounds.Width);
                }
                else
                {
                    result = new Rect(bounds.Y, 800 - bounds.X - bounds.Width, bounds.Height, bounds.Width);
                }
 
                return result;
            }
        }
 
        public static bool IsElementObstructed(FrameworkElement target)
        {
            var page = GetPage(target);
            var frame = GetFrame(target);
            var transform = target.TransformToVisual(frame);
            var rect = TransformBoundsToPortrait(transform.TransformBounds(new Rect(0, 0, target.ActualWidth, target.ActualHeight)), page);
            var covers = VisualTreeHelper.FindElementsInHostCoordinates(rect, page);
 
            if (covers != null && covers.Count() > 0)
            {
                return !IsElementChildOf(covers.First(), target);
            }
 
            return false;
        }
 
        public static bool IsElementChildOf(DependencyObject element, DependencyObject parent)
        {
            var current = element;
            while (current != null)
            {
                if (current == parent)
                {
                    return true;
                }
 
                current = VisualTreeHelper.GetParent(current);
            }
 
            return false;
        }
 
    }
}

Tags: ,

Copyright © 2003 - 2017 Alan Mendelevich
Powered by BlogEngine.NET 2.5.0.6