What we have learnt during the development of Speak Reminder and Group Tiles

So it’s been a while since we published Group Tiles and Speak Reminder to the Windows Phone Store. In case you did not know, Group Tiles is an app to create header tiles on the Start Screen to separate your messy tiles into distinguishable parts, and Speak Reminder is an app leveraging the Voice commands functions of Windows Phone 8 to help you create quick reminders.

You can download the 2 by scanning or clicking on the 2 QR code below:

Group Tiles

Speak Reminder

 

We did get a significant number of users of those apps, around 30 thousands for Group Tiles and 3 thousands for Speak Reminder. That is great not just because of all the encouragement and opportunity of that user base, but our users also help us to identify so many small bugs that were not stated on the Windows Phone Dev Center.

Group Tiles

Ok I will start with this guy first. This was really a big success for us. First day, we have 16 downloads, rather in line with our previous apps on Windows Phone, but then second day, we have more than 600. We were so amazed by the number and then shocked on the day this app was featured on WMPowerUser, almost 3000 in a single day.

Unfortunately, we did not prepare for that “success”. Our host provider constantly complained us abusing the shared server and suspended our account. We then realized the problem in our telemetry service (yes, I build one for our app instead of using an existing service like flurry to get more control and also to learn more about those kinds of problems). Somehow it went crazy consuming all the CPU resources, even though only a simple insert command is execute with the entity framework.

Back at that time I was so naïve and write the very “simple” lines as below to insert an information log to a project:

info.Project = project;
project.Infoes.Add(info);
context.Infoes.Add(info);
context.SaveChanges();

What could go wrong anyway? The first 2 lines were for the association between the 2 entities. The third line were to add that new info entity to the database and the last were to save all changes. I then had to profile each line of my code (there some other processing as well) to find the culprit, and it turned out to be the second line was not only unnecessary but also very dangerous:

project.Infoes.Add(info);

Instead of just marking the association, this would query all the info records of this particular project (which is around 10,000 at that time) every time a new one was inserted (at a crazy rate of around 1 time per second). Removing that line and everything worked exactly as expected.

We then moved all the telemetry modules to Azure Web Sites and SQL Azure, and were very happy with what those 2 provided, including very useful monitoring information on the dashboard.

So there were also two other small bugs that was detected by our users, one are very easy to identify and the other are more difficult to identify and fix.

IOException & IsolatedStorageException

This one was so straight forward although I doubt not many apps check for that. The app simply could not save the tile images when there is not enough space on the phone, and it could not save any settings as well, so be careful of this case if you put something important into the isolated settings.

ArgumentException – XcpImports

This was the full stack of that exception:

at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
at MS.Internal.XcpImports.SetValue(IManagedPeerBase obj, DependencyProperty property, DependencyObject doh)
at MS.Internal.XcpImports.SetValue(IManagedPeerBase doh, DependencyProperty property, Object obj)
at System.Windows.DependencyObject.SetObjectValueToCore(DependencyProperty dp, Object value)
at System.Windows.DependencyObject.SetEffectiveValue(DependencyProperty property, EffectiveValueEntry& newEntry, Object newValue)
at System.Windows.DependencyObject.UpdateEffectiveValue(DependencyProperty property, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, ValueOperation operation)
at System.Windows.DependencyObject.SetValueInternal(DependencyProperty dp, Object value, Boolean allowReadOnlySet)
at Microsoft.Phone.Controls.PhoneApplicationFrame.System.Windows.Controls.IFrame.set_Content(Object )
at System.Windows.Navigation.NavigationService.CompleteNavigation(DependencyObject content, NavigationMode mode)
at System.Windows.Navigation.NavigationService.<>c__DisplayClass7.b__4()

There was not much information inside the exception to identify what had caused the crash. It happened in all our apps and we could not reproduce the problem at all.

I left it there for a while until I suddenly reproduced the crashes with the same exception: we navigated to a page inside the OnNavigatedTo function of another page, which sometimes caused both page to appear (one just overlay on the other), then the app would crash if the user press back button. The problem was slightly overcame by putting the navigation inside Loaded event handler instead, and now the crash rarely occurs.

Speak Reminder

We were very careful in implementing with the new speech feature of Windows Phone. There is a post here http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj662934(v=vs.105).aspx stating how to handle speech error. However, they only handle the function call, which is definitely not enough.

There are 2 other places that you will have to wrap with try catch block. The first one is the SpeechRecognizer, SpeechRecognizerUI and SpeechSynthesizer constructors, and the second one is the function call to register the VCD file with the system. Below are the exceptions that we have met in Speak Reminder

Exception (Exception from HRESULT: 0x800455BC) – SpeechRecognizer, SpeechRecognizerUI, SpeechSynthesizer constructors

    at Windows.Phone.Speech.Recognition.SpeechRecognizerUI..ctor()

As the documentation on Dev Center, this error code means “The requested language is not supported.” And this will happen on a new phone (or sometimes after you reset the phone) when the speech is activated, a language is chosen, but the language pack is not actually downloaded and installed on the phone. The user will have to go to phone settings to choose another speech language and then switch back again to see the message prompt for installing the language pack.

ArgumentException (Value does not fall within the expected range.) – SpeechRecognizer, SpeechRecognizerUI, SpeechSynthesizer constructor

    at Windows.Phone.Speech.Recognition.SpeechRecognizerUI..ctor()

This one is rather strange and is not documented on Dev Center. This also happens on new phone; sometimes there is no selected speech language. The user just have to choose one and this should be ok.

FileNotFoundException (The system cannot find the file specified. (Exception from HRESULT: 0x80070002)) – InstallCommandSetsFromFileAsync

at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()

This one is very strange and I have not found the exact reason or solution for this. Would be very grateful if someone can tell me how to handle this case (except from silencing the error or just show a useless error message). I found something about missing XML files on some phones, but I am not too sure about that.

DirectoryNotFoundException (The system cannot find the path specified. (Exception from HRESULT: 0x80070003)) – InstallCommandSetsFromFileAsync

at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()

This one is the same as the above.

Conclusion

It is a great opportunity for me to improve my skills when there is that large number of users, and I am very happy about that. On other lesson that I have learnt about Windows Phone Dev Center is that the automatic crash reports of the system usually lack of information (for example inner exception or stack trace), so you should try to report it yourself.

Windows Store certification, and Privacy Policy again

I think I have seen many different posts on this already. People keeps reminding others about putting a Privacy Policy page if you app happens to connect to the Internet.

I already have a published app on the Store, and this time is my second one. I always remember about the requirements so I put a setting for Privacy Policy right from the beginning and linked it to a page on the app website. The problem was I had not implemented the webpage at all. The situation at that time forced me to publish the app rather early, so I decided to put the website later, after I had submitted the app, when the certification was going on.

Pushing the website back was a good idea and it helped me to finish the app on time, but it turned out to be not a totally good. One may suggest that I should have put a basic page for the Privacy Policy and delayed the rest, but the problem was more complex than that. There were actually 3 pages that need to be implemented for the certification: the Privacy Policy of course, the How To page (I included this setting as well, thinking that this could help me to put work later, even after the app is published on the Store), and surprisingly the home page as well (I put a link to the home page inside the About settings). The home page surprised me because I thought I already have it there, but then I realize the testers also rejected the current blank home page (with a default Index header on top); this was regards as incomplete functionality of the app.

So next time I will have to note down every link I have inside the app, making sure that I do not forget any of them before a Microsoft tester starts to fail the app!

And I would say, this is painful.