WP8

How to use WordPress to display remote notifications in your Windows Phone app

Sometimes, we need to display information to our users on demand. The easiest way is to do this in our app via a remote notification service.

If you have a WordPress blog, my solution may also be helpful for you.

I am using a page that is not linked anywhere in my blog to display the message. To add a new page, go to your WordPress Dashboard and hover over “Pages” and click on “Add New”.

image

Fill in the title and your notification and publish the page. Before closing your browser, save/remember the id of the page, we will need it later.

image

The next step is to download my WordPress Universal library, which can be downloaded right here from my Github. You can add the project directly to your solution or build it and then reference the library you will find in the bin folder of the WordPress Universal project folder. If you want to learn more about the library, visit http://bit.ly/WordPressUniversal.

Now that we have everything in place, let’s add the code that does the magic for us:

        public async void ShowNotification()
        {
            //initialize the client and load the list of pages from your blog
            wpClient = new WordPressClient();
            var pages = await wpClient.GetPostList("msicc.net", WordPressUniversal.Models.PostType.page, WordPressUniversal.Models.PostStatus.publish, 20, 0);

            //select the notification page
            var notificationContentPage = from p in pages.posts_list where p.id == 4248 select p;

            //check if has content
            if (!String.IsNullOrEmpty(notificationContentPage.FirstOrDefault().content))
            {
                //convert parapgraphs into NewLines
                //you might have more HTML content in there which needs to be converted
                string content = notificationContentPage.FirstOrDefault().content.Replace("

", string.Empty).Replace("

", "\n\n"); //App.SettingsStore = ApplicationData.Current.LocalSettings //change this to your appropriate storage like IsolatedStorage etc. //this displays the message only once to our users, but keeps the door open for an easy update mechanism if (App.SettingsStore.LastNotificationContent != content) { MessageBoxResult result = MessageBox.Show(content, notificationContentPage.FirstOrDefault().title, MessageBoxButton.OK); switch (result) { //the button click saves the actual message case MessageBoxResult.OK: App.SettingsStore.LastNotificationContent = content; break; //BackButtonPress does this as well case MessageBoxResult.None: App.SettingsStore.LastNotificationContent = content; break; } } } }

What does this code do? First, it fetches all pages from our WordPress blog. Then, we are selecting the page we created via its id. If your WordPress blog does not show you the id in the url of the page, set a BreakPoint at the “var notificationContentPage = …” line. you will then easily be able to get the id:

image

Naturally, the returned content is HTML formatted. To remove the paragraph tags and but respect their function, we are using a simple String.Replace pattern. You may have more HTML tags in your message that needs to be removed or converted.

To generate an easy way to display the message only once but keep it open for updates, we are saving the converted message locally. In this case, I used the LocalSettings of my Windows Phone 8.1 app. I am using the MessageBoxResult to make the method saving the message either at the point of the OK click as well as on BackButtonPress.

This is how the above generated WordPress Page looks as a Notification:

wp_ss_20141127_0001

As my WordPress Universal library works cross platform for C# apps, you should be able to adapt this for your Windows 8.1 or  Xamarin apps as well.

As always, I hope this is helpful for some of you.

Happy coding!

Posted by msicc in Archive, 1 comment

WordPressUniversal – a PCL library for WordPress based C# mobile apps

WP_CSharp_Lib

As I have already developed a news reader app for my blog, I got asked quite a few times if I want to share my code to help others creating their apps. As I need to redesign my blog reader to match the latest OS features of Windows and Windows Phone, I decided to create my WordPressUniversal library.

Automattic, the company behind WordPress, integrated a powerful JSON API into their JetPack plugin. My library is based on this API. Please make sure the JSON API is active on the blog you are developing your app for.

The library currently provides the following features:

  • getting a list posts or pages
  • getting a list of all categories
  • getting a list of comments for the site and single posts
  • supports Windows Phone 8 & 8.1 Silverlight, Windows Phone 8.1 RT, Windows 8, Xamarin.iOS and Xamarin.Android

The library deserializes all data into C# objects you can immediately work with.

It is still a work in progress, but as it provides already a bunch of options to get you started, I am making this public already.

I am constantly working on the library, so be sure to follow the project along.

Note: JetPack’s JSON API does not support guest commenting at the moment. I already reached out to Automattic to (hopefully) find a solution for this. If you cannot wait, Disqus has a portable solution for Windows Phone apps.

Please make sure to see the documentation on my GitHub page.

If you have any questions, idea, wishes for me, just post a comment here or ping on Twitter.

Happy coding everyone!

Posted by msicc in Archive, 17 comments

How to load a list of a user’s twitter friends/followers in your Windows Phone app

TwitterFriendsList_WP_Blog During the last days, I was adding a new function to UniShare that suggests users the Twitter handles while typing in some text. The base of this new function is a list of the user’s twitter friends. In this post, I am going to show you how to generate this list and save it for further use. First thing I need to talk about: you can only load a maximum of 3000 friends at once due to the rate limit on Twitter’s part. At the end of the post, I’ll give you also an idea how to continue this after the first 3000 users were loaded. For the most scenarios, 3000 should be enough to cover the major part of your users. To be able to load all friends we first create a Task that fetches 200 entries of our user’s friends list. To be able to perform paging through all entries, Twitter uses so called cursors, which are 64-bit signed integers (long). You can read more about that here on Twitter’s API documentation. Let’s have a look on this Task:

        private async Task<string> TwitterFriendsListString(long twitterCursor)
        {
            ShowProgressIndicator("generating mention suggestion base...");

            //needed for generating the Signature
            string twitterRequestUrl = "https://api.twitter.com/1.1/friends/list.json";

            //used for sending the request to the API
            //for usage of the url parameters, go to https://dev.twitter.com/docs/api/1.1/get/friends/list
            string twitterUrl = string.Format("https://api.twitter.com/1.1/friends/list.json?cursor={0}&screen_name={1}&count=200&skip_status=true&include_user_entities=false", twitterCursor, App.SettingsStore.twitterName);

            string timeStamp = GetTimeStamp();
            string nonce = GetNonce();

            string response = string.Empty;

            //we need to include all url parameters in the signature
            //IMPORTANT: Twitter's API demands them to be sorted alphabetically, otherwise the Signature will not be accepted
            string sigBaseStringParams = "count=200";
            sigBaseStringParams += "&" + "cursor=" + twitterCursor;
            sigBaseStringParams += "&" + "include_user_entities=false";
            igBaseStringParams += "&" + "oauth_consumer_key=" + twitterConsumerKey;
            sigBaseStringParams += "&" + "oauth_nonce=" + nonce;
            sigBaseStringParams += "&" + "oauth_signature_method=HMAC-SHA1";
            sigBaseStringParams += "&" + "oauth_timestamp=" + timeStamp;
            sigBaseStringParams += "&" + "oauth_token=" + App.SettingsStore.twitteroAuthToken;
            sigBaseStringParams += "&" + "oauth_version=1.0";
            sigBaseStringParams += "&" + "screen_name=" + App.SettingsStore.twitterName;
            sigBaseStringParams += "&" + "skip_status=true";
            string sigBaseString = "GET&";
            sigBaseString += Uri.EscapeDataString(twitterRequestUrl) + "&" + Uri.EscapeDataString(sigBaseStringParams);

            string signature = GetSignature(sigBaseString, twitterConsumerSecret, App.SettingsStore.twitteroAuthTokenSecret);

            string authorizationHeaderParams =
                "oauth_consumer_key=\"" + twitterConsumerKey +
                "\", oauth_nonce=\"" + nonce +
                "\", oauth_signature=\"" + Uri.EscapeDataString(signature) +
                "\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"" + timeStamp +
                "\", oauth_token=\"" + Uri.EscapeDataString(App.SettingsStore.twitteroAuthToken) +
                "\", oauth_version=\"1.0\"";

            HttpClient httpClient = new HttpClient();

            httpClient.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("OAuth", authorizationHeaderParams);
            var httpResponseMessage = await httpClient.GetAsync(new Uri(twitterUrl));

            response = await httpResponseMessage.Content.ReadAsStringAsync();

            return response;
        }

As you can see, we need to create our signature based on the url parameters we are requesting. Twitter demands them to be sorted alphabetically. If you would not sort them this way, the Signature is wrong and your request gets denied by Twitter. We are overloading this Task with the above mentioned cursor to get the next page of our user’s friends list. If you need the GetNonce() and GetSignature() methods, take a look at this post, I am using them for all requests to Twitter. Now that we have this Task ready to make our requests, lets load the complete list. First, declare these objects in your page/model:

        public List<TwitterMentionSuggestionBase> twitterMentionSuggestionsList;
        public long nextfriendlistCursor = -1;
        public string friendsResponseString = string.Empty;
        public string friendsJsonFileName = "twitterFriends.json";

Then we need to create a loop to go through all pages Twitter allows us until we are reaching the rate limit of 15 requests per 15 minutes. I using a do while loop, as this is the most convenient way for this request:

            //to avoid double entries, make sure the list is we are using is empty
            if (twitterMentionSuggestionsList.Count != 0)
            {
                twitterMentionSuggestionsList.Clear();
            }
            //starting the do while loop
            do
            {
                //fetching the Json response
                //to get the first page of the list from Twitter, the cursor needs to be -1
                friendsResponseString = await TwitterFriendsListString(nextfriendlistCursor);

                //using Json.net to deserialize the string
                var friendslist = JsonConvert.DeserializeObject<TwitterFriendsClass.TwitterFriends>(friendsResponseString);
                //setting the cursor for the next request
                nextfriendlistCursor = friendslist.next_cursor;

                //adding 200 users to our list
                foreach (var user in friendslist.users)
                {
                    //using the screen name ToLower() to make the further usage easier
                    TwitterMentionSuggestionsList.Add(new TwitterMentionSuggestionBase() { name = "@" + user.screen_name.ToLower() });
                }

                //once the last page is reached, the cursor will be 0
                if (nextfriendlistCursor == 0)
                {
                    //break will continue the code after the do while loop
                    break;
                }
            }
            //the while condition needs to return true if you would set up a Boolean for it!
            while (nextfriendlistCursor != 0);

As long as the cursor is not 0, the loop will load the json string with 200 entries. The class you’ll need for deserializing can be easily generated. Just set a breakpoint after the call of our Task, copy the whole response string and go to http://json2csharp.com to get your class. The TwitterMentionSuggestionBase class only contains a string property for the name and can be extended for you needs:

    public class TwitterMentionSuggestionBase
    {
        public string name { get; set; }
    }

Of course we need to save the list for further use. The code I use is pretty much the same you’ll find when you search for “saving json string to file” with your favorite search engine and works with Windows Phone 8 and 8.1:

            //saving the file to Isolated Storage
            var JsonListOfFriends = JsonConvert.SerializeObject(twitterMentionSuggestionsList);
            try
            {
                //getting the localFolder our app has access to
                StorageFolder localFolder = ApplicationData.Current.LocalFolder;
                //create/overwrite a file
                StorageFile friendsJsonFile = await localFolder.CreateFileAsync(friendsJsonFileName, CreationCollisionOption.ReplaceExisting);
                //write the json string to the file
                using (IRandomAccessStream writeFileStream = await FriendsJsonFile.OpenAsync(FileAccessMode.ReadWrite))
                {
                    using (DataWriter streamWriter = new DataWriter(writeFileStream))
                    {
                        streamWriter.WriteString(JsonListOfFriends);
                        await streamWriter.StoreAsync();
                    }
                }
            }
            catch
            {

            }

This way, we can easily generate a friends list for our users, based on their Twitter friends. Some points that might be helpful:

  • users with more than 3000 friends will receive an error after reaching this point on our task. Catch this error, but continue to save the already loaded list. Save the latest cursor for the next page and prompt the user to continue loading after 15 minutes to continue loading.
  • if you want to have a list with more details about a user’s friends, extend the TwitterMentionSuggestionBase class with the matching properties.
  • this code can also be used to determine the followers of a user, you just need to change the url parameters as well as the signature parameters according to the matching Twitter endpoint

As always, I hope this is helpful for some of you. Until the next post, happy coding!

Posted by msicc in Archive, 3 comments

How to use Text to Speech to read text aloud on Windows Phone 8

tts

Today I started to update my very first app I ever wrote to Windows Phone 8. The app has a read aloud feature that uses the Bing translation service (as TTS was not available on Windows Phone 7).

Of course I am now using the new Windows Phone 8 API, but I had some trouble figuring out how to handle text to speech with different languages and if no language speech pack is installed on a device. I finally found a solution and want to share it with you.

First, we need to declare a new SpeechSynthesizer and an  IEnumerable for VoiceInformation:

SpeechSynthesizer speechSynth = new SpeechSynthesizer();
IEnumerable<VoiceInformation> voices = InstalledVoices.All;

Next, I declared a simple helper method to get the currently used language:

         public string GetCurrentCulture()
         {
             return CultureInfo.CurrentCulture.TwoLetterISOLanguageName.ToString();
         }

I am using the TwoLetterISOLanguageName property because there are different versions of some languages like German or English. This makes it easier to handle throughout other methods.

Now that we are able to read the installed voices and to read the currently used language, we can use a simple Linq query to get the speech language we want to use:

var engVoice = from voice in voices where voice.Language.StartsWith("en") select voice;

The engVoice object contains now all English speech packages – if they are installed. To determine if we have items we can use, we just need to check the Count(). As long as the count is bigger than 0, we can start to let our app reading aloud our text. If not, we should inform the user that there is no matching language pack installed.

                 if (engVoice.Count() > 0)
                 {
                     speechSynth.SetVoice(engVoice.ElementAt(0));
                     await speechSynth.SpeakTextAsync(text);
                 }
                 else
                 {
                     MessageBox.Show("Language package missing");
                 }

My app supports three languages. Because of this, I am using if/else if statements to match the languages. If the user uses another language than the supported ones, I am cancelling all speech attempts and display a message to the user which languages are supported.

Here is my complete method:

         private async void StartReadAloud(string text)
         {
             IEnumerable<VoiceInformation> voices = InstalledVoices.All;

             if (GetCurrentCulture() == "en")
             {
                 var engVoice = from voice in voices where voice.Language.StartsWith("en") select voice;
                 if (engVoice.Count() > 0)
                 {
                     speechSynth.SetVoice(engVoice.ElementAt(0));
                     await speechSynth.SpeakTextAsync(text);
                 }
                 else
                 {
                     MessageBox.Show("Language package missing");
                 }
             }
             else if (GetCurrentCulture() == "it")
             {
                 var itVoice = from voice in voices where voice.Language.StartsWith("it") select voice;
                 if (itVoice.Count() > 0)
                 {
                     speechSynth.SetVoice(itVoice.ElementAt(0));
                     await speechSynth.SpeakTextAsync(text);
                 }                                  
                 else
                 {
                     //msgbox Italian
                 }
             }
             else if (GetCurrentCulture() == "de")
             {
                 var deVoice = from voice in voices where voice.Language.StartsWith("de") select voice;
                 if (deVoice.Count() > 0)
                 {
                     speechSynth.SetVoice(deVoice.ElementAt(0));
                     await speechSynth.SpeakTextAsync(text);
                 }
                 else
                 {
                     //msgbox German
                 }
             }
             else
             {
                 speechSynth.CancelAll();
                 //msgbox notSupported language               
             }
         }

I hope this is helpful for some of you and saves you some trouble.If you have anything to add/correct on my method, feel free to leave a comment below.

Happy coding, everyone!

Posted by msicc in Archive, 1 comment

Experiment: using uservoice.com for Support, Feedback and FAQ

On my daily job, I am working as a Mobile Hardware Support Agent of a German  carrier. Because of that, I know how important a good support for customers (=users) is – and also, a little knowledge base where users can find most probably an answer for their  questions.

I want my customers to be satisfied. As an indie developer, I have a little problem: I don’t have a support team that catches all the support questions for me. I need to do this by myself. Until now, I am doing this by using a send-me-a-mail button in my apps. However, due to the fact that I have a 9to5 job and a family besides developing apps, time is a bit limited for me. I searched for some solutions to improve the way I am doing my customer service, and uservoice seems like a good tool to improve my customer service a lot.

As you can see at the feature comparison list of uservoice, the free account already allows you to do a lot of things: https://www.uservoice.com/plans/?ref=top_pricing. It is free for one support agent – perfect for an indie developer like me.

What can you do with uservoice?

uservoice has a lot of features:

  • support ticket system
  • knowledge base
  • feedback system/forum
  • and many more, if you are going for a paid plan

Let’s have a look at the first three features:

Support ticket system

Adding the ticketing system is very easy. You just need a EMailComposeTask pointing to your ticket system. Your standard mail address for that will be: “tickets@<yourname>.uservoice.com”. This is how a received ticket looks like:

Screenshot (289)

Answering to a user is as easy as writing an email – plus you have a ticket history at a glance.

On top of that, you are able to insert a so called ‘canned response’ based on your knowledge base:

Screenshot (290)

Knowledge base

You can build up a knowledge base for your apps.

Screenshot (286)

In the left menu at the bottom at your admin console, you will find the ‘ARTICLES’ section. This is where all the knowledge base articles are collected.

You can create also topics within that KB. I did so for all of my apps:

Screenshot (286)

This way, you can use your free account to support all of your apps with FAQ/KB articles – pretty easy.

Here is how to set up a new article: after clicking on ‘All articles’, there is a ‘New Article’ button on the right side of your screen. Click on that, you will see this on the right hand side:

Screenshot (287)

You can set up the article name, the text and the topic as well as the position you want to show it up in your knowledge base.

You can take a look at my knowledge base here: https://msiccdev.uservoice.com/knowledgebase

How can you use this in your apps? I plan to create an API wrapper for their C# SDK, which is not compatible with Windows Phone at the moment. I will write another blog post for that. Luckily, uservoice as a very nice mobile interface, so you can start off with a simple WebBrowserTask to open your knowledge base:

wp_ss_20140106_0001

Technically, it would be possible to use a WebBrowser control, too. But you would need to code more to get a proper browsing handling.

Feedback system/forum

Some of you might be already familiar with the feedback or idea forum of uservoice (even Microsoft uses this). This time, we look at the other side of the forum, from our admin console:

Screenshot (292)

You have a similar view to what users see, but there are some more parts to control your forum. As a free user, you have only one forum, so it might be useful if you add the app name in front of the title of an idea. You can respond, take notes, and change the status of the ideas:

Screenshot (293)

To integrate the feedback function in your app, you can again use a WebBrowserTask to open the mobile page of your idea forum:

wp_ss_20140106_0002

These are the first simple steps to create your own customer support system with uservoice. Like I said before, I will write a Windows Phone wrapper to get this into an app as native, and will share it here with you all.

Until the next post, happy coding!

Posted by msicc in Archive, 0 comments

The very weird way of checking if Bluetooth or Location is enabled

BT_GPS_WP_Blog

As I am in constant development of new features for my NFC Toolkit, I came to the point where I needed to detect if Bluetooth and Location is enabled or not.

I searched about an hour across the internet, searched all well known WPDev sites as well as the MSDN Windows Phone documentation.

The solution is a very weird one.

As I change the opacitiy of an Image depending on the stauts (on/off), I created the following async Task to check:

private async Task GetBluetoothState()
 {
 PeerFinder.AlternateIdentities["Bluetooth:Paired"] = "";

            try
 {
 var peers = await PeerFinder.FindAllPeersAsync();

                Dispatcher.BeginInvoke(() =>
 {
 BluetoothTileImage.Opacity = 1;
 });
 }
 catch (Exception ex)
 {
 if ((uint)ex.HResult == 0x8007048F)
 {
 Dispatcher.BeginInvoke(() =>
 {
 BluetoothTileImage.Opacity = 0.5;
 });
 }
 }
 }

As you can see above, we are searching for already paired devices with the Proximity API of Windows Phone. If we don’t have any of our already paired devices reachable, and we don’t throw an exception with the HResult of “0x8007048F”, Bluetooth is on. If the exception is raised, Bluetooth is off.

In a very similar way we need to check if the location setting is on:

private async Task GetLocationServicesState()
 {
 Geolocator geolocator = new Geolocator();

try
 {
 Geoposition geoposition = await geolocator.GetGeopositionAsync(
 maximumAge: TimeSpan.FromMinutes(5),
 timeout: TimeSpan.FromSeconds(10)
 );

Dispatcher.BeginInvoke(() =>
 {
 LocationStatusTileImage.Opacity = 1;
 });

}
 catch (Exception ex)
 {
 if ((uint)ex.HResult == 0x80004004)
 {
 Dispatcher.BeginInvoke(() =>
 {
 LocationStatusTileImage.Opacity = 0.5;
 });
 }
 else
 {
 //tbd.
 }

}
}

For the location services, the HResult is “0x80004004”. We are trying to get the actual GeoLocation, and if the exception is thrown, location setting is off.

On Twitter, I got for the later one also another suggestion to detect if the location settings is enabled or not, by Kunal Chowdhury (=>follow him!):

geoLocator.LocationStatus == PositionStatus.Disabled;

This would work technically, but PositionStatus has 6 enumarations. Also, as stated here in the Nokia Developer Wiki, this can be a battery intese call (depends on the implementation). I leave it to you which one you want to use.

Back to the header of this post. Catching an exception to determine the Status of wireless connections just seems wrong to me. I know this is a working “solution” and we can use that. But it could have been better implemented (for example like the networking API).

I hope this post is helpful for some of you.

Until then, happy coding!

Posted by msicc in Archive, 0 comments

How to select an item of (Rad)ListPicker control via speech recognition

This one is a short follow up to my post from yesterday about speech recognition in Windows Phone 8 apps.

I made the first steps with speech recognition in the last few  days with speech recognition, coming to the point where I had to select Items from a (Rad)ListPicker control (tried both, the Windows Phone Toolkit one as well as the Telerik one).

I was then realizing that calling the SelectedItem or the SelectedIndex does not work. By my app’s design the ListPicker has the IsExpanded property set to true, so there was one problem: in this state, it accepts only touch input.

Today I found a quick solution for this problem. If you rely on the input of the ListPicker control, just make sure that its IsExpanded state is false. You then will be able to set the SelectedItem or the SelectedIndex via code.

As always, I hope this will be helpful for some of you.

Happy coding!

Posted by msicc in Archive, 0 comments

Make your app listening to the user’s voice

speech_recognition_WPLogo

In one of my recent projects, I added speech recognition to start the app as well as for using the app. This blog post gives you a short overview on what’s possible and how to do it.

How to start your app with certain conditions:

Any app can be started by the simple voice command “open [AppName]” on Windows Phone. But what if we want to start certain functions when calling our app via speech? Then you’ll need a so called Voice Command Definition (VCD) file. This is a xml file that tells the OS to launch a certain function of your app.

Before we can start, please make sure you enabled ID_CAP_SPEECH_RECOGNITION, ID_CAP_MICROPHONE, and ID_CAP_NETWORKING capabilities in your app manifest.

Let’s have a look at a VCD with two different launch arguments:

<?xml version="1.0" encoding="utf-8"?>

<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.0">
 <CommandSet xml:lang="en-US">
 <CommandPrefix>speech test app</CommandPrefix>
 <Example> speech test app</Example>

<Command Name="open MainPage">
 <Example> open the MainPage </Example>
 <ListenFor> open the MainPage </ListenFor>
 <ListenFor> bring me to Mainpage </ListenFor>
 <ListenFor> let me see my MainPage </ListenFor>
 <Feedback> loading Mainpage....</Feedback>
 <Navigate />
 </Command>

<Command Name="open SettingsPage">
 <Example> open the settings page</Example>
 <ListenFor>open settings</ListenFor>
 <ListenFor>bring me to settings page</ListenFor>
 <ListenFor>let me see my settings page</ListenFor>
 <Feedback>opening settings ...</Feedback>
 <Navigate />

</Command>

</CommandSet>
 </VoiceCommands>

As you can see, the syntax is pretty easy to use. Here is some short explanation about the commands:

  • <CommandPrefix> is for telling the OS how to launch your app
  • <Command Name=”xxx”> is for telling the OS which launch parameter should be passed to your app
  • <ListenFor> defines which speech cases you want to allow to let the OS launch your app (pretty important point)
  • <Example> Text entered here is shown in TellMe’s speech Window and on the “What can I say?” page
  • <Feedback> this is the answer of TellMe to the user

The next part is to load the VCD file once the app starts. Therefore, you will need to add the VCD file in the App constructor. I created an async Task for that:

private async Task InitializeVoiceCommands()
 {
 await VoiceCommandService.InstallCommandSetsFromFileAsync(new Uri("ms-appx:///VoiceCommandDefinitions.xml"));
 }

It is recommended that you set “Copy to Output Directory” property of the VCD file to “Copy if newer”.

Now that we have implemented and loaded our VCD file, let’s have a look on how we can open our app based on the arguments. Based on that VCD file, our app gets key/value pairs of the launch arguments. The implementation is pretty easy in a few lines of code:

if (NavigationContext.QueryString.ContainsKey("voiceCommandName"))
 {
   string voiceCommandName = NavigationContext.QueryString["voiceCommandName"];
   switch (voiceCommandName)
    {
       case "open MainPage":
       //let the App launch normally
       //you can also pass other launcharguments via the VCD file that could launch other functions
       break;

       case "open SettingsPage":
       //let the App lauch immediately to the settings page
       NavigationService.Navigate(new Uri("/SettingsPage.xaml", UriKind.Relative));
       break;
     }
 }

And with this few lines we already added our app with individual voice commands to the speech function of the OS.

 

Using your app with in app voice commands:

We now learned how to start our app with certain conditions. However, this is not how we are using the speech recognition within our app.

There are several ways on how you can implement in app voice commands. I will show you two of them.

First of all, using the Windows button does not work in app. You will need to add a dedicated button to start the voice recognition.

Let’s start with a List<string> or string[] array, and launch the SpeechRecognizerUI:

            try
            {
                //initalize speech recognition
                SpeechRecognizerUI speech = new SpeechRecognizerUI();

                List<string> InAppCommandList = new List<string>
                {
                       "goto home",
                       "goto settings",
                        "set name",
                        "set age",
                        //add more to that list as you need
                };

                //load the List as a Grammar
                speech.Recognizer.Grammars.AddGrammarFromList("InAppCommandList", InAppCommandList);

                //show some examples what the user can say:
                speech.Settings.ExampleText = " goto home, goto settings, set name, set age ";

                //get the result
                SpeechRecognitionUIResult result = await speech.RecognizeWithUIAsync();

                //delegate the results
                switch (result.RecognitionResult.Text)
                {
                    case "goto home":
                        //your code here
                        break;
                    case "goto settings":
                        //your code here
                        break;
                    case "set name":
                        //your code here
                        break;
                    case "set age":
                        //your code here
                        break;
                }
            }
            catch (System.NullReferenceException)
            {
                //do something with the Exception
            }

 

As you can see, there are only a few steps needed:

  • initalize speech recognition
  • load the List<string>/string[] as a Grammar
  • get the result
  • delegate the results

You might have noticed that I wrapped the code into a try/catch block. I needed to do that as I often got a NullReferenceException on closing without voice input or also if no text was heard. This way, your app will not crash.

There is also another way to add a Grammar to the speech recognition engine: SRGS (Speech Recognition Grammar Specification), which is again a XML file that contains which input is accepted.

While I was working on this app, I noticed that it is pretty powerful – and complex. This is why I decided to mix both methods to get things done (you know, timelines and such). I will dive into that topic deeper and then write another blog post about it. But for now, I’ll show you a simple example.

In this case, I wanted the SpeechRecognizerUI to only accept numbers as input. This is how my SRGS file looks like:

<?xml version="1.0" encoding="utf-8" ?>

<grammar version="1.0" xml:lang="en-US" root="Command" tag-format="semantics/1.0"
 xmlns="http://www.w3.org/2001/06/grammar"
 xmlns:sapi="http://schemas.microsoft.com/Speech/2002/06/SRGSExtensions">

<rule id="Command" scope="public">
 <item repeat="1-20">
 <ruleref uri="#Numbers"/>
 </item>
 </rule>

<rule id="Numbers">
 <one-of>
 <item >1</item>
 <item >2</item>
 <item >3</item>
 <item >4</item>
 <item >5</item>
 <item >6</item>
 <item >7</item>
 <item >8</item>
 <item >9</item>
 <item >0</item>
 </one-of>
 </rule>

</grammar>

If you add a SRGS file as to your project, the correct structure is already implemented. You only need to set the root to the first rule you want to be executed. In my case, I defined a rule with the id Command in a public scope (this way, you would also be able to call it from another Grammar).

The rule returns items that will occur minimum 1 time and maximum 20 times. Basically, this defines the range of the input length.

To make the SpeechRecognitionUI only accepting numbers, I defined another rule that contains a list of numbers. the <one-of> property defines here that any of the numbers is accepted. With <ruleref uri=”#Numbers”/> I am telling my app to accept any of the numbers as often as they occur until the count of 20.

Now let’s have a look on how to implement this Grammar into our app and connect it to our SpeechRecognizerUI:

 SpeechRecognizerUI speech = new SpeechRecognizerUI();

            //generate a Numberonly Input Scope based on a SRGS file
            //the ms-appx:/// prefix will not work here and return a FileNotFoundException!
            Uri NumberGrammarUriPath = new Uri("file://" + Windows.ApplicationModel.Package.Current.InstalledLocation.Path + @"/NumberOnlyGrammar.xml", UriKind.RelativeOrAbsolute);

            speech.Recognizer.Grammars.AddGrammarFromUri("NumberGrammarUriPath", NumberGrammarUriPath);

            SpeechRecognitionUIResult speechRecognitionResult = await speech.RecognizeWithUIAsync();

            if (speechRecognitionResult.ResultStatus == SpeechRecognitionUIStatus.Succeeded)
            {
                //using Regex to remove all whitespaces
                string NumberInputString = Regex.Replace(speechRecognitionResult.RecognitionResult.Text, @"\s+", "");
                // do somethin with the string
            }

We are again calling the SpeechRecognizerUI, but this time we are loading our XML formatted SRGS file as Grammar. Notice that loading the file only works with the way above. Using the “ms-appx:///” prefix will return a FileNotFoundException and crash your app.

Instead of AddGrammarFromList we are using AddGrammarFromUri to load the file.

By checking the SpeechRecognitionUIStatus, we are performing actions only if the recognition was succesful based on our SRGS Grammar. If you want to perform other actions on non-success status, you will be able to implement the following enumerations:

  • Succeeded (0)
  • Busy (1)
  • Cancelled (2)
  • Preempted (3)
  • PrivacyPolicyDeclined (4)

As you can see, basic speech recognition is fast to implement. As always, I hope this post is helpful for some of you.

I also recommend to read these pages on MSDN about speech for Windows Phone: http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj207021(v=vs.105).aspx

Happy coding everyone!

Posted by msicc in Archive, 1 comment

Announcement: beta test for NFC Toolkit

 wp_ss_20130201_0002

NFC Toolkit, my latest app project, is ready for a first beta look.

If you want to take part in this beta, please consider following points before applying:

  • You need a WP8 device with NFC
  • You will need NFC tags for now, as communication between devices is still in development
  • You are willing to give serious feedback to improve the app

This will be a long time beta, means that even if the app goes live for all customers, I will continue developing with this beta before launching new versions. If you join the beta, you can use and test all new features before all others.

NFC Toolkit aims at normal users, that don’t need all to technical information but want to use NFC.

The beta has following features at the moment:

  • basic tag reading
  • tag writing of most commonly used tag scenarios
  • profiles! This is one of the main features of NFC Toolkit. It is all about settings based on a NFC tag.
  • more unique features to come!

Send your MS Account via mail, if you want to participate in beta testing this all new Windows Phone 8 app.

 

Posted by msicc in Archive, 0 comments

Application ID’s of built in Windows Phone 8 apps

 

As you may have noticed, I am currently working on an NFC app. Development goes pretty well at the moment, thanks to the absolutely awesome and easy to use NDEF library by Andreas Jakl.

If you want to open apps from your app or from an NFC tag, you will need to use the AppId of the desired app. If you have an installed app from the Windows Phone Store, this is pretty easy. You can go to the application list on your phone, long tap and hit “send”. If you now choose mail or SMS, you can obtain the AppId very easy, as it is the last part behind “appId=” on the web address.

With the built in apps, it is a bit more difficult. Luckily, the app NFC interactor for Windows Phone 8, which is aimed at developers, has a solution. The app is written also by Andreas Jakl, who provides a huge tool with this app to support you on developing your own app and it is worth every cent.

I made it through all records for built in apps and extracted the following list, which might come handy for some of you:

  • Alarms AppId 5B04B775-356B-4AA0-AAF8-6491FFEA560A
  • Bing Scan AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5682
  • Calculator AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5603
  • Calendar AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5612
  • Camera AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5631
  • Data Sense AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5646
  • Games AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5634
  • Help+Tips AppId E05410F1-753B-47BC-B101-226E5802B9E1
  • IE AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5660
  • Maps AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5661
  • Messaging AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5610
  • Music+Videos AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5630
  • Office AppId 5B04B775-356B-4AA0-AAF8-6491FFEA561E
  • OneNote AppId 5B04B775-356B-4AA0-AAF8-6491FFEA561B
  • People AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5615
  • Phone AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5611
  • Photos AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5632
  • Rooms AppId 5B04B775-356B-4AA0-AAF8-6491FFEA562D
  • SIM Applications AppId 5B04B775-356B-4AA0-AAF8-6491FFEA562C
  • Start (Home Screen) AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5602
  • Store AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5633
  • Wallet AppId 5B04B775-356B-4AA0-AAF8-6491FFEA5683

All credits for this App IDs goes to Andreas Jakl, I only put them together as a list to find them more easily.

Posted by msicc in Archive, 4 comments