Category Archives: Uncategorized

Hack that 4K Monitor

As in http://arstechnica.com/information-technology/2015/08/open-source-typeface-hack-brings-design-to-source-code/ – “Combine it with an HD monitor and you can comfortably work at 6 or 7px sizes.”

I’m somewhat skeptical of that for 40-year-old+ users…but still it looks like an interesting typeface. I have yet to find anything else besides this that would be equal to or better than Consolas. It may be a good option for Mac use. However, if you look at the image below, the lack of a line spacing option in Visual Studio makes it a wash. I could, in fact, use 9-pt Consolas and still find it usable, although the height savings is only a line or so in 30! Perhaps in an IDE with a line-spacing option Hack would make more sense (or someone who is inclined to futzing with typeface editors could fork the project and create a reduced-line-height version).

hack_v_consolas
(click to embiggen)

On my 1920×1200 monitor, reducing Hack below 8 pt (or Consolas below 9 pt) is just not comfortable. That said, it is a highly-legible and pleasing typeface. I’ll try it out in Xcode too and see if it make a difference there.

Javascript @media queries

On newer browsers, you can match @media states like “(min-width: 45em)” using javascript, then apply conditional code. I only found this out last night. Today, I came across http://wicky.nillia.ms/enquire.js/. It not only offers some additional functionality beyond the vanilla javascript. It can be made backwards compatible even with IE6.

One of the best use cases is only loading certain content (via AJAX) if the screen size warrants it, e.g. a sidebar or a higher resolution image.

Picking the Right Voice for Windows Phone

Recently, I had an interesting problem come up when testing localization (in French and Spanish in my case) in conjunction with letting the user choose a female or male voice in one of my Windows Phone apps (http://www.windowsphone.com/en-us/store/app/fn8/dd72d13d-1a7b-42c4-81d3-adbc98d4b002). The main part of the problem is basically financial, i.e. given the economics of app development it isn’t feasible to localize for many languages, let alone variants (cultures), e.g. whatever dialect of French is spoken in lower, mid-western Upper Volta. Additionally, given the inefficient workings of the Windows Phone store, it takes forever to submit (or even update) an app for each supported language. In my case, I have asked my translators to use a international a flavor as possible to cover as many markets as I can. Localizing into a language will still allow you to reach all the cultures that support the base language, e.g. localizing into Spanish will work for users in Spain (es-es) as well as Mexico (es-mx).

Part of the problem is technical. If you go this route, then when the user selects a gender for an installed voice, the app has to be able to match the appropriate voices from among those installed. With my first approach what I found when testing was that no voices were being selected at all in a device set to Mexican Spanish. The reason became immediately apparent when debugging:

The app was working fine in English because I was looking for a culture name and because en-us was the default culture for the app, it was finding that. But since the Spanish-speaking user is only getting a generic Spanish translation, the app was looking for a culture name of es-mx and blithely skipping over plain ol’ es.

So then I switched to grabbing the two-letter ISO language name instead. That made the app feliz in Español, but now on my device set to American English I was getting a male voice with a British accent when the radio button was set to female.

Another quick debug session and I could see that American voices Mike and Zira had some friends in the house I didn’t know about, including George and Susan from Great Britain and their friends Raul from Mexico and Stefan from Germany. All obviously there to enjoy Cortana’s predictions on the World Cup.

So here’s what can only be described as an amateurish hack to deal with this issue. Well, as my co-workers and I used to tell our boss in a previous job, all our code is “QDC – quick, dirty, or cheap. Pick any two.”

var twoLetterIsoLanguageName = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;

var currentCultureName = CultureInfo.CurrentCulture.Name;

IEnumerable<VoiceInformation> voiceInfos = from voice in InstalledVoices.All select voice;

var localVoices = new List<VoiceInformation>();

// See if any voices match the current culture specifically
foreach (var voiceInfo in voiceInfos)
{
 if (voiceInfo.Language == currentCultureName)
 {
 localVoices.Add(voiceInfo);
 }

 localVoices =
 localVoices.OrderByDescending(v => v.Language).ThenByDescending(v => v.Gender).ToList();
}

// No matches? Go for the generic language instead
if (localVoices.Count < 1)
{
 foreach (var voiceInfo in voiceInfos)
 {
 var primaryLangStr = voiceInfo.Language.Split('-')[0];

 if (primaryLangStr == twoLetterIsoLanguageName)
 {
 localVoices.Add(voiceInfo);
 }

 localVoices =
 localVoices.OrderByDescending(v => v.Language).ThenByDescending(v => v.Gender).ToList();
 }
}

App.StorageSettings.TryGetValue("VoiceGender", out _voiceGender);

_speechSynthesizer.SetVoice(localVoices.ElementAt(_voiceGender));

Cancelling Windows Phone SpeechSynthesizer under different conditions

While testing one of my apps I realized that long bits of speech were interfering with other sound effects in the app. Since they (unfortunately) can’t play simultaneously, I needed a way to cancel the speech sound if it exceeded three seconds. And, yes, this has a negative side-effect of abruptly cutting off mid-sentence. However, that’s mitigated by the same text appearing on screen.

I also need the Task to be cancelled externally if, for example, the user switches to another page or resets the app to the beginning. The following code is able to do both these things:

public async Task TextToSpeech(string text, CancellationToken externalCancellationToken)
{
 try
 {
 var internalCancellationTokenSource = new CancellationTokenSource();
 var internalCancellationToken = internalCancellationTokenSource.Token;

using (
 var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(internalCancellationToken,
 externalCancellationToken))
 {
 linkedCts.CancelAfter(3000);

var alreadyPlayed = false;

while (!linkedCts.IsCancellationRequested)
 {
 if (!alreadyPlayed)
 {
 _speechSynthesizer.SpeakTextAsync(text);

alreadyPlayed = true;
 }

if (linkedCts.Token.IsCancellationRequested)
 {
 _speechSynthesizer.CancelAll();
 }
 }
 }
 }
 catch (Exception err)
 {
 Debug.WriteLine(err.Message);
 }
}

There are a couple funky things to note: You’ll get a warning about the async modifier on the Task. Remove it and the app won’t compile because it will expect a return type. Why not use a void method? It wouldn’t be cancellable. The other is the use of the SpeechSynthesizer.CancelAll() method. You can set SpeechSynthesizer.SpeakTextAsync() to an IAsyncAction, e.g. “var task = _speechSynthesizer.SpeakTextAsync(text);” and do task.Cancel(). But this didn’t seem to have any effect.

So use the CancelAll method and be sure to wrap it in a try-catch block to head off the error it will throw.

Geocognitivity?

http://www.fastcodesign.com/3020708/evidence/the-science-of-a-great-subway-map

Generally, I think the simplification works, particularly in the redesign of the Boston subway map. But the last example ( a weekend schedule) struck me as better for the geographically knowledgeable local than for any out-of-town visitor. The map it replaces is horrible, but there must be some happy medium that would keep enough geographic context.

Comparing the geographically detailed map with a schematic version

As a visitor, I’d likely be looking at a potential destination, then figure out how to get there. Of course, who uses these maps anymore when every smartphone will just tell you which line to take? Although I found the hardest part of dealing with public transit that way (at least when last in Seattle) was figuring out which way to go when on foot in between buses.

Overall, an article worth reading. The visual tracking research and renderings depicting user perception are fascinating.

Music to Code By

When I was in college, I used to listen to music all the time when studying. I worked at KGLT (still one of the best alternative college stations in the country) as a DJ and the assistant manager (which meant sometimes being referred to by the music director – all innocence and sweetness – as the “ass. mgr.” in written communications). I had access to all kinds, but mostly liked grungy, thrashy music…and liked all of it loud. People would ask how I could ever study like that. But, believe it or not, the volume served to drown out external distractions and helped me focus.

I no longer find that true of the hard stuff. I still crank it up on occasion, but even find that on my bike rides or while running that I prefer thinking in relative silence. So while working, my musical choices have become more judicious. I still find Classical unappealing in this setting, needing a little more pep in the morning. (That’s why NPR always goes off  after 8:00 a.m!)

One of my favorites is Alberta Hunter’s Downhearted Blues: Live at the Cookery. If you’ve never checked out this wonderful performer, you owe it to yourself to not only enjoy the music, but also to fully consume her inspirational story.  There’s a good bio here but I was first introduced to her and her music by the documentary Alberta Hunter: My Castle’s Rockin’, which captures just how remarkable she was as a performer and a person. (You can find it here).

Accompanied on piano by the elegant gentleman and composer, Gerald Cook, Hunter really struts her stuff. Even at age 82 she still had the charm and impeccable timing that originally made her a star way back when. It’s worth watching just to see how a professional does it. I also find inspiring both her self-effacing modesty and her sometimes risque banter.

Most of all, Hunter has some wise advice – some of which will bring tears to your eyes if you’ve ever felt blocked or frustrated. Her words are without question informed by a life spent first working her way up the hard way to stardom, then chucking it all to change careers. She prudently fudged her age, conjured up a high school diploma, went to nursing school and worked in health care until forcibly retired in 1977 at the age of 82. Then resumed her musical career at an age when most people are probably just thinking about what the nursing home will serve for lunch today.

Did ya hear the one about the serial killer?

Turns out his victim was found floating in a tub full of corn flakes and milk. Bahhh, dahhh, dahhh, da.

Anyway, in this case it was more that the serializer got killed…by an uncoöperative class. (BTW, that’s not an umlaut over the second “o”. It’s a diaeresis. Lovely sounding term. More on the subject: http://www.newyorker.com/online/blogs/culture/2012/04/the-curse-of-the-diaeresis.html). Typically, this happens because the class has a constructor with parameters. I couldn’t get around that. Well, I don’t want to anyway. I also didn’t want to depart from my vanilla JSON serializer, although in the past I’ve found SilverlightSerializer to be a solution when all else fails…like serializing an entire model. (Why would you want to do that? Long story, for some other time).

The solution is to simply mark up the class with the DataContract attribute and use DataMember for each of the members you want to serialize. In my case, this had the advantage of not serializing a voluminous sub-list I don’t want included. And it allows this class to be used in several places, rather than creating a separate Dictionary or similar.


[DataContract]
public class Exercise
{
 public List<Asset> AssetsList;

public Exercise(int id, int order, string description)
 {
 Id = id;

Order = order;

Description = description;

AssetsList = new List<Asset>();
 }

[DataMember]
 public int Id { get; set; }

[DataMember]
 public int Order { get; set; }

[DataMember]
 public string Description { get; set; }
}

And, voila, we end up with something that can be saved to IsolatedStorage:

[{“Description”:”JUMPING JACKS”,”Id”:0,”Order”:0},{“Description”:”WALL SIT”,”Id”:1,”Order”:1},{“Description”:”PUSH UPS”,”Id”:2,”Order”:2},{“Description”:”CRUNCHES”,”Id”:3,”Order”:3},{“Description”:”STEP UPS”,”Id”:4,”Order”:4},{“Description”:”SQUATS”,”Id”:5,”Order”:5},{“Description”:”TRICEPS DIP”,”Id”:6,”Order”:6},{“Description”:”PLANK”,”Id”:7,”Order”:7},{“Description”:”HIGH KNEES”,”Id”:8,”Order”:8},{“Description”:”LUNGES”,”Id”:9,”Order”:9},{“Description”:”PUSH UP & ROTATE”,”Id”:10,”Order”:10},{“Description”:”SIDE PLANK”,”Id”:11,”Order”:11}]

Market share, market share, market share

First, why is a developer writing about this? The most obvious reason is that there has to be at least some market to make it worthwhile to create and promote apps. What I find misleading, however, is raw percentage numbers. There’s no denying that if a raw percentage is too low, e.g. Blackberry, you’re wasting your time. That platform is dead in the water.

But I also have doubts over the value of Android’s seemingly commanding 80% of worldwide smartphone users. And I find it amusing/disturbing that many still dismiss Windows Phone because it has 1/4th the share that iPhone does. While no one writes off Apple because it has 1/4th the share of Android.

From a developer perspective, it (literally) pays to look deeper into the numbers. Recently I’ve read that a good number of Android apps are simply pirated, which in certain countries is also true for iPhone, since a good many are jailbroken. I’m sure there are many reasons, including the “free” OS ethos Google likes to promote, that Android users don’t pay for apps. And that seems to apply across national boundaries. But in some places, Apple faces the same problem.

80% market share is not as impressive if only 1% of users ever pay for your apps. Granted, that can still be a large actual number. But the point is, again, it’s worthwhile to not just take raw numbers at face value. Because of the underlying lack of value, I’ve never been interested in developing for Android. Technically, it would seem more feasible for a C# developer to move to Java. Prior to Xamarin (which doesn’t solve all my problems), the main barrier to iOS development for me has been finding the time to fit in learning Objective-C. C# has been my bread-and-butter, actual make-a-living, development language for quite some time.

Going forward, I will develop or work with other developers to get into the iOS market. I’ve read a few negatives such as many iPhones in places like China are jailbroken. And that apps are mercilessly copied and slowly purged by an indifferent Apple App Store. (But the latter has happened somewhat to me too in the Windows Phone store, where elements of an app were poorly aped – like some sort of Bizarro Superman version). Yet – if one can do enough outside promotion – the iOS market is definitely worthwhile.

Much has been written about the diminishment of Apple (reflected in its stock price) and even its potential demise if developers ever switch to an Android-first policy en masse. But I doubt I’m the only developer that has noticed that Apple still holds almost half the American smartphone market (never mind tablets). And that, along with European/ANZ markets, is almost certainly where people are not adverse to shelling out 1/3rd the price of a Starbucks latte for apps.

On to Windows Phone. While it has made some impressive gains in certain markets – particularly in Europe (http://www.kantarworldpanel.com/Global/News/Record-share-for-Windows-phone) – there is both good and bad for the developer. First the bad: Windows Phone still doesn’t have a great share in the U.S. It’s just 3.5%…up from about 3.0 from the same quarter last year.

Also (less bad), the people buying Windows Phones tend to be converting from feature phones. While I don’t have proof, I have concerns whether they’re willing to spend on apps. Furthermore, it’s not Android/iOS users jumping ship and giving mind share to Microsoft/Nokia.

Finally, (least bad but also potentially indicative of shallow pockets), the Windows Phones people are getting are not the trophy devices like the Lumia 1020. Rather, the 520 is the most popular phone. I say least bad because – from a developer standpoint – even the lowliest Lumia is still going to hold up pretty well to your coding demands. It might not support some games but that’s an invitation to put more creative thought into the game play rather than the special effects. I have both a 920 and a 620. While I’d never choose the 620 as my personal phone, it’s a dandy little device and runs my code just the same as its bigger, heavier brother.

Also, bear in mind that outside the U.S. phones are rarely subsidized. In Europe, too, everything tends to be more expensive (my wife still reminds me how I paid €3.00 for floss in Italy). Paying for a phone up front would, in my opinion, lead one to the cheaper models. So perhaps given that backdrop doesn’t mean users are going to be payment-adverse when it comes to apps. (More on that below).

The good news for the developer is that market share is growing. It may not be perfect and may not be widespread, but if it was contracting after all this time, there would be no clearer message to get out. What is also encouraging is that – at least for my two current apps in the Windows Phone Store ( 7-Minute Workout – http://www.windowsphone.com/en-us/store/app/7-minute-workout/879efccc-5c9e-4b19-b8e6-346b76ff0133 and Ballistica – http://www.windowsphone.com/en-us/search?q=ballistica) – conversion rates from trial to paid are quite good. 7-Minute Workout, which is a more broadly popular app and is priced at the sweeter spot of $0.99, has a 20.6% conversion rate. Ballistica, which is definitely a niche app (aimed at target shooters and hunters), has a 14.3% conversion rate.

I should point out that despite not (yet) being localized, 7-Minute Workout has done really well in non-U.S. markets, further strengthening my hypothesis (Isn’t that what you call any notion relying on anecdotal data?) that Windows Phone users tend to be more like their iOS counterparts, i.e. willing to pay for good apps.

So when it comes to percentages, a larger paid percentage of a smaller market share may well beat writing apps that never make a dime off a vast pool of freeloaders…did I say that?

On a topical note: I do hope (as expressed in the intro to Outkast’s Hey Ya http://www.youtube.com/watch?v=PWgvGjAhvIw) that Microsoft doesn’t screw up the acquisition of Nokia’s phone assets. It’s still critical that they find a way to build up U.S. market share.

Turning down a job offer

Here’s most of a reply I made to a potential employer that just offered me a pretty good position doing .NET web development:

I’m basically crazy to turn down any other work given the sad state of Windows 8 adoption and hardly better for Windows Phone. Yet I’m going to stick with that and eventually get my Xamarin/iOS skills up to speed. I thought about it and what I want to do quite a bit while being away from the computer for over a week. While the money sucks, being a micro-ISV is going to make me happier than doing what I’ve been doing for all my working life, which is building someone else’s equity. Don’t get me wrong. I’ve worked for some great companies/people and you’d be one of them. But now’s the time to really take a shot at this. Even when I ran my own business with 4.5 employees it was always working on somebody else’s projects. While all work is essentially working for somebody else – even apps – the crucial difference is that it’s me interacting with end users as customers.

Yes, I am f***in’ crazy to turn that down. Right now, my app income is measured in the hundreds of dollars. And if it wasn’t for working my butt off the last couple years, saving most of it and having a doctor for a wife I wouldn’t even be writing this. Lately, I’ve read two damning articles on Windows 8 and Windows Phone but time to put the blinders on, damn the torpedos and full speed ahead.

 

 

Localizable Balloon Tooltip Control

I wanted to create a tooltip in the style of the balloons used in Windows Phone apps like Messaging. Almost immediately, I realized it needed to be localizable, which would mean adjustable in width to accomodate text lengths in different languages.

In the past I’ve bound XAML elements, such as WPF menus to the ActualWidth of another element, e.g:

Width="{Binding ActualWidth, ElementName=window, Mode=Oneway}"

However, in this case I couldn’t get the desired result, which is to have a bit of padding on either side of the text. What documentation I read suggested that ActualWidth would take into account Margin settings. But I had to resort to a hack in the code-behind, adding a line to the constructor:


public MessageBoxControl()
 {
 InitializeComponent();

TextGrid.Width = MsgText.ActualWidth + 16;
 }

Here’s the XAML:


<UserControl x:Class="Controls.MessageBoxControl"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 mc:Ignorable="d"
 FontFamily="{StaticResource PhoneFontFamilyNormal}"
 FontSize="{StaticResource PhoneFontSizeNormal}"
 Foreground="{StaticResource PhoneForegroundBrush}"
 d:DesignHeight="56" d:DesignWidth="440">

<Grid x:Name="LayoutRoot" Background="Transparent" IsHitTestVisible="False" Height="56"
 Width="{Binding ActualWidth, ElementName=TextGrid, Mode=OneWay}" MaxWidth="440">

<Grid.RowDefinitions>
 <RowDefinition Height="32" />
 <RowDefinition Height="24" />
 </Grid.RowDefinitions>

<Grid Name="TextGrid" Background="#FFD68B" Grid.Row="0" MinWidth="200" MaxWidth="440">
 <TextBlock Name="MsgText" Foreground="#2368B0" FontSize="24" Height="32" MaxWidth="424"
 HorizontalAlignment="Center" TextTrimming="WordEllipsis"
 Text="{Binding Path=LocalizedResources.ResetMessage, Source={StaticResource LocalizedStrings}}"/>
 </Grid>

<Grid Grid.Row="1">
 <Path Name="Tail" Fill="#FFD68B" Data="M-1,-1,24,24,24,-1,-1,-1"
 HorizontalAlignment="Left" Width="24" Height="24" Margin="24 0" />
 </Grid>

 </Grid>
</UserControl>

Note that a MaxWidth is assigned to Grid and Text elements. Also, the TextTrimming attribute is set. This is meant to safeguard against exceeding the width of the display in Portrait mode. 

And a sample screen shot of a (hopefully accurate) French translation of “Hold to reset to 0:00”:

balloon_example