Mittwoch, 19. Dezember 2012

Windows Phone 8 Using SQLite

After using a flat file to persists my local data within my WorkTime app and sync them to SkyDrive I asked myself: Why not using a local database to store the data?

So what the database systems that will be supported by Windows Phone 8:

(1) With Windows Phone 7.5 (Mango) Microsoft has introduced an old technology with a new database access layer. SQL CE as database engine and LINQ to SQL to manipulate and define tables using classes.

(2) At the Build Microsoft introduces a new solution for Windows Phone 8: SQLite. That the right decision, because with SQLite you have the chance to share your local application data across several platforms Windows Phone 8, Windows 8, Android and iOS. Microsoft has worked with the SQLite team to provide an easy way to add SQLite to our Windows 8 and Windows Phone 8 projects. The result are two extensions in the  Visual Studio Gallery. One to support Windows 8 projects and an other one to use with Windows Phone 8.

Writing native code for Windows Phone 8?

But what his? These extensions are only the SQLite database engine and written in native code.To use them you have to write native code to interact with the SQLite database engine and perform operations with the database. So what to do: Searching a library which supports a wrapper that you can use C# to use the SQLite database engine.

Peter Torr – who introduces SQLite at the Build - actual posts about the current development process for such an wrapper from Microsoft: http://blogs.msdn.com/b/ptorr/archive/2012/11/27/update-on-sample-code.aspx – so we have to wait for the demoed solution from Microsoft.

So Microsoft gives us a new SQLite database engine but unfortunately no wrapper library to access this by C#.

What’s about csharp-sqlite?

csharp-sqlite is published on Google Code that allows to use the native SQLite engine directly in a C# application. I have worked with this library already on Windows Phone 7 and the library works fine with Windows Phone 8 and can be used as it is.

But if you want to use the same data access layer within Windows Phone 8 and Windows 8 (which should be the main goal for developing apps for these platforms)? The solution: Usage of a additional library sqlite-net which could be found and installed via Nuget:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="sqlite-net" version="1.0.5" targetFramework="wp80" />
</packages>

Sqlite-net works for my Windows 8 and my Windows Phone 8 test projects and capsulated the data access in a very nice way.

The data class:

public class Contact
    {
        [PrimaryKey]
        public string UnqiqueId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

The CRUD methods:

public async Task CreateContactAsync(Contact contact)
{
    var conn = GetConnection();
    await conn.InsertAsync(contact);
}
 
public async Task UpdateContactAsync(Contact contact)
{
    var conn = GetConnection();
    var existingContact = await conn.FindAsync<Contact>(c => c.UnqiqueId == contact.UnqiqueId);
    if (existingContact != null)
    {
        await conn.UpdateAsync(contact);
    }
}
 
public async Task DeleteContactAsync(Contact contact)
{
    var conn = GetConnection();
    await conn.DeleteAsync(contact);
}
 
private SQLiteAsyncConnection GetConnection()
{
    return new SQLiteAsyncConnection("contacts");
}

Some helper methods:

private async void CreateTableAsync<T>() where T : new()
{
    var conn = GetConnection();
    await conn.CreateTableAsync<T>();
}
 
private bool ExistsTable<T>()
{
    var connStr = new SQLiteConnectionString("contacts", false);
    using (var conn = new SQLiteConnection(connStr.DatabasePath))
    {
        var command = new SQLiteCommand(conn)
        {
            CommandText =
                "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='" +
                typeof(T).Name + "'"
        };
        return (command.ExecuteScalar<int>() > 0);
    }
}

 

So in case you are developing a Windows Phone application and you need to use a database, which are the possible solutions?

 

What database solutions for Windows Phone 8?

The first one I mentioned above: still keep using the old SQL CE which works just fine in Windows Phone 8. But then your database could not be used by other apps from different platforms.

A alternative approach is to use SQLIte and the csharp-sqlite library. Together with sqlite-net you can implement the same data access layer for Windows 8 and Windows Phone 8 by changing the underlying SQLite database engine for both platforms.

Sonntag, 16. Dezember 2012

Windows Phone 8–Speech Recognition problem Can’t access network

In my current Windows Phone 8 project WorkTime I used the very nice new feature of the Windows Phone 8 speech recognition Api. With Windows Phone 7 you have to handle with the Bing translation services, but now you have a capsulated API in the Windows.Phone.Speech.Recognition namespace. Here is a sample code which uses the default Dictation grammar for Recognition. It is also possible to define your own grammar (expected words) by code or using a SRGS grammar file.

W3C Standard definition: http://www.w3.org/TR/speech-grammar/

Microsoft MSDN documentation: http://msdn.microsoft.com/en-us/library/hh361633(v=office.14).aspx

SpeechRecognizerUI speechRecognizer;
 
public TimeSheetEntryPage()
{
    InitializeComponent();
 
    this.BindingValidationError += TimeSheetEntryPageBindingValidationError;
 
    this.speechRecognizer = new SpeechRecognizerUI();
 
}
 
void TimeSheetEntryPageBindingValidationError(object sender, ValidationErrorEventArgs e)
{
    this.HandleBindingValidationError(sender, e);
}
 
#region Events
 
private void PhoneApplicationPage_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
{
    var vm = DataContext as TimeSheetEntryDetailViewModel;
    if (vm != null)
    {
        vm.GoBackCommand.Execute(null);
    }
}    
 
#endregion
 
private async void Search_ActionIconTapped(object sender, EventArgs e)
{
    this.speechRecognizer.Recognizer.Grammars.Clear();
 
    // Use the short message dictation grammar with the speech recognizer.
    speechRecognizer.Recognizer.Grammars.AddGrammarFromPredefinedType("message", SpeechPredefinedGrammar.Dictation);
 
    await speechRecognizer.Recognizer.PreloadGrammarsAsync();
 
    var sr = new SpeechRecognizerUI();
    sr.Settings.ListenText = AppResources.VoiceListenTextDescription;
    sr.Settings.ReadoutEnabled = true;
    sr.Settings.ShowConfirmation = true;
 
    try
    {
        // Use the built-in UI to prompt the user and get the result.
        SpeechRecognitionUIResult recognitionResult = await sr.RecognizeWithUIAsync();
 
        if (recognitionResult.ResultStatus == SpeechRecognitionUIStatus.Succeeded)
        {
            // Output the speech recognition result.
            DescriptionTextBox.Text = recognitionResult.RecognitionResult.Text;
        }
    }
    catch (Exception ex)
    {
        //TODO change
        MessageBox.Show(ex.Message);
    }
}

But there is an issue with the Speech recognition API, if you localize the app title with a C++ resource-only DLL.

WindowsPhoneSpeechRecognition

If you use this way of localization for your app title you get an error message from the Speech Recognition API “We're sorry, but we can't access the network right now” ?!? (costs me several hours to find out this correlation)

But if you remove the reference to the AppResLib.dll it works properly.

Windows Phone 8: Voice command support

I really love it, if the implementation of rich user functions is easy – and the addition of voice command support for a Windows Phone 8 app is very easy.

With Windows Phone 8 you can add additional startup commands for your app which can be used to deep link in your app functions (see details here: http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj206959(v=vs.105).aspx)

In my WorkTime app I want to have a new voice command “WorkTime add entry”.

What are the necessary steps?

Adding a new Voice Command Definition file to the project. I used two CommandSets for each supported language.

<?xml version="1.0" encoding="utf-8"?>
 
<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.0">
  <CommandSet xml:lang="de">
    <CommandPrefix>WorkTime</CommandPrefix>
    <Example> neuer Eintrag </Example>
 
    <Command Name="NewEntry">
      <Example> neuer Eintrag </Example>
      <ListenFor> neu </ListenFor>
      <ListenFor> [ein] neuer Eintrag </ListenFor>
      <ListenFor> [und] [ein] neuer Eintrag </ListenFor>
      <Feedback> WorkTime erzeugt einen neuen Eintrag... </Feedback>
      <Navigate Target="/MainPage.xaml" />
    </Command>
 
  </CommandSet>
  <CommandSet xml:lang="en-US">
    <CommandPrefix>WorkTime</CommandPrefix>
    <Example> new entry </Example>
 
    <Command Name="NewEntry">
      <Example> new entry </Example>
      <ListenFor> new </ListenFor>
      <ListenFor> [a] new entry </ListenFor>
      <ListenFor> [and] [a] new entry </ListenFor>
      <Feedback> WorkTime creating a new entry... </Feedback>
      <Navigate Target="/MainPage.xaml" />
    </Command>
 
  </CommandSet>
</VoiceCommands>

After that you have to enable the following capabilities in the AppManifest.xml

<Capabilities>
     <Capability Name="ID_CAP_NETWORKING" />
     <Capability Name="ID_CAP_MICROPHONE" />
     <Capability Name="ID_CAP_SPEECH_RECOGNITION" />
   </Capabilities>

In the constructor of the App or your start page it is necessary to tell Windows Phone that your app supports new voice commands, which are defined in your added Voice Command Definition file (VoiceCommandDefinitionWorkTime.xml in my case)

public App()
   {
       // Global handler for uncaught exceptions.
       UnhandledException += Application_UnhandledException;
 
       // Standard XAML initialization
       InitializeComponent();
 
       // Phone-specific initialization
       InitializePhoneApplication();
 
       // Language display initialization
       InitializeLanguage();
 
       // Add voice command support
       InitalizeVoiceCommands();
 
       //Readies the DispatcherHelper for usage throughout application
       DispatcherHelper.Initialize();
private async Task InitalizeVoiceCommands()
{
    //VoiceCommandService.InstalledCommandSets.ContainsKey("en-US")
    await
        VoiceCommandService.InstallCommandSetsFromFileAsync(
            new Uri("ms-appx:///VoiceCommandDefinitionWorkTime.xml"));
}

The last step is to check on the start page or your target page (see Voice Command Definition file) if the user starts the app by this command. You can do this by overriding the OnNavigatedTo event:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);
 
    if (e.NavigationMode == NavigationMode.New)
    {
        if (NavigationContext.QueryString.ContainsKey("voiceCommandName"))
        {
            var command = NavigationContext.QueryString["voiceCommandName"];
 
            if (command == "NewEntry")
            {
                var vm = this.DataContext as MainViewModel;
                if (vm != null)
                {
                    vm.AddCommand.Execute(null);
                }
            }
        }
    }
}

The result is that your app will now support a command “NewEntry” which will be executed if the user presses the Windows button for a few seconds and speaks:

“WorkTime add new entry” or “WorkTime new” or “WorkTime add a new entry”

wp_ss_20121216_0001