Pierre's Embedded and Mobile Blog

Soulevons le capot des systèmes embarqués et mobiles

Posts
  • Pierre's Embedded and Mobile Blog

    Update de l’AppHub Windows Phone 7: béta et distribution privée, nouveau SDK pub, nouveau dashboard….

    • 4 Comments

    Aujourd’hui se lance la version améliorée de l’AppHub, le dashboard développeur qui permet de publier une application sur le Marketplace Windows Phone 7… et c’est une sacrée update! De très nombreux feedbacks de notre communauté ont été intégrés, et la liste des nouveautés est impressionnante:

    Nouveaux modèles de distribution d’application: béta privée, et distribution cachée

    “Je veux pouvoir faire tester mon application avant de la publier!”

    Il est maintenant possible de proposer une beta à des utilisateurs en indiquant leur live ID dans le dashboard, sans passer de certification, et sans débloquer leur téléphone: ils recevront un email, et pourront télécharger l’application et l’utiliser pendant 90 jours. Limitée à 100 utilisateurs, forcément gratuite, et sans mécanisme d’update (i.e.. nouvelle version == nouvelle beta).

    “Je veux pouvoir distribuer mon application sans qu’elle soit visible!” ou bien “je veux un marketplace privé!”

    Pour ceux qui veulent déployer leur application en privé, il est aussi possible, après certification, de ne pas publier l’application mais obtenir un lien privé, sans contrôle d’accès: à vous de voir ensuite comment vous distribuez votre lien, et faites votre sécurité dans l’application! pas de limite en nombre d’utilisateurs ou en durée d’utilisation, et la possibilité d’utiliser le système d’updates pour pousser les nouvelles versions. il est aussi possible de passer l’application en distribution publique plus tard, et même de choisir si elle sera gratuite ou payante!

    Processus d’inscription simplifié pour les développeurs indépendants et les étudiants

    “J’en peux plus de Geotrust, ça fait 3 semaines que j’essaye d’ouvrir un compte pour débloquer mon téléphone!”

    Pour la catégorie Individual, une simple carte de crédit valide (qu’on rentre de toutes façons au moment de payer l’abonnement) suffit pour valider le compte, plus besoin de passer par le processus Geotrust. Pour les étudiants, le compte sera validé par dreamspark, et l’âge vérifié avec le Live ID, plus besoin de publier une première application, pour que le compte soit validé.

    Inscription, soumission d’apps, reporting… un dashboard beaucoup plus clair, avec des informations plus pertinentes

    “Je veux comprendre ce qui se passe avec mes applications!”

    Toutes les parties du dashboard Marketplace ont été grandement améliorées: le processus d’inscription est plus simple, plus pertinent (par exemple, on ne demande plus de remplir les informations bancaires pour les gens qui publient des applications gratuites). Le processus de soumission aussi bénéficie d’améliorations (le statut de certification est plus explicite par exemple). Enfin le reporting aussi est amélioré: daily downloads, crash counts, graphes consolidés de downloads, et surtout possibilité de les exporter..

    Le SDK de pub Microsoft Advertising bientôt disponible dans plus de pays, notamment la France!

    “Je veux pouvoir intégrer de la pub dans mon application et toucher des sous-sous!”

    Disponible auparavant uniquement aux états-unis, on pourra bientôt intégrer le SDK “officiel” de pub in-app de Microsoft dans les applications, notamment en Europe et en Asie… Vous retrouverez à l’occasion un article sur ce blog pour vous en parler!

    Plus de pays pour soumettre des applications, et pour les distribuer!

    “Je veux que mon application soit visible par le monde entier!”

    Une amélioration sensible pour tous ceux qui publient une application à vocation internationale: vous allez maintenant pouvoir régionaliser votre application pour 19 pays de plus (incluant le Brésil, l’Argentine et la Colombie, l’Inde, l’Afrique du Sud, certains pays d’Europe de l’Est dont la Pologne, la Russie…) et publier votre application depuis 9 pays de plus (dont la Chine, l’Inde, l’Afrique du Sud…). Enfin le global publisher program continue d’être disponible pour tous les pays qui ne sont pas encore listés dans ces listes…

    Soumission d’applications pour Mango dès le mois prochain!

    “Mon application est prête je veux pouvoir la distribuer aux gens qui ont déjà installé Mango!”

    Patience, ça arrive! une version RC des outils devrait arriver d’ici la fin Août et avec ça la possibilité de soumettre des applications sur Marketplace directement à destination des terminaux Mango!

    Toutes ces nouveautés sont également détaillées sur le blog officiel des développeurs Windows Phone 7.

  • Pierre's Embedded and Mobile Blog

    [Windows Phone] le SDK Windows Phone 7.1 est disponible en version finale (RTW) et en français

    • 3 Comments

    wp7sdk71rtwC’est encore une annonce sur le blog développeurs Windows Phone 7 qui nous l’apprend, le SDK Windows Phone 7.1 (pour Mango) est arrivé en version finale (RTW: Release To Web). Il est disponible en version multilingue, c’est à dire que vous pouvez l’installer en Français! Il vous suffit de choisir votre langage dans la liste déroulante sur la page de téléchargement.

    Quelques points qui me paraissent intéressants à souligner:

    • Le nouvel émulateur dispose d’outils pour simuler le GPS (depuis une carte Bing) et l’accéléromètre (dans une vue 3D). Il intègre aussi le navigateur IE9 pour Windows Phone 7 qui supporte le HTML5 et vous permet de tester le rendu de votre site web.
    • Un outil de profiling a été inclus, pour mesurer les performances CPU et mémoire de vos apps (et éventuellement trouver des bugs!)
    • Un marketplace test kit qui vous permet de simuler chez vous les tests automatisés de la certification
    • Le contrôle pub de Microsoft Advertising, disponible maintenant en France! Mais ça ne doit pas vous encourager à mettre de la pub dans vos applications Tire la langue

    Pour ce qui est du processus de mise à jour…

    • Si vous avez le SDK 7.0 alors vous pouvez directement installer le 7.1 sans désinstaller les outils précédents.
    • Si vous avez le SDK 7.1 en version RC ou Beta, il faudra le désinstaller avant.

    Par ailleurs, le déploiement de la mise à jour Mango est en cours depuis hier! vos utilisateurs vont donc s’attendre à trouver une version de votre application pour Mango Sourire C’est le moment de soumettre vos mises à jours!

    Pour l’instant, la dernière version 7.0 restera disponible pour les terminaux 7.0 et vos mises à jours avec le SDK 7.1 seront déployées sur les terminaux Mango. D’ici la fin octobre on vous offrira un contrôle encore plus fin de vos mises à jours et vous pourrez faire évoluer en parallèle la branche 7.0 et la branche 7.1. il n’y a donc plus aucune raison d’attendre pour mettre vos applications à jour!

    Happy updating!

  • Pierre's Embedded and Mobile Blog

    [La question qui tue] Portabilité des applications métier de Windows Mobile 6.5 vers Windows Phone 7

    • 12 Comments

    “Je suis un pro, j’ai fait le choix de Windows Mobile il y a des années, je vois plein de buzz positif autour de Windows Phone 7 mais il parait que la compatibilité n’est pas assurée… Or j’ai des collaborateurs avec des applications d’entreprise, comment je fais ?”

    Mauvaise nouvelle, il n’y a pas de réponse simple. Ce n'’est pas si grave que ça non plus, parce qu’il y a quand même toujours une réponse :) Chaque cas étant particulier c’est difficile de faire des généralités pertinentes, mais on va essayer quand même de se faire une opinion et de “dégrossir” le terrain. En tous cas, On va lister quelles questions et avec quelles informations appeler votre serviteur pour trancher sur une potentielle migration de Windows Mobile 6.x vers Windows Phone 7.

    L’usage: terminal durci ou pas?

    D’abord si vous faites dans les terminaux durcis… Windows Phone 7 ne devrait pas être dans vos plans. Je ne dis pas que ça n’arrivera jamais (qui sait de quoi le futur est fait…) mais ce n’est pas pour ce type de terminaux que cet OS a été pensé. Windows Phone 7 est avant tout grand public, et l’OS, le SDK, les applications et le mode de déploiement des applications ont été pensées avec le grand public en tête. En plus les spécifications matérielles minimales de Windows Phone 7 sont souvent incompatible avec le milieu durci (écran capacitif obligatoire par exemple).

    Ceci étant dit, il existe tout une population “d’information worker” qui utilisent un terminal grand public pour des taches métiers: commerciaux ou agents de terrain avec une application de CRM, chauffeurs, etc. Sans compter la volonté pour un certain nombre d’entreprises de faire une application “intranet” ou “note de frais”. Toutes ces populations pourraient être concernées par des applications métier sur un smartphone sexy avec Windows Phone 7. Ca vaut vraiment le coup de se poser la question. Ou plutôt les questions, car il n’y en a pas qu’une… et tant qu’à faire autant commencer par la question la plus épineuse: le déploiement de l’application en question sur les terminaux.

    Le déploiement passe obligatoirement par le Marketplace public

    C’est le point sensible. Autant on pourra quasiment toujours contourner une difficulté technique, autant, celle là, ce n’est pas possible. Votre application sera visible par tout le monde. Voire, téléchargeable part tout le monde (à condition d’y mettre le prix que vous fixerez). Ca peut être un showstopper, comme une grande force: après tout, un simple système d’authentification peut vous permettre de protéger votre application tout en garantissant que vous êtes visible sur le Marketplace: prenons un exemple simple: vous avez une application “note de frais” qui est customizable par chaque client: la configuration du client lui est propre et ne doit pas forcément se trouver sur Marketplace. Quelqu’un d’anonyme qui téléchargerait l’application pourrait la voir en mode “restreint” et avoir l’option de vous contacter pour en savoir plus: Marketplace devient alors un vecteur de publicité et de leads. Dans le même genre d’optique, vous pouvez aussi utiliser l’authentification pour débloquer par exemple l’accès à des services spéciaux (internes par exemple) et sans authentification proposer à vos clients une application publique qui pourrait leur servir indépendamment de votre backend.

    Si votre application est faite par l’interne, pour l’interne, le cas est plus délicat: quoiqu’il en soit Microsoft étudie toutes les possibilités pour offrir aux entreprises la possibilité de déployer leur application sans passer par les moyens du grand public et saura revenir, on l’espère le plus vite possible, avec des propositions: dans tous les cas, ce n’est pas encore annoncé, et donc pas encore roadmapé…

    La technologie / Les fonctionnalités

    Une fois l’écueil “publication sur Marketplace” passé, reste à savoir si vous pouvez implémenter votre application sur Windows Phone 7 et combien ça va vous coûter.

    Tout a changé avec Windows Phone 7: l’OS, mais aussi le SDK, et le modèle applicatif. Pour de plus amples informations, je vous conseille l’article Comprendre la plateforme Windows Phone 7 sur MSDN. Du coup, il n’y a pas de compatibilité binaire entre Windows Phone 7 et les versions précédentes de l’OS ou entre le kit de développement Windows Phone 7 et les kits de développement précédents. D’une manière ou d’une autre il faudra réécrire l’application. Toute? Pas forcément… tout dépend de votre technologie de départ et de la modularité de votre code. Si vous avez opté pour le Compact Framework par le passé, alors il y a de fortes chances que vous puissiez réutiliser vos couches métiers, même s’il faudra vraisemblablement revoir la partie réseau. En ce qui concerne la couche de présentation en revanche, elle est à oublier, il faudra tout refaire avec Silverlight. Si vous aviez opté pour des technologies natives (C/C++, Win32, MFC…) alors il faudra tout bonnement tout réécrire.

    Une fois la décision sur la réécriture/portage validée, il faudra s’intéresser aux fonctionnalités du SDK. La bonne nouvelle est qu’il y a 98% de chances qu’il soit possible d’écrire une application iso-fonctionnelle à l’ancienne, même s’il faudra surement utiliser quelques ressources de la communauté, et peut-être un peu de malice. En effet, sans background processing par exemple il faudra peut-être recourir à un service online et des notifications en push pour provoquer des synchronisations de données par exemple . Un autre exemple, s’il y a besoin d’une base de donnée locale, Microsoft n’a pas encore porté SQL CE sur Windows Phone 7, mais SQLite existe déjà dans la communauté. Du coup, il est fort probable que votre application puisse, moyennant un peu d’adaptation, être portée. En revanche, il faut rester honnête, certain scénarios vont être impossible à implémenter pour le moment : par exemple le suivi de véhicule avec une application tournant en background dans le téléphone et uploadant régulièrement sa position GPS (il faudrait que l’application soit affichée à l’écran pour que cela marche), ou alors l’accès aux couches basses ou aux API de l’OS comme l’interfaçage avec un équipement particulier qui requiert l’accès à un port série et une pile Bluetooth.

    Après cette longue lecture, vous devriez avoir une idée un peu plus claire mais pas forcément très positive de l’idée du portage de votre application: cela représente de toutes façons pas mal de travail. Mais ce travail peut en valoir la peine. Windows Phone 7 marque une nouvelle page de l’histoire des smartphones avec une ergonomie différente centrée sur l’utilisateur. A vous de voir en fonction des usages, des besoins de vos collaborateurs et de l’image que vous voulez véhiculer. Les points bloquants mentionnés tout au long de cet article sont-ils réellement bloquants? ils ne l’ont pas forcément été pour d’autres! Dans tous les cas, toute l’équipe mobile chez Microsoft saura répondre aux questions et dissiper les doutes éventuels. Cet article n’est là que pour expliquer la base, car encore une fois il est impossible de faire des généralités sur les applications métiers… Alors contactez-nous!!

  • Pierre's Embedded and Mobile Blog

    [Breaking News] Un nouveau SDK pour Windows Mobile 6.5 avec de nouveaux templates et contrôles riches

    • 3 Comments

    newSDK65

    Avec les rumeurs qui vont bon train sur la prochaine version majeure de Windows Mobile, on en oublie qu’il y a une plateforme sur le marché qui marche déjà et qui a sa communauté de développeurs. Une communauté qui attendait pas mal de choses comme par exemple des templates et un environnement de développement sérieux pour les widgets, ou bien encore, un contrôle de cartographie riche.

    Que cette communauté se réjouisse, le SDK nouveau est arrivé! Courez le télécharger ainsi que les dernières images localisées des émulateurs, qui vous réservent bien des surprises !

    SDK Windows Mobile 6.5 et les images des émulateurs localisés

    [edit] Le lien semble avoir retiré. l’investigation est en cours… :)

  • Pierre's Embedded and Mobile Blog

    Pratique: Partager la connexion réseau de son PC sous Windows 7 avec l’émulateur Windows Mobile

    • 2 Comments

    Ceux d’entre vous qui ont eu la bonne idée de passer sous Windows 7 (ou de tester la RC, ou autre) ont peut-être eu la désagréable impression qu’on venait de casser quelque chose avec l’émulateur… le partage de connexion réseau. Pourquoi? parce qu’avec XP et Vista, c’était facile, il suffisait d’installer le driver de Virtual PC 2007 (c’est ce qui était suggéré, et c’était très facile). Oui mais voila, avec Windows 7, Virtual PC est intégré et donc il est impossible d’installer Virtual PC 2007, et donc son driver réseau. Deadlock, plus possible de partager sa connexion… Heureusement, un gars futé du nom de Brian Peek a trouvé la solution: Pour faire simple: on installe “manuellement” le driver manquant en l’extrayant de l’installer de Virtual PC 2007 SP1. Ce post est une traduction approximative de son post original

    • Téléchargez Virtual PC 2007 SP1
    • renommez l’exécutable, par exemple en “vpc.exe”
    • Dans une ligne de commande (Démarrer –> tapez “cmd” puis Entrée), il faut taper les commandes suivantes:
      • vpc.exe /c
      • cd %temp%
      • msiexec /a Virtual_PC_2007_Install.msi /qb TARGETDIR=c:\vpc
    • Ce qui consiste à extraire le msi (l’installeur) du setup.exe, puis décompresser les fichiers contenu dans ce .msi vers C:\vpc
    • Ensuite, il faut aller rajouter ce driver sous forme de service dans les propriétés de la carte réseau dont on veut partager la connexion:
      • Dans le “Network and Sharing Center” (Centre Réseau et Partage):
        • Cliquer sur “Change Adapter Settings” (Modifier les paramètres de la carte)

    adapter

        • Puis sélectionner la connexion qu’on veut partager, click droit –> Properties (Propriétés)

    install

        • Cliquer ensuite sur “Install…” (Installer…), puis sélectionner Service cliquez sur “Add” (Ajouter) , “Have Disk…” (Disque fourni…)

    type

    disk

        • Naviguer vers le dossier C:\vpc\Program Files\Microsoft Virtual PC\Utility\VMNetSrv\ (et x64 pour les machines 64 bits)
        • Sélectionner “Virtual Machine Network Services” Puis OK

    vmns

    • Et voila! maintenant, il est possible de partager sa connexion réseau, plus de message d’erreur!

    Encore merci à Brian pour ce tip bien utile!

  • Pierre's Embedded and Mobile Blog

    Prototyping a connected object using the .NET Gadgeteer: the example of a steampunk meteo station

    • 2 Comments

    clip_image002[6]

    For years I’ve had this very old voltmeter I wanted to do something with: I liked the beautiful wooden case, the leather strap, but honestly, I had better tools for my day to day electronics experiments. I found a purpose for it when I started experimenting with the .NET Gadgeteer kit, and one of my first prototype of connected object: a simple meteo station that would measure temperature, humidity and pressure and upload data to a feed in Cosm, formerly known as Pachube, which is a connected objects web platform used to publish and consume realtime data. I had two goals with this project: have fun with the .NET Gadgeteer kits, and experiment on a complete connected object prototyping cycle (I’m not going to talk about industrialization or mass production here).

    Here’s the plan:

    1. Discovering the .NET Gadgeteer tooling, and interfacing with sensors
    2. Connecting to Cosm (Pachube)
    3. Creating the steampunk GUI
    4. Making the meteo station user-configurable using a small webserver
    5. Prototyping the finished design using 3D modeling tools

     

    >> If you want to download the whole article in a Word document, here’s the link. <<

    Discovering the .NET Gadgeteer tooling, and interfacing with sensors

    The .NET Gadgeteer is a rapid prototyping environment for connected objects. Kits are manufactured by Microsoft partners, like GHI Electronics (http://www.ghielectronics.com), Seed Studio (http://www.seeedstudio.com/depot/), or the Mountaineer Group (http://www.mountaineer.org/). The core libraries (based on the .NET Micro Framework: (http://www.netmf.com)) are maintained by Microsoft and the community, while the hardware specific drivers and updaters are maintained by the different partner.

    Therefore, there are 3 different packages to install on top of Visual Studio 2010 (any version, Express will do) to install the .NET Gadgeteer tools: the .NET Micro Framework base, the Gadgeteer Core, and the hardware specific SDK. In our case, we are going to use a FEZ Spider Kit from GHI Electronics as well as a couple of sensors and a Wifi module.

    Once you have installed everything, you can create your first .NET Gadgeteer application. You are then presented with a “designer” view of your project: at this time there’s only one motherboard in the designer. Using the toolbox, you can add the modules you are going to use. Once you have all the modules you need, you can either click on the connectors to wire them manually or right-click anywhere on the designer and select “Connect all modules”. If you don’t know anything about hardware, this will show you how to connect modules to the motherboard. Once this is done, you’re ready to start coding!

    clip_image004[6]

    Click on Program.cs to dive into the source code. At this point there’s only the main entry point, and a debug instruction. However all the objects needed to control the hardware have already been instantiated (in the Program.Generated.Cs file) and can be used right away. For example, if you have a temperature sensor, you can directly subscribe to the MeasurementComplete event, that will fire whenever a new measure is ready.

    In our case, we are going to use a timer to regularly measure the meteorological parameters (temperature, pressure, and humidity). Everytime the timer fires, we will ask the different sensors to start measuring and they will notify us through their respective MeasurementComplete event that a new measure is ready.

    First register for sensor events:

    temperatureHumidity.MeasurementComplete += new TemperatureHumidity.MeasurementCompleteEventHandler(temperatureHumidity_MeasurementComplete);
    barometer.MeasurementComplete += new Barometer.MeasurementCompleteEventHandler(barometer_MeasurementComplete);

     

    Then instantiate the timer and start it:

    GT.Timer SensorTimer = new GT.Timer(TimeSpan.FromTicks(TimeSpan.TicksPerMinute));
    SensorTimer.Tick += new GT.Timer.TickEventHandler(timer_Tick);
    SensorTimer.Start();
    And here’s the timer handler code:
     

    void timer_Tick(GT.Timer timer)
    {
        barometer.RequestMeasurement();
        temperatureHumidity.RequestMeasurement();
    }
    

    At this point, you already have an object that regularly measure meteorological parameters. You can compile and run it directly on the .NET Gadgeteer kit by connecting it to a USB port on your PC. It’s not connected though; we will handle that in the next part.

    Connecting to Cosm

    Before connecting to Cosm, we need to connect to a network. GHI Electronics offer different modules, we’ll talk about the Wifi Module, and the Ethernet (J11D) module .When purchasing anyone of them, pay attention that there are different references depending on the motherboard you’re using. Read the docs!

    The Ethernet module is the easier to program: here’s the code to connect to a network using DHCP:

    ethernet.NetworkSettings.EnableDhcp();

    The static equivalent:

    ethernet.NetworkSettings.EnableStaticIP("192.168.0.10", "255.255.255.0", "192.168.0.1");
    string[] dnsServers = { "192.168.0.1", "192.168.0.2" };
    ethernet.NetworkSettings.EnableStaticDns(dnsServers);
    

    There are a couple of events you can subscribe to be notified about Network changes:

    ethernet.NetworkDown += new GTM.Module.NetworkModule.NetworkEventHandler(ethernet_NetworkDown);
    ethernet.NetworkUp += new GTM.Module.NetworkModule.NetworkEventHandler(ethernet_NetworkUp);

    The Wifi module is also very straightforward to configure: you are going to use the same code, only you need to join a network first:

    WiFi_RS21.WiFiNetworkInfo wifiInfo = wifi.Search("<SSID>");
    wifi.Join(wifiInfo, "<KEY>");

    The second step is to set the system time. Since there’s no “backup” battery that saves the clock time, one has to set it everytime the system is powered. This is done with a small NTP library called MicroNTP extracted from the Micro Framework Toolkit: http://mftoolkit.codeplex.com/

    DateTime UtcTime = NtpClient.GetNetworkTime("0.fr.pool.ntp.org");
    Microsoft.SPOT.Hardware.Utility.SetLocalTime(UtcTime + new TimeSpan(TimeSpan.TicksPerHour * 2));

    The NTP server returns the Coordinated Universal Time (UTC) therefore I add the timezone difference (+2H, hardcoded here for readability reasons, it would have to be a system parameter, we’ll see later how to create a settings system.

    Once you’re connected to a network you need to send (and eventually, receive) data from Cosm (Pachube). It’s using a simple REST API and JSON serialization… you just have to pass your API key in the headers. Here’s how to send a simple webrequest posting data to your feed:

    public void Post(IFeedItem item)
    {
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(this.AssociatedAccount.EventsUrl + this.Id.ToString());
        req.Method = "PUT";
        req.ContentType = "application/json";
        req.UserAgent = "NetduinoPlus";
        req.Headers.Add("X-PachubeApiKey", this.AssociatedAccount.ApiKey);
        req.Timeout = 1000;
        if (this.AssociatedAccount.HttpProxy != null)
            req.Proxy = this.AssociatedAccount.HttpProxy;
    
        string content = item.ToJson(this.Id);
        Debug.Print(content);
    
    
        byte[] postdata = System.Text.Encoding.UTF8.GetBytes(content);
        req.ContentLength = postdata.Length;
    
        try
        {
            using (Stream s = req.GetRequestStream())
            {
                s.Write(postdata, 0, postdata.Length);
            }
    
            using (WebResponse resp = req.GetResponse())
            {
    
                using (Stream respStream = resp.GetResponseStream())
                {
                    byte[] respBytes = new byte[respStream.Length];
    
                    int length = respStream.Read(respBytes, 0, respBytes.Length);
    
                    string respString = new string(System.Text.Encoding.UTF8.GetChars(respBytes));
                    Debug.Print(respString);
                }
            }
        }
        catch (Exception ex)
        {
            Debug.Print("exception : " + ex.Message);
        }
        finally
        {
            req.Dispose();
        }
    }
    
     
    I’m not going to go into many details about how Cosm works. Most of these networks (like OpenSenSe) have the same kind of APIs so feel free to adapt them. For your convenience I’ve wrapped my code into a very simple nuget package that you can find here:
     

     

    And the sources are on codeplex:

     

    The use of this package is really easy: first, instantiate an Account object and pass it your API key. Then you can create as many feeds as you want (I only have one here, with 3 datasets), and use the Post() method to send directly data to it:

    Account pachube = new Account("miQnUMICT-KjWhDwOxWQuycKTiuSAKxCWGgrdTNyaUNEND0g");
    Feed meteoFeed = new Feed(44741, pachube);
    
          
    meteoFeed.Post(new DoubleFeedItem("barometer", sensorData.Pressure));

    There you have it – a connected meteo station, in a few lines of code. Now, let’s make use of that screen!

    Creating the Steampunk GUI : reading and displaying images from the SD Card, and charting data.

    There are two ways to create a user interface using the .NET Micro Framework. Either using the very small subset of WPF, or, a bit like a game, create a display loop and use graphical elements and fonts, just like a game. In my case, I really want my interface to have a steampunk feeling so I’m going to use a lot of images. Since it will be sealed in a box, I have no need for touch interactions, so I’m going to go for the game-like approach. I’ll have a timer that will regularly draw all images, in the right order and at the right place, depending on the various data I have. The only “non-image” data that I’m going to display is a graph, and for that all I need is a SetPixel() method. It’s very easy.

    The first step of the creation of the user interface was to work with a designer (Michel, who’s part of my team) to create a bitmap of the finished interface. Then, Michel generated all the images necessary to compose the interfaces: all the numbers, the different meteorological symbols, the fake copper plate, etc.

    I will store the graphical assets on an SD Card, and load them at startup : here’s how to check that the SD Card is present and mounted:

    if (sdCard.IsCardInserted)
    {
        if (!sdCard.IsCardMounted)
            sdCard.MountSDCard();
    
        Debug.Print("sd card mounted");
    }

    And the files are accessed this way:

    var storage = sdCard.GetStorageDevice();
    
    for (int i = 0; i < 10; i++)
    {
        Numbers[i] = storage.LoadBitmap(i.ToString() + ".bmp", Bitmap.BitmapImageType.Bmp);
    }

    Then there is a very simple API to display an image:

    display.SimpleGraphics.DisplayImage(MetalCover, 0, 0);

    The only thing I have to do to build my user interface is to combine them in the right order to draw the bitmaps on top of one another. The problem is that, as you have correctly read, I’m using… bitmaps. .NET Micro Framework only supports JPEG, GIF and Bitmap images . Luckily for me the Bitmap class has a method that I can call to specify that a specific color should be treated as transparent… so I can lay a square bitmaps on top of one another and using a specific color (a really ugly pink color in my case) give them a square look: here’s an example of a clock number, and the corresponding transparency API:

    clip_image005[6]

    Color Transparent = ColorUtility.ColorFromRGB(255, 0, 255);
    MetalCover = storage.LoadBitmap("FondTransp.bmp", Bitmap.BitmapImageType.Bmp);
    MetalCover.MakeTransparent(Transparent);

    The trick with such a technique (which is not very elegant, but quit effective) to build an interface is to have pixel perfect assets and placements. Work with your designer and be precise!

    The last thing is to draw the graph. It’s not very complicated, either algorithmically or technically: I just store a list of measures in memory, discarding them as new ones come in, much like a queue with a fixed length. Then I go through every element, drawing them backwards from the latest one, and making sure I never get out of the rectangle in which I’m allowed to draw. Here’s the code for the whole Graph class:

    class Graph
    {
        public ArrayList Values;
    
        public double Max;
        public double Min;
    
    
        public Graph(int Capacity)
        {
            Values = new ArrayList();
            Values.Capacity = Capacity;
        }
    
        public void Add(double measure)
        {
            if (Values.Count == Values.Capacity)
            {
                Values.RemoveAt(0);
            }
    
            Values.Add(measure);
            UpdateMinMax();
        }
    
        private void UpdateMinMax()
        {
            int index = Values.Count - 1;
    
            this.Min = (double)Values[index] - 3.0;
            this.Max = (double)Values[index] + 3.0;
        }
    
        public void Draw(Display_T35 display, uint x, uint y, uint height) // width == capacity
        {
            double a,b;
            uint offset;
    
            if (Max > Min)
                a = -(height / (Max - Min));
            else
                a = 0;
    
            b = y - a * Max;
    
            for (int i = 0; i < Values.Count; i++)
            {
                int index = Values.Count - 1 - i;
    
                if (a == 0)
                    offset = y + (height / 2);
                else
                    offset = (uint)System.Math.Round(a * (double)Values[index] + b);
    
                DrawPoint(display, (uint)(x + Values.Capacity - i), offset);
            }
        }
    
        public void DrawPoint(Display_T35 display, uint x, uint y)
        {
            display.SimpleGraphics.SetPixel(Gadgeteer.Color.Black, x, y);
            display.SimpleGraphics.SetPixel(Gadgeteer.Color.Black, x + 1, y);
            display.SimpleGraphics.SetPixel(Gadgeteer.Color.Black, x, y + 1);
            display.SimpleGraphics.SetPixel(Gadgeteer.Color.Black, x + 1, y + 1);
        }
    
        public double Mean(int Count)
        {
            if (Count > 0 && Values.Count > 0)
            {
                var max = (Count > Values.Count) ? Values.Count : Count;
    
                double tmp = 0.0;
                for (int i = 0; i < max; i++)
                {
                    tmp += (double)Values[max - i - 1];
                }
                tmp /= max;
    
                return tmp;
            }
            else
                return 0;
        }
    }
     
    You may also see that I have a vertical bitmap indicating the latest value of measured temperature: Placing it on the interface requires a small trick: since it’s very high, it’s far larger than the screen, so using simple maths to know, according to the temperature, which section I need, I just cut a small part of it and display this small part: here’s how I do it:
    int pixel = (int)(System.Math.Round((double)(40 - Status.Temperature) * 16.3)) - 38;
    if (pixel < 0)
        pixel = 0;
    
    Bitmap tmpCopy = new Bitmap(TemperatureIndicator.Width, TemperatureIndicator.Height);
    tmpCopy.DrawImage(0, 0, TemperatureIndicator, 0, pixel, 34, 109);
    display.SimpleGraphics.DisplayImage(tmpCopy, 137, 120);

    There we have the user interface for a connected meteo station… if you look at connected object however, you will guess that most of them need some configuration (network, usernames…). The next part is about how to build a small webserver within the meteo station, with a small form to configure its parameters (timezone, etc).

    Building a webserver and configuration interface within the meteo station

    There’s a sample project for .NET Micro Framework that works great, but the .NET gadgeteer makes it even simpler: there’s a WebServer class already included, with basic routing functionalities. We’re going to use it. We will store the HTML files on the SD Card, as well as a configuration file.

    Starting a WebServer is as simple as one line of code:

    WebServer.StartLocalServer(ethernet.NetworkSettings.IPAddress, 80);

    To configure routing (i.e. associate code execution with specific URLs), use the WebEvent class:

    WebEvent webevt = WebServer.SetupWebEvent("Settings.htm");
    webevt.WebEventReceived += new WebEvent.ReceivedWebEventHandler(webevt_WebEventReceived);

    Once the webevent is configured, calling “http://ip:port/Settings.htm” will automatically trigger the execution of the handler associated with the string “Settings.htm”. What we need to do in the handler, is therefore to return, as an HTTP response, the content of the Settings.htm file.

    void webevt_WebEventReceived(string path, WebServer.HttpMethod method, Responder responder)
    {
        responder.Respond(LoadHtmlFile(path), "text/html");
    }

    The Responder class makes it really easy to send an HTTP response, and takes a byte array as the first argument of its Respond method. This byte array is generated from an HTML file stored in the SD Card:

    private byte[] LoadHtmlFile(string path)
    { 
        byte[] result = null;
        var storage = sdCard.GetStorageDevice();
        using (var stream = storage.OpenRead(wwwRoot + path))
        {
            using (StreamReader sr = new StreamReader(stream))
            {
                string content = sr.ReadToEnd();
                result = new System.Text.UTF8Encoding().GetBytes(content);
            }
        }
    
        return result;
    }

    Once the form is submitted with the right parameters, it’s caught with another WebEvent, and the configuration is saved to the SD Card before sending the response:

    void setparams_WebEventReceived(string path, WebServer.HttpMethod method, Responder responder)
    {
        Config c = new Config();
        c.Name = (string)responder.UrlParameters["Name"];
        c.UtcOffset = int.Parse(HttpUtility.UrlDecode((string)responder.UrlParameters["UtcOffset"]));
    
        SaveConfigToSdCard(c);
    
        responder.Respond(LoadHtmlFile(path), "text/html");
    }

    The HttpUtility class that I’m using is from the community and can be found here:

     

    The SaveConfigToSdCard method is very simple:

    private void SaveConfigToSdCard(Config c)
    {
        var storage = sdCard.GetStorageDevice();
        using (var stream = storage.OpenWrite(configFilePath))
        {
            using (StreamWriter sw = new StreamWriter(stream))
            {
                sw.Write(c.ToString());
            }
        }
    }

    The Config object stores all the parameters :

    public class Config
    {
        public string Name { get; set; }
        public int UtcOffset { get; set; }
            
        public static Config FromString(string str)
        {
            Config res = new Config();
            string[] settings = str.Split('\n');
            res.Name = settings[0].Split(':')[1];
            res.UtcOffset = int.Parse(settings[1].Split(':')[1]);
                
            return res;
        }
    
        public override string ToString()
        {
            return "name:" + Name + "\n utcoffset:" + UtcOffset.ToString();
        }
    }

    As you see, the serialization/deserialization mechanism is as simple as possible. Since we’re on an embedded system with limited capabilities, the simpler the code, the faster it runs: no need for fancy XML or JSON serialization here.

    You could use the same kind of mechanism to build an API for your object so that other devices could connect directly to it. In the present case, it’s not necessary since we publish feeds to Cosm: we can use Cosm APIs!

    As anything with a configuration, one has to think of a mechanism for resetting to factory defaults. We could do that with a simple button and a timer, it’s not really interesting to detail it here, but you’ll have to think about it!

    Cherry on the cake: Using 3D modeling tool to prototype the object

    There are two ways to build a “physical” object around an electronic kit such as the gadgeteer: either by trial and error, at the risk of using a lot more material than what’s needed, or by being modeling it either on paper or using 3D tools. The pen & paper is a simple approach so it works for simple objects, but the gadgeteer teams contributed 3D models of most parts of the kits, and even if you can’t afford professional tools such as SolidWorks (personally, I can’t) there are some free tools that work really great. While researching the subject to prepare this article I’ve used 123D, but I also gave a shot at FreeCad, SketchUp, and even had Blender installed (useful for 3D format transformation). These tools manipulate different formats, and for example SketchUp doesn’t support STEP files natively (this is the format used for the gadgeteer models). So you want to be careful about the tool you choose depending on the input format for models, and the output format you wish to have. Especially if you want to model some parts using a 3D printer!

    Getting used to a CAD tool takes some time. You’re not going to make complex parts and assemblies overnight, and you’ll spend quite a few hours learning keyboard shortcuts, navigation, and good practices to be efficient. What I found out is that it’s more efficient to follow a couple of tutorials, rather than try to prototype directly the object you need. Then work on individual parts. Then assemble them. Don’t try to do the whole thing in one project directly. Here’s an example of the work in progress for the internals of my meteo station:

    clip_image007[6]

    It’s your call to see what method you prefer. For most of my projects I’ve been experimenting directly with hardware, but in this case, since I didn’t want to damage the case, and since I wanted to have a reuseable design, I decided to go with the CAD tools.

    Conclusion

    In this article, we’ve gone through the process of prototyping every function of a connected object, from the sensors, to the network, and configuration. Hopefully you now understand:

    • How to use the .NET Gadgeteer tooling
    • How to connect sensors, and get data from them
    • How to work with different kind of files on the SD Card
    • How to build a simple user interface
    • How to post them on the network
    • How to interface with Cosm
    • How to buld a webserver in your object
    • How to build a configuration mechanism

     

    We also made use of a few toolkits (mftoolkit, HttpUtility, Pachube DAL, etc) that will hopefully help you, and concluded on the possibility to use CAD tools to physically design the object around the 3D models of the gadgeteer components. Now it’s your turn to build something!

  • Pierre's Embedded and Mobile Blog

    [Windows Phone 7] Inscription sur Marketplace: les ressources pour s'en sortir dans toutes les situations

    • 12 Comments

    Ca maintenant quelques semaines qu’on peut s’inscrire et publier des applications sur Marketplace. Seulement voila, le processus d’inscription, dépendant de vos comptes existants sur d’autres plateformes Microsoft, peut s’avérer… complexe. Sans compter la validation d’identité par Geotrust, dont on reparle un peu plus bas, ou les formulaires pour être éligible au paiement.

    Aujourd’hui l’idée de Microsoft est d’unifier les comptes développeurs à travers un seul portail, l’App-Hub: ainsi, qu’on soit développeur XBox ou Windows Phone, un seul compte, un seul endroit pour gérer tout son portefeuille d’applications. Ce qui fait du sens vu qu’avec XNA Game Studio 4.0 il devient très facile de faire des jeux multi-plateformes.

    Donc avant toute chose… connaitre les pages de ressources du portail Microsoft:

    Parce que des fois, il suffit de lire la doc… Smile

    Ensuite, https://billing.microsoft.com/ est le site qui unifie les paiements que vous faites avec votre live id: il est donc important que les informations (personnelles, professionnelles, de facturation) qui y sont enregistrées soient valides et valables! Je vous recommande de passer par là dès le départ pour mettre les choses en ordre.

    Enfin, sachez que votre identité est vérifiée par Geotrust, une entité indépendante de Microsoft, et que Geotrust est censé, après votre inscription, vous envoyer un email relatant comment vérifier cette identité (cela consiste la plupart du temps à envoyer un simple scan de pièce d’identité). Pour les entreprises, si vous avez rempli le champ “approver” lors de votre inscription, l’approver en question recevra un email lui demandant de valider que vous avez le droit de poster des applications: cela permet à plusieurs collègues d’accéder au compte Marketplace de la société avec leur live id individuel par exemple. Ces emails sont automatisés… et peuvent donc arriver dans votre filtre antispam !! si vous ne recevez pas de contacts de la part de Geotrust parce que vous n’avez pas la main sur ce filtre antispam par exemple, ce n’est pas grave, vous pouvez toujours les contacter en direct:

    GeoTrust Customer Support
    http://www.geotrust.com/support
    Hours of Operation: Mon - Fri 05:00 - 17:00 (PST)
    Email:     cs-orders@geotrust.com
    Web:       http://www.geotrust.com
    Phone:     1-866-436-8787 or 1-678-366-8399 option 2
    Live Chat: http://www.geotrust.com/support

    Je ne peux que recommander leur Live Chat qui est extrêmement réactif.

    Pour info, certains développeurs ont trouvés une feinte pour se faire valider le compte plus vite: soumettre une application bidon qui oblige Geotrust à vous passer en mode “haute priorité”… je ne recommande pas cette méthode, qui surcharge évidemment l’équipe certification, qui a déjà fort à faire!

    Ensuite, vient le temps des formulaires à remplir pour se rendre éligible au paiement. (Avant toute chose.. sachez que je ne suis pas juriste… j’aide comme je peux…)

    Le formulaire W8-BEN est le seul absolument nécessaire pour se faire payer: il est à renvoyer à Microsoft. Vous pouvez le retrouver directement sur l’App-Hub dans la section “payee details” de votre compte.

    Maintenant, vous pouvez aller plus loin en demandant à être exempté du prélèvement à la source de l’impôt américain (c’est quand même 30%…). Pour cela il faut un numéro ITIN ou un EID, qui s’obtient auprès de l’IRS (l’institut qui gère les impôts américains). Pour obtenir ce numéro… il faut remplir un formulaire W-7, et pour justifier cette demande, utiliser la lettre de justification de Microsoft que vous pouvez générer directement depuis l’App-Hub. L’obtention de ce numéro ITIN permet de certifier que vous vous comportez correctement vis à vis de la loi Américaine, et de la loi de votre pays, et est sujette aux accords entre l’organisation des impôts de votre pays, et de l’IRS.

    On reprend:

    • Demander la lettre de justification de Microsoft
    • Remplir le formulaire W7 de l’IRS pour obtenir un numéro ITIN ou un EID
    • Remplir le formulaire W8-BEN en indiquant le numéro ITIN ou EID

    Ca peut prendre un peu de temps, et ça peut ressembler à la maison qui rend fou, mais c’est un processus légal et standard auquel n’importe quel citoyen est obligé de se conformer quand on reçoit des revenus depuis les US, indépendamment de Microsoft!! Sachez que vous pouvez retrouver toutes ces informations directement dans la section “payee details” de votre compte, et que l’IRS a une antenne à l’ambassade américaine qui est joignable par téléphone. A priori, les fiscalistes, comptables, etc sont censés comprendre toutes ces choses… si vous en avez dans votre entourage, faites vous aider!

  • Pierre's Embedded and Mobile Blog

    [Windows Phone 7] Le SDK pour VS2010 RTM est disponible!

    • 5 Comments

    Nombre d’entre nous, développeurs mobiles, n’en pouvions plus de ne pouvoir installer la RTM de Visual Studio 2010, car le SDK pour Windows Phone 7 n’était compatible qu’avec la RC. La CTP Refresh vient corriger tout ça!

    Les outils sont comme d’habitude téléchargeables à partir de http://developer.windowsphone.com

    Les liens utiles:

    happy installing // happy coding!

  • Pierre's Embedded and Mobile Blog

    Expiration du certificat fournit avec le SDK Windows Mobile 6 Refresh

    • 0 Comments

    Certain d’entre vous l’ont déjà remarqué, le certificat pour signer du code qui est fournit avec le SDK Windows Mobile 6 Refresh a expiré au 31/12/2009. Si vous avez besoin de signer votre code, vous ne pouvez donc plus l’utiliser. La solution est d’en recréer un nouveau. Ce n’est pas vraiment compliqué, et la démarche est complètement expliquée sur le forum MSDN US: Créez un nouveau certificat et provisionnez le sur votre terminal

    Une lecture éducative même pour ceux qui ne signent pas leur code!

    [edit] l’équipe Windows Phone vient de faire un post sur le sujet sur leur blog et de publier un lien direct vers de nouveaux certificats

  • Pierre's Embedded and Mobile Blog

    La Boite à Outils de l’Application Géolocalisée: Partie 1: GPS, et CellId

    • 2 Comments

    Cet article fait partie d'une série de 3: La Boite à Outils de l'Application Géolocalisée

    Une des révolutions de l'intégration du GPS dans le smartphone, c'est la possibilité pour l'utilisateur de se localiser ou qu'il soit et de trouver des informations en rapport avec sa position: que ce soit une carte ou des directions pour aller quelque part, les horaires de métro de la station d'à coté, les critiques du restaurant devant lequel il passe, etc.

    Windows Mobile propose un certain nombre d’outils pour facilement trouver la localisation de l’utilisateur: avec ou sans GPS. Cet article va détailler un certain nombre d’outils pratiques pour l’application qui voudrait proposer du contenu géolocalisé.

    Récupérer sa position

    Avec le GPS

    Le SDK Windows Mobile propose un code d’exemple (Sample Code) qui expose en .NET les API natives permettant d’accéder au GPS. La première chose à faire est donc de compiler ce sample qui est situé dans C:\Program Files\Windows Mobile 6 SDK\Samples\PocketPC\CS\GPS. Ceci étant fait, on peut référencer la DLL générée (qui se trouve dans bin/Debug ou bin/Release) dans un projet et ajouter :

    using Microsoft.WindowsMobile.Samples.Location;

    Ceci étant fait, l’utilisation du GPS est pire que simple. Voici un tout petit bout de code qui permet de récupérer la position courante et qui le place dans le champ Text d’un contrôle de type Label:

    Gps myGps = new Gps();

    GpsPosition myPosition = myGps.GetPosition();

    if (myPosition.LatitudeValid && myPosition.LongitudeValid)

    {

        lblLatResult.Text = myPosition.Latitude.ToString();

        lblLngResult.Text = myPosition.Longitude.ToString();

    }

    else

    {

        MessageBox.Show("Can't get a valid position");

    }

    myGps.Close();

     

    Avec l’identifiant de cellule (CellId)

    Si on veut faire de la géolocalisastion sans avoir de GPS (soit parce qu’il n’y en a pas sur le smartphone, soit parce que la couverture GPS ne le permet pas (à l’intérieur d’un bâtiment par exemple) il est possible de récupérer une localisation à quelques dizaines, voire centaines de mètres près, en utilisant l’identifiant de la cellule dans laquelle le téléphone est connecté au réseau de l’opérateur. En effet, il existe des bases de données qui permettent de faire correspondre un identifiant de cellule à un couple latitude/longitude.

    L’identifiant de station de base est en fait constitué de 4 champs différents :

    -          L’identifiant de pays : (Mobile Country Code)

    -          L’identifiant de réseau : (Mobile Network Code)

    -          Le code de zone (Location Area Code)

    -          L’identifiant de la cellule : (Cell Identifier)

    Ces quatre champs peuvent être récupérés avec une fonction de l’API RIL (Radio Interface Layer) : RIL_GetCellTowerInfo.

    Pour utiliser cette API depuis un programme en .NET il faut donc utiliser un wrapper, mais je n’ai pas besoin de le réinventer : un développeur de la communauté .NET, Dale Lane, l’a déjà fait !

    -          Son code : http://dalelane.co.uk/blog/post-images/080312-rilcode.cs.txt

    -          Son Blog : http://dalelane.co.uk/blog/

    J’ai légèrement modifié le code de Dale, qui à l’origine ne retournait pas de Mobile Network Code. Maintenant, la fonction GetCellTowerInfo() retourne les 4 champs séparés par des tirets de la façon suivante : CellId-LAC-MCC-MNC :

    class CellIdWrapper

    {

        // string used to store the CellID string

        private static string celltowerinfo = "";

     

        /*

         * Uses RIL to get CellID from the phone.

         */

        public static string GetCellTowerInfo()

        {

            // initialise handles

            IntPtr hRil = IntPtr.Zero;

            IntPtr hRes = IntPtr.Zero;

     

            // initialise result

            celltowerinfo = "";

     

            // initialise RIL

            hRes = RIL_Initialize(1,                                        // RIL port 1

                                  new RILRESULTCALLBACK(rilResultCallback), // function to call with result

                                  null,                                     // function to call with notify

                                  0,                                        // classes of notification to enable

                                  0,                                        // RIL parameters

                                  out hRil);                                // RIL handle returned

     

            if (hRes != IntPtr.Zero)

            {

                return "Failed to initialize RIL";

            }

     

            // initialised successfully

     

            // use RIL to get cell tower info with the RIL handle just created

            hRes = RIL_GetCellTowerInfo(hRil);

     

            // wait for cell tower info to be returned

            waithandle.WaitOne();

     

            // finished - release the RIL handle

            RIL_Deinitialize(hRil);

     

            // return the result from GetCellTowerInfo

            return celltowerinfo;

        }

     

     

        // event used to notify user function that a response has

        //  been received from RIL

        private static AutoResetEvent waithandle = new AutoResetEvent(false);

     

     

        public static void rilResultCallback(uint dwCode,

                                             IntPtr hrCmdID,

                                             IntPtr lpData,

                                             uint cbData,

                                             uint dwParam)

        {

            // create empty structure to store cell tower info in

            RILCELLTOWERINFO rilCellTowerInfo = new RILCELLTOWERINFO();

     

            // copy result returned from RIL into structure

            Marshal.PtrToStructure(lpData, rilCellTowerInfo);

     

            // get the bits out of the RIL cell tower response that we want

            celltowerinfo = rilCellTowerInfo.dwCellID + "-" +

                            rilCellTowerInfo.dwLocationAreaCode + "-" +

                            rilCellTowerInfo.dwMobileCountryCode + "-" +

                            rilCellTowerInfo.dwMobileNetworkCode;

     

            // notify caller function that we have a result

            waithandle.Set();

        }

     

     

     

        // -------------------------------------------------------------------

        //  RIL function definitions

        // -------------------------------------------------------------------

     

        /*

         * Function definition converted from the definition

         *  RILRESULTCALLBACK from MSDN:

         *

         * http://msdn2.microsoft.com/en-us/library/aa920069.aspx

         */

        public delegate void RILRESULTCALLBACK(uint dwCode,

                                               IntPtr hrCmdID,

                                               IntPtr lpData,

                                               uint cbData,

                                               uint dwParam);

     

     

        /*

         * Function definition converted from the definition

         *  RILNOTIFYCALLBACK from MSDN:

         *

         * http://msdn2.microsoft.com/en-us/library/aa922465.aspx

         */

        public delegate void RILNOTIFYCALLBACK(uint dwCode,

                                               IntPtr lpData,

                                               uint cbData,

                                               uint dwParam);

     

        /*

         * Class definition converted from the struct definition

         *  RILCELLTOWERINFO from MSDN:

         *

         * http://msdn2.microsoft.com/en-us/library/aa921533.aspx

         */

        public class RILCELLTOWERINFO

        {

            public uint cbSize;

            public uint dwParams;

            public uint dwMobileCountryCode;

            public uint dwMobileNetworkCode;

            public uint dwLocationAreaCode;

            public uint dwCellID;

            public uint dwBaseStationID;

            public uint dwBroadcastControlChannel;

            public uint dwRxLevel;

            public uint dwRxLevelFull;

            public uint dwRxLevelSub;

            public uint dwRxQuality;

            public uint dwRxQualityFull;

            public uint dwRxQualitySub;

            public uint dwIdleTimeSlot;

            public uint dwTimingAdvance;

            public uint dwGPRSCellID;

            public uint dwGPRSBaseStationID;

            public uint dwNumBCCH;

        }

     

        // -------------------------------------------------------------------

        //  RIL DLL functions

        // -------------------------------------------------------------------

     

        /* Definition from: http://msdn2.microsoft.com/en-us/library/aa919106.aspx */

        [DllImport("ril.dll")]

        private static extern IntPtr RIL_Initialize(uint dwIndex,

                                                    RILRESULTCALLBACK pfnResult,

                                                    RILNOTIFYCALLBACK pfnNotify,

                                                    uint dwNotificationClasses,

                                                    uint dwParam,

                                                    out IntPtr lphRil);

     

        /* Definition from: http://msdn2.microsoft.com/en-us/library/aa923065.aspx */

        [DllImport("ril.dll")]

        private static extern IntPtr RIL_GetCellTowerInfo(IntPtr hRil);

     

        /* Definition from: http://msdn2.microsoft.com/en-us/library/aa919624.aspx */

        [DllImport("ril.dll")]

        private static extern IntPtr RIL_Deinitialize(IntPtr hRil);

     

    }

    J’intègre le code de Dale dans une classe CellIdWrapper que je rajoute à mon projet dans un fichier séparé.

    Puis, dans le code de mon application, je récupère ces informations de la façon suivante :

    string cellIdInfo = CellIdWrapper.GetCellTowerInfo();

    string[] splittedInfos = cellIdInfo.Split('-');

     

    lblCellIdResult.Text = splittedInfos[0];

    lblLACResult.Text = splittedInfos[1];

    lblMCCResult.Text = splittedInfos[2];

    lblMNCResult.Text = splittedInfos[3];

    Il faut maintenant que je fasse correspondre cet identifiant à une latitude et une longitude. Pour cela, j’ai trouvé 2 bases différentes à utiliser :

    -          Une API « cachée » de Google Maps

    -          Une API ouverte du groupe OpenCellID

    L’API Cachée de Google Maps

    Petit disclaimer obligatoire : il ne s’agit pas d’un API officielle, elle n’est donc pas supportée par Google, il est tout à fait possible qu’un jour ça ne marche plus…

    Encore une fois, pas besoin de tout réécrire depuis zéro, la communauté va travailler pour moi. Un développeur du nom de Neil Young a développé un bout de wrapper qui fait exactement ce que je veux. Problème, son site n’existe plus, heureusement il a été repris :

    -          Article de Wei Meng sur DevX : http://www.devx.com/wireless/Article/39709/1954

    Comme avec le wrapper de Dale Lane, je rajoute ce wrapper dans un fichier séparé, dans une classe que j’appelle GoogleMapsApi.

    static byte[] PostData(int MCC, int MNC, int LAC, int CID,

                           bool shortCID)

    {

        /* The shortCID parameter follows heuristic experiences:

         * Sometimes UMTS CIDs are build up from the original GSM CID (lower 4 hex digits)

         * and the RNC-ID left shifted into the upper 4 digits.

         */

        byte[] pd = new byte[] {

            0x00, 0x0e,

            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

            0x00, 0x00,

            0x00, 0x00,

            0x00, 0x00,

     

            0x1b,

            0x00, 0x00, 0x00, 0x00, // Offset 0x11

            0x00, 0x00, 0x00, 0x00, // Offset 0x15

            0x00, 0x00, 0x00, 0x00, // Offset 0x19

            0x00, 0x00,

            0x00, 0x00, 0x00, 0x00, // Offset 0x1f

            0x00, 0x00, 0x00, 0x00, // Offset 0x23

            0x00, 0x00, 0x00, 0x00, // Offset 0x27

            0x00, 0x00, 0x00, 0x00, // Offset 0x2b

            0xff, 0xff, 0xff, 0xff,

            0x00, 0x00, 0x00, 0x00

        };

     

        bool isUMTSCell = ((Int64)CID > 65535);

     

        if (isUMTSCell)

            Console.WriteLine("UMTS CID. {0}", shortCID ?

                "Using short CID to resolve." : "");

        else

            Console.WriteLine("GSM CID given.");

     

        if (shortCID)

            CID &= 0xFFFF;      /* Attempt to resolve the cell using the

                                GSM CID part */

     

        if ((Int64)CID > 65536) /* GSM: 4 hex digits, UTMS: 6 hex

                                digits */

            pd[0x1c] = 5;

        else

            pd[0x1c] = 3;

     

        pd[0x11] = (byte)((MNC >> 24) & 0xFF);

        pd[0x12] = (byte)((MNC >> 16) & 0xFF);

        pd[0x13] = (byte)((MNC >> 8) & 0xFF);

        pd[0x14] = (byte)((MNC >> 0) & 0xFF);

     

        pd[0x15] = (byte)((MCC >> 24) & 0xFF);

        pd[0x16] = (byte)((MCC >> 16) & 0xFF);

        pd[0x17] = (byte)((MCC >> 8) & 0xFF);

        pd[0x18] = (byte)((MCC >> 0) & 0xFF);

     

        pd[0x27] = (byte)((MNC >> 24) & 0xFF);

        pd[0x28] = (byte)((MNC >> 16) & 0xFF);

        pd[0x29] = (byte)((MNC >> 8) & 0xFF);

        pd[0x2a] = (byte)((MNC >> 0) & 0xFF);

     

        pd[0x2b] = (byte)((MCC >> 24) & 0xFF);

        pd[0x2c] = (byte)((MCC >> 16) & 0xFF);

        pd[0x2d] = (byte)((MCC >> 8) & 0xFF);

        pd[0x2e] = (byte)((MCC >> 0) & 0xFF);

     

        pd[0x1f] = (byte)((CID >> 24) & 0xFF);

        pd[0x20] = (byte)((CID >> 16) & 0xFF);

        pd[0x21] = (byte)((CID >> 8) & 0xFF);

        pd[0x22] = (byte)((CID >> 0) & 0xFF);

     

        pd[0x23] = (byte)((LAC >> 24) & 0xFF);

        pd[0x24] = (byte)((LAC >> 16) & 0xFF);

        pd[0x25] = (byte)((LAC >> 8) & 0xFF);

        pd[0x26] = (byte)((LAC >> 0) & 0xFF);

     

        return pd;

    }

     

    static public string GetLatLng(string[] args)

    {

        if (args.Length < 4)

        {

            return string.Empty;

        }

        string shortCID = "";   /* Default, no change at all */

        if (args.Length == 5)

            shortCID = args[4].ToLower();

        try

        {

            String url = "http://www.google.com/glm/mmap";

            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(

                new Uri(url));

            req.Method = "POST";

     

            int MCC = Convert.ToInt32(args[0]);

            int MNC = Convert.ToInt32(args[1]);

            int LAC = Convert.ToInt32(args[2]);

            int CID = Convert.ToInt32(args[3]);

            byte[] pd = PostData(MCC, MNC, LAC, CID,

                shortCID == "shortcid");

     

            req.ContentLength = pd.Length;

            req.ContentType = "application/binary";

            Stream outputStream = req.GetRequestStream();

            outputStream.Write(pd, 0, pd.Length);

            outputStream.Close();

     

            HttpWebResponse res = (HttpWebResponse)req.GetResponse();

            byte[] ps = new byte[res.ContentLength];

            int totalBytesRead = 0;

            while (totalBytesRead < ps.Length)

            {

                totalBytesRead += res.GetResponseStream().Read(

                    ps, totalBytesRead, ps.Length - totalBytesRead);

            }

     

            if (res.StatusCode == HttpStatusCode.OK)

            {

                short opcode1 = (short)(ps[0] << 8 | ps[1]);

                byte opcode2 = ps[2];

                int ret_code = (int)((ps[3] << 24) | (ps[4] << 16) |

                               (ps[5] << 8) | (ps[6]));

                if (ret_code == 0)

                {

                    double lat = ((double)((ps[7] << 24) | (ps[8] << 16)

                                 | (ps[9] << 8) | (ps[10]))) / 1000000;

                    double lon = ((double)((ps[11] << 24) | (ps[12] <<

                                 16) | (ps[13] << 8) | (ps[14]))) /

                                 1000000;

                    return lat + "|" + lon;

                }

                else

                    return string.Empty;

            }

            else

                return string.Empty;

        }

        catch (Exception ex)

        {

            return ex.Message;

        }

    }

    Super simple à réutiliser depuis mon code avec la méthode GetLatLng  à qui on passe un tableau de string avec dans l’ordre MCC, MNC, LAC et CellId, et qui me renvoie dans une chaine de caractères la latitude et la longitude séparée par un caractère ‘|’  (pipe) :

    string result = GoogleMapsApi.GetLatLng(args);

     

    string[] splittedResult = result.Split('|');

    lblLatResult.Text = splittedResult[0];

    lblLngResult.Text = splittedResult[1];

    L’API ouverte du groupe OpenCellID

     

    OpenCellId est une initiative qui vise à crowdsourcer un maximum de coordonnées de tour cellulaires. C’est un peu moins précis que la base de données de Google, mais c’est en participant que ca s’améliorera J

    -          Le site web : http://opencellid.org/

    -          L’application Windows Mobile pour aider à crowdsourcer les informations : http://opencellclient.sourceforge.net/

    Pour utiliser l’API OpenCellID, il faut demander une clé d’API, qui est envoyée automatiquement lorsqu’on s’enregistre sur le site d’OpenCellID : http://opencellid.org/users/signup.

    L’API OpenCellID est très simple : c’est du REST, donc j’envoie une requête http, et ils me renvoient les informations dans du XML : l’API est détaillée à l’adresse suivante : http://opencellid.org/api

    Pour plus d’homogénéité dans mon projet je vais encore créer un autre fichier avec à l’intérieur une classe OpenCellIdApi qui contiendra, comme le wrapper pour l’API Google, une fonction GetLatLng, avec le même tableau d’arguments en entrée, et la même chaine de caractères en sortie.

    Voici à quoi ressemble du code pour interroger la base OpenCellID :

    struct OCIWebServiceResponse

    {

        public string lat;

        public string lng;

        public string status;

        public string nbSamples;

        public string range;

     

    }

     

    static public string GetLatLng(string[] args)

    {

        if (args.Length < 4)

        {

            return "Not Enough Arguments";

        }

        OCIWebServiceResponse response;

        StringBuilder urlArgs = new StringBuilder("key=" + myApiKey);

        urlArgs.Append("&mnc=" + args[1]);

        urlArgs.Append("&mcc=" + args[0]);

        urlArgs.Append("&lac=" + args[2]);

        urlArgs.Append("&cellid=" + args[3]);

        try

        {

            WebRequest myRequest = WebRequest.Create(new Uri(BaseUrl + urlArgs.ToString()));

            WebResponse myResponse = myRequest.GetResponse();

            XmlReader myReader = XmlReader.Create(myResponse.GetResponseStream());

            try

            {

                response = (from rsp in XDocument.Load(myReader).Descendants("rsp")

                            let cell = rsp.Descendants("cell").Single()

                            select new OCIWebServiceResponse

                            {

                                status = rsp.Attribute("stat").Value,

                                lat = cell.Attribute("lat").Value,

                                lng = cell.Attribute("lon").Value,

                                nbSamples = cell.Attribute("nbSamples").Value,

                                range = cell.Attribute("range").Value

                            }).Single();

            }

            finally

            {

                myReader.Close();

                myResponse.Close();

            }

        }

        catch (Exception ex)

        {

            return ex.Message;

        }

        if (response.status != "ok")

            return "Response from OpenCellId not OK!";

        else

            return response.lat + "|" + response.lng;

    }

     

    Pour parser la réponse en XML, j’utilise une requête LINQ et une structure « maison » qui rend mon code plus lisible.

    Point important, c’est du code de démo, la gestion des erreurs est assez pauvre, même carrément mauvaise : il ne faudrait pas retourner une chaine de caractère comme je le fais mais plutôt lever une exception !

    Prochaine étape: Geocoding d'adresse!

  • Pierre's Embedded and Mobile Blog

    [Pratique] Suivez les mises à jour de HTC pour votre Windows phone

    • 0 Comments

    Truc pratique du jour: le support HTC publie sur un flux RSS la liste des mises à jour qu’ils publient.. utilisez votre newsreader préféré pour vous abonner à : http://www.htc.com/fr/supportrss.aspx

    Et vous verrez arriver les nouvelles ROMs officielles, ainsi que les bugfixes qu’ils publient de plus en plus réguilèrement!

    C’est important car les constructeurs sont les seuls à pouvoir intégrer des mises à jour sur leurs téléphones (eh oui, malheureusement, pour des raisons de licencing, mais aussi d’accès aux sources des drivers et aux outils d’intégration, Microsoft ne peut pas “obliger” les constructeurs à fournir des mises à jour, qu’elles soient majeures, ou de simples bugfixes… c’est d’ailleurs la même chose avec Android :))

  • Pierre's Embedded and Mobile Blog

    [Teasing] Windows Phone au Mobile World Congress et au MIX10

    • 0 Comments

    A une époque ou les rumeurs (que je ne commenterai pas) vont bon train sur le net… Pourquoi est-ce qu’on pourrait bien faire:

    On dirait que je vais a voir des choses à blogger sous peu…

  • Pierre's Embedded and Mobile Blog

    Les différences entre Windows Embedded Standard 7 et Windows Embedded Standard 2009 (XP Embedded)

    • 0 Comments

    Voici un excellent article publié par le non moins excellent site WindowsForDevices (en anglais) sur les différences entre Windows Embedded Standard 2009 (la dernière mouture de ce qui s’appelait il n’y a encore pas si longtemps XP Embedded) et Windows Embedded Standard 7 (WES7 pour les intimes, construit avec les briques de Windows 7).

    En substance, on retrouve les détails sur les changements dans l’architecture de componentisation (des applications, des drivers, etc), sur la gestion des dépendances, des “Embedded Enabling Features” et des phases de construction et de déploiement de l’image.

    Comparatif: WES2009 vs WES7

  • Pierre's Embedded and Mobile Blog

    Windows Phone 8: Faites le plein de nouveautés rapide à intégrer dans votre application

    • 2 Comments

    Windows Phone 8 offre un grand nombre de nouvelles APIs qui vont permettre aux développeurs de proposer de nouvelles expériences à leurs utilisateurs, et améliorer grandement l’intégration dans l’OS. Le but de cet article est de faire le tour des plus faciles et rapides à intégrer.

    Ou sont les outils ?

    Tous les liens importants sont listés dans cet article, alors lancez les téléchargements/installations pendant que vous lisez cet article !

    Les liens utiles du SDK Windows Phone 8

    Que faire du code existant ?

    Réponse courte : on peut tout garder ! 100% des API de Windows Phone 7.0/7.1 sont présentes dans Windows Phone 8. Ceci étant dit, le passage à une nouvelle version et l’ajout de fonctionnalités est souvent l’occasion de ré-architecturer un peu son code. Pourquoi ne pas le rendre plus portable, par exemple pour être présent aussi sous Windows 8 ? Pour cela je vous réfère à la série d’articles sur le portage et le partage de code entre Windows 8 et Windows Phone :

    Stratégies et Techniques de Partage et de Portage de code entre Windows Phone et Windows 8

    Que vous décidiez de modifier votre code existant ou pas, vous pouvez par ailleurs tester votre application sur un Windows Phone 8 et constater que sans rien changer, elle fonctionne, voire noter un gain de performance significatif, principalement dû au nouveau matériel, et aux optimisations réalisées sur l’OS et le Runtime.

    Si vous préférez un document offline et l’application exemple:

    Voici le lien vers le dossier Skydrive contenant les deux:

    http://sdrv.ms/Sx5VsO

     

    Quels sont les nouveaux scénarios possibles ?

    Passons maintenant aux nouveaux scénarios, que nous allons étudier en commençant par les plus rapides à intégrer (de l’ordre de quelques minutes !!) et en poussant vers les plus compliqués.

    En moins d’une heure…

    Vous pourrez avoir intégrer des nouvelles vignettes dynamiques, animées, et de différentes tailles, et de l’intégration sur l’écran de verrouillage. Vous pourrez également profiter des nouveaux launchers et choosers, de l’expérience Nokia Maps, des fonctionnalités de reconnaissance et synthèse vocales, d’un gain de performance non négligeable sur le LongListSelector… et aussi éventuellement revoir vos layouts et vos assets pour les nouvelles résolutions J

    En une demi-journée…

    Associez votre application à des types de fichiers ou des schémas d’URL, devenez une application « Lens » intégrée à l’appareil photo, ou bien un fournisseur de contact pour le hub contacts/people. Profitez de la nouvelle option de géolocalisation en background. Monétisez votre contenu et les bonus de vos applications avec les nouvelles options d’achat In-App.

    Et pour aller plus loin…

    Intégrez de nouvelles fonctionnalités ou du code existant avec le nouveau modèle de développement en C++, tirez parti de la technologie NFC pour s’identifier, payer ou établir une communication entre 2 appareils et profiter ensuite du Bluetooth ou du Wifi pour échanger des données, Intégrez-vous au wallet pour offrir à l’utilisateur d’y retrouver ses cartes de fidélité, cartes de membres, et éventuellement des coupons de réduction… Autoriser l’application à tourner 100% du temps en background pour faire de la géolocalisation… Ces points-là méritent des articles à part entière, nous ne les traiterons donc pas dans cet article-ci.

    Passons à la pratique

    Les nouvelles vignettes dynamiques

    Le nouvel écran d’accueil supporte 3 tailles de vignettes :

    • Les petites, d’environ ¼ de la taille des vignettes « normales »
    • Les vignettes carrées, auxquelles nous étions déjà habituées
    • Les vignettes larges, qui font la taille de deux vignettes carrées

    Avec ces nouvelles tailles viennent de nouveaux modèles, à l’instar des vignettes de Windows 8, qui permettent d’animer (ou pas) votre vignette principale et les vignettes secondaires.

    • StandardTile, qui permet d’avoir une icône, un titre, éventuellement du texte au dos, et un compteur
    • FlipTile, qui se retournera aléatoirement et supporte des contenus sur l’avant et l’arrière de la vignette.
    • CycleTile, qui permettra de faire défiler verticalement du contenu (texte ou photos)
    • IconicTile, qui mettra en valeur votre icône et éventuellement du texte ou un compteur associé.

     

    Chacun de ces modèles existe dans les formats normaux et larges, le petit format étant déduit du premier. A chaque modèle est associé une structure de donnée contenant le texte et éventuellement l’adresse des images qu’on veut afficher, il s’agit des classes héritant de la classe abstraite ShellTileData.

    Comme avant, on pourra donc créer une telle structure de donnée, la remplir avec les informations à afficher, et créer une nouvelle vignette correspondante en appelant la méthode ShellTile.Create( …) pour une nouvelle tuile secondaire, ou bien la méthode Update() pour les vignettes existantes.

     

    FlipTileData ftd = new FlipTileData();
    ftd.Title = "Flip Tile Title";
    ftd.Count = 42;
    ftd.BackBackgroundImage = new Uri("/Assets/Tiles/FlipCycleTileMedium.png", UriKind.Relative);
    ftd.WideBackContent = "Flip Tile Wide Back Content";
    ftd.WideBackBackgroundImage = new Uri("/Assets/Tiles/FlipCycleTileLarge.png", UriKind.Relative);
    ftd.SmallBackgroundImage = new Uri("/Assets/Tiles/FlipCycleTileSmall.png", UriKind.Relative);
    
    ShellTile.Create(new Uri("/Pages/TilesAPI.xaml", UriKind.Relative), ftd, true);

    IconicTileData itd = new  IconicTileData();
    itd.BackgroundColor = Colors.DarkGray;
    itd.Title = "Iconic Tile Title";
    itd.IconImage = new Uri("/Assets/Tiles/IconicTileMediumLarge.png", UriKind.Relative);
    itd.SmallIconImage = new Uri("/Assets/Tiles/IconicTileSmall.png", UriKind.Relative);
    itd.Count = 42;
    itd.WideContent1 = "Wide Content 1";
    itd.WideContent2 = "Wide Content 2";
    itd.WideContent3 = "Wide Content 3";
    
    ShellTile.Create(new Uri("/Pages/TilesAPI.xaml", UriKind.Relative), itd, true);

    var images = new List<Uri>();
    images.Add(new Uri("/Assets/Tiles/FlipCycleTileLarge.png", UriKind.Relative));
    images.Add(new Uri("/Assets/Tiles/FlipCycleTileMedium.png", UriKind.Relative));
    images.Add(new Uri("/Assets/Tiles/FlipCycleTileSmall.png", UriKind.Relative));
    
    CycleTileData ctd = new CycleTileData();
    ctd.Count = 42;
    ctd.CycleImages = images;
    ctd.SmallBackgroundImage = new Uri("/Assets/Tiles/FlipCycleTileSmall.png", UriKind.Relative);
                
    ctd.Title = "Cycle Tile Title";
                
    ShellTile.Create(new Uri("/Pages/TilesAPI.xaml", UriKind.Relative), ctd, true);

    Changer le contenu de l’écran de verrouillage

    Une nouvelle API de Windows Phone 8 permet de changer l’image de fond de l’écran de verrouillage, ainsi que les 3 lignes de texte qui apparaissent sous l’heure, et éventuellement un compteur avec une mini-icône, comme les applications mails.

    Le changement de l’image de fond se fait en appelant d’abord l’API du LockScreenManager pour récupérer l’autorisation de changer celui-ci, puis il suffit de lui indiquer l’URL (locale) de l’image à utiliser. Moins de 10 lignes de code :

     

    try
    {
        if (!LockScreenManager.IsProvidedByCurrentApplication)
        {
            await LockScreenManager.RequestAccessAsync();
        }
    
        if (LockScreenManager.IsProvidedByCurrentApplication)
        {
            Uri imageUri = new Uri("ms-appx:///Assets/wpbackground.png", UriKind.RelativeOrAbsolute);
            Windows.Phone.System.UserProfile.LockScreen.SetImageUri(imageUri);
        }
    }
    catch (Exception ex)
    {
        // Handle exception
    }

    Pour ce qui est du texte et éventuellement du compteur, en fait c’est encore plus simple (et logique) : le lockscreen reprendra le texte et le compteur de la vignette dynamique principale de l’application. Il faut donc que l’application soit épinglée sur l’écran d’accueil et que l’utilisateur ait choisi d’avoir ces notifications sur son écran de verrouillage.

    Devenir un Store de contacts

    Avec la version précédente du SDK, il était possible d’accéder à la liste de contacts (avec des API LINQ) en lecture seule, et éventuellement d’écrire dans un store existant, avec le launcher SaveContactTask.

    Il est maintenant possible de devenir un fournisseur de contacts, au même titre que les réseaux sociaux ou de comptes mails existants nativement. Il faut commencer par créer (ou ouvrir, s’il est déjà créer) le store de contacts propre à l’application :

    var store = await ContactStore.CreateOrOpenAsync();

    Ensuite, on peut y faire des requêtes, pour par exemple afficher la liste des contacts déjà enregistrés par l’application :

    ContactQueryResult cqr = store.CreateContactQuery();
    IReadOnlyList<StoredContact> contacts = await cqr.GetContactsAsync();
    if (contacts.Count > 0)
        Dispatcher.BeginInvoke(() => lbxContacts.DataContext = contacts.ToList());

    Enfin, on peut ajouter de nouveaux contacts simplement:

     

    StoredContact c = new StoredContact(store);
    c.DisplayName = "John Doe";
                
    
    IDictionary<string, object> props = await c.GetPropertiesAsync();
    props.Add(KnownContactProperties.Email, "john@doe.com");
    props.Add(KnownContactProperties.MobileTelephone, "118218");
                
    await c.SaveAsync();

    Facile, et on obtient ensuite une fiche contact dans le hub avec lequel l’utilisateur peut interagir, et éventuellement la lier aux autres fiches qu’il aurait de différentes sources sur le même contact :

    wp_ss_20121031_0001

     

    S’intégrer au calendrier

    En plus des alarmes et des rappels, qui permettaient d’imiter l’expérience native du réveil ou du calendrier pour rappeler à l’utilisateur un évènement, et en plus de l’accès en lecture seule au calendrier, l’arrivée de Windows Phone 8 rajoute un launcher qui permet de sauvegarder un évènement dans le calendrier :

    SaveAppointmentTask sat = new SaveAppointmentTask();
    sat.StartTime = DateTime.Now + TimeSpan.FromDays(1);
    sat.Details = "Details of the appointment";
    sat.Subject = "Appointment generated from an app";
    sat.EndTime = sat.StartTime + TimeSpan.FromHours(2);
    
    sat.Location = "location";
    sat.Show();

    Rajouter le partage de photos/vidéos sur les réseaux sociaux

    A l’instar des ShareLinkTask et ShareStatusTask qui permettent, depuis Windows Phone 7.5, de partagere des liens et des statuts sur les réseaux sociaux, la nouvelle ShareMediaTask va permettre de partager des photos et des vidéos.

     

    ShareMediaTask smt = new ShareMediaTask();
    smt.FilePath = "/Assets/ApplicationIcon.png";
    
    smt.Show();

    Profiter du LongListSelector natif

    Ce contrôle, qui était avant fourni dans le Silverlight Toolkit (qui s’appelle maintenant le Windows Phone Toolkit) est maintenant natif. Au menu, le même usage, mais de meilleures performances. Changez juste l’assembly !

    <DataTemplate x:Key="AddrBookItemTemplate">
        <StackPanel VerticalAlignment="Top">
            <TextBlock FontWeight="Bold"  Text="{Binding Name}" />
        </StackPanel>
    </DataTemplate>
    
    <DataTemplate x:Key="AddrBookGroupHeaderTemmplate">
        <Border Background="Transparent" Padding="5">
            <Border Background="{StaticResource PhoneAccentBrush}" BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="2" Width="62" 
        Height="62" Margin="0,0,18,0" HorizontalAlignment="Left">
                <TextBlock Text="{Binding Key}" Foreground="{StaticResource PhoneForegroundBrush}" FontSize="48" Padding="6" 
        FontFamily="{StaticResource PhoneFontFamilySemiLight}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
            </Border>
        </Border>
    </DataTemplate>
    
    <phone:JumpListItemBackgroundConverter x:Key="BackgroundConverter"/>
    <phone:JumpListItemForegroundConverter x:Key="ForegroundConverter"/>
    <Style x:Key="AddrBookJumpListStyle" TargetType="phone:LongListSelector">
        <Setter Property="GridCellSize"  Value="113,113"/>
        <Setter Property="LayoutMode" Value="Grid" />
        <Setter Property="ItemTemplate">
            <Setter.Value>
                <DataTemplate>
                    <Border Background="{Binding Converter={StaticResource BackgroundConverter}}" Width="113" Height="113" Margin="6" >
                        <TextBlock Text="{Binding Key}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" FontSize="48" Padding="6" 
            Foreground="{Binding Converter={StaticResource ForegroundConverter}}" VerticalAlignment="Center"/>
                    </Border>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>

     

    <phone:LongListSelector x:Name="lls" 
                            GroupHeaderTemplate="{StaticResource AddrBookGroupHeaderTemmplate}"
                            ItemTemplate="{StaticResource AddrBookItemTemplate}"
                            JumpListStyle="{StaticResource AddrBookJumpListStyle}"
                            LayoutMode="List"
                            HideEmptyGroups="True"
                            IsGroupingEnabled="True" />

    Comment gérer proprement les nouvelles résolutions ?

    Les terminaux Windows Phone 7 et 7.5 n’avaient qu’une seule définition : WVGA, soit 800x480. Avec Windows Phone 8, les fabricants ont la possibilité d’utiliser 2 nouvelles définitions en plus : WXGA (1280x768) et 720p (1280x720). Dans le cas de la première, on garde le même ratio largeur/hauteur, mais pas dans le second ! Il va donc y avoir une petite bande noire en haut de l’écran (de 53px) si vous n’adaptez pas votre layout dynamiquement (la feinte principale consistant à utiliser des "*" et des "Auto" dans les propriétés des tailles de vos contrôles. Une page de la documentation est dédiée à ce sujet et vous permettra de comprendre ce qu’il faut faire pour tirer parti de toutes les résolutions au mieux :

    Multi-Resolution Apps for Windows Phone

    Pour ce qui est des assets graphiques, (images, etc) vous avez la possibilité de les resizer dynamiquement (dans ce cas je vous conseille de les prévoir pour la résolution 1280x768 et faire du downscaling plutôt que l’inverse), ou bien d’utiliser un petit helper qui permet de savoir sur quelle image se binder en fonction de la résolution :

    Une classe statique, ResolutionHelper, qui retourne de manière lisible la définition de l’écran :

    public enum Resolutions { WVGA, WXGA, HD720p };
    
    public static class ResolutionHelper
    {
        private static bool IsWvga
        {
            get
            {
                return Application.Current.Host.Content.ActualHeight == 800
                && Application.Current.Host.Content.ScaleFactor == 100;
            }
        }
    
        private static bool IsWxga
        {
            get
            {
                return Application.Current.Host.Content.ScaleFactor == 160;
            }
        }
    
        private static bool Is720p
        {
            get
            {
                return Application.Current.Host.Content.ScaleFactor == 150;
            }
        }
    
        public static Resolutions CurrentResolution
        {
            get
            {
                if (IsWvga) return Resolutions.WVGA;
                else if (IsWxga) return Resolutions.WXGA;
                else if (Is720p) return Resolutions.HD720p;
                else throw new InvalidOperationException("Unknown resolution");
            }
        }
    }

    Ensuite une classe sur laquelle l’interface pourra se binder et qui renverra l’image adaptée :

    public class MultiResImageChooser
    {
        public Uri BestResolutionImage
        {
            get
            {
                switch (ResolutionHelper.CurrentResolution)
                {
                    case Resolutions.HD720p:
                        return new Uri("/Assets/ResolutionDependent/720x1280.jpg", UriKind.Relative);
                    case Resolutions.WXGA:
                        return new Uri("/Assets/ResolutionDependent/768x1280.jpg", UriKind.Relative);
                    case Resolutions.WVGA:
                        return new Uri("/Assets/ResolutionDependent/480x800.jpg", UriKind.Relative);
                    default:
                        throw new InvalidOperationException("Unknown resolution type");
                }
            }
        }
    }

    Et pour finir, dans l’interface, instancier cette classe sous forme d’une StaticResource et se binder sur le champ approprié :

    <phone:PhoneApplicationPage.Resources>
        <helpers:MultiResImageChooser x:Key="MultiResImageChooser" />
    </phone:PhoneApplicationPage.Resources>
    <
    Image Source="{Binding BestResolutionImage, Source={StaticResource MultiResImageChooser}}"/>

    Enfin, pour ce qui est du SplashScreen, il suffit de le mettre en 3 versions (pour les 3 résolutions) dans le XAP avec la convention de nommage suivante :

    • SplashScreenImage.Screen-WXGA.jpg
    • SplashScreenImage.Screen-WVGA.jpg
    • SplashScreenImage.Screen-720p.JPG

     

    Et le système s’en sortira tout seul !

    Passer à Nokia Maps

    Si vous utilisez le contrôle Map, vous pouvez profiter de la qualité des cartes vectorielles de Nokia Maps quel que soit la marque du téléphone de votre utilisateur, en quelques étapes très simples :

    1. Migrer votre projet à Windows Phone 8
    2. Enlever la référence à l’assembly Bing Maps et changer les namespaces là où ça s’impose
    3. Rajouter la capability « ID_CAP_MAP » dans votre manifest
    4. Recompiler

     

    Pas besoin de changer le code, sauf peut-être pour enlever la clef d’API ;)

    Sachez que les launchers BingMapsTask et BingMapsDirectionTask ouvriront également automatiquement Nokia Maps et non plus Bing Maps.

    Vous pouvez également profiter des nouveaux launchers MapsTask, MapsDirectionTask, et MapsDownloadTask,  qui offrent respectivement l’accès à l’application Nokia Maps, au guidage tour-par-tour, et au téléchargement de cartes pour une utilisation offline. Un exemple avec la MapsTask :

    MapsTask mt = new MapsTask();
    mt.ZoomLevel = 15;
    mt.SearchTerm = "Pizza";
                
    mt.Show();

    Rajouter la reconnaissance et la synthèse vocale

    Avec la reconnaissance vocale, vous allez pouvoir demander à l’utilisateur de parler à votre application, et récupérer le texte déduit par le moteur intégré à Windows Phone. La synthèse vocale, quant à elle, vous permettra de faire lire à l’application du texte, ce qui améliorera l’accessibilité de votre application.

    Reconnaissance vocale : avec l’interface standard, ou la vôtre !

    Voici comment utiliser l’interface graphique du système pour lancer la reconnaissance vocale :

    // Create an instance of SpeechRecognizerUI.
    var speechRecognizerWithUI = new SpeechRecognizerUI();
    
    // Start recognition (load the dictation grammar by default).
    SpeechRecognitionUIResult recoResult = await speechRecognizerWithUI.RecognizeWithUIAsync();
    
    // Do something with the recognition result.
    tbSpeechRecognized.Text = recoResult.RecognitionResult.Text + " || confidence: " + recoResult.RecognitionResult.TextConfidence;

    Vous pouvez également lancer la reconnaissance vocale avec votre propre interface, mais attention à bien guider l’utilisateur ! Voici un exemple minimaliste, avec une boite de message indiquant juste que la reconnaissance vocale va démarrer :

    if (MessageBox.Show("Recognize?", "SpeechRecognizer", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
    {
        speechRecognizer = new SpeechRecognizer();
        var recoResult = await speechRecognizer.RecognizeAsync();
        tbSpeechRecognized.Text = recoResult.Text + " || confidence: " + recoResult.TextConfidence;
    }
    Synthèse vocale : simple comme bonjour ;)

    Pour vocaliser du texte, il suffit de le passer en argument à une instance de la classe SpeechSynthesizer, en ayant précisé la voix à utiliser… sachant que l’utilisateur peut choisir une langue dans les paramètres du téléphone indépendamment de la langue de son interface graphique. Voici un petit exemple qui lit le contenu d’une TextBox :

    // Initialize the SpeechSynthesizer object.
    SpeechSynthesizer synth = new SpeechSynthesizer();
    
    // Query for a voice that speaks French.
    var Voices = from voice in InstalledVoices.All
                    where voice.Id == (lbxVoices.SelectedItem as VoiceInformation).Id
                    select voice;
    
    // Set the voice as identified by the query.
    synth.SetVoice(Voices.ElementAt(0));
    
    await synth.SpeakTextAsync(tbxSpeech.Text);

    L’association avec des extensions de fichier et des schémas d’URL

    Voici une nouvelle option qui permettra à d’autres applications de lancer directement la vôtre, et d’avoir vos propres formats de fichier pour échanger des données d’un utilisateur à un autre.

    S’associer avec des extensions de fichiers

    Pour s’associer avec une extension, il faut signaler au système qu’on a cette capacité : cela se passe évidemment dans le manifest de l’application, dans lequel il faut rajouter, dans la partie extensions :

    <FileTypeAssociation Name="Windows Phone SDK test file type" TaskID="_default" NavUriFragment="fileToken=%s">
      <Logos>
        <Logo Size="small">/Assets/apitests-small-33x33.png</Logo>
        <Logo Size="medium">/Assets/apitests-medium-69x69.png</Logo>
        <Logo Size="large">/Assets/apitests-large-176x176.png</Logo>
      </Logos>
      <SupportedFileTypes>
        <FileType ContentType="application/text">.apitests</FileType>
      </SupportedFileTypes>
    </FileTypeAssociation>

    Quand un fichier est téléchargé, par le navigateur, par email ou par une autre application, et que l’utilisateur tente de l’ouvrir en tapant sur l’icône de celui-ci (fournie, au passage, également par votre application), le système lancera votre application, avec en paramètre, un « token » permettant de récupérer ce fichier. La bonne pratique est donc de vérifier, en utilisant un UriMapper, si un nom de fichier est passé en paramètre au lancement pour éventuellement rediriger vers la page idoine, et l’ouvrir.

    class ApiTestsUriMapper : UriMapperBase
    {
        private string tempUri;
    
        public override Uri MapUri(Uri uri)
        {
            tempUri = System.Net.HttpUtility.UrlDecode(uri.ToString());
            
            if (tempUri.Contains("/FileTypeAssociation")) // File association launch
            {
                // Get the file ID (after "fileToken=").
                int fileIDIndex = tempUri.IndexOf("fileToken=") + 10;
                string fileID = tempUri.Substring(fileIDIndex);
    
                // Get the file name.
                string incomingFileName = SharedStorageAccessManager.GetSharedFileName(fileID);
    
                // Get the file extension.
                int extensionIndex = incomingFileName.LastIndexOf('.');
                string incomingFileType =
                    incomingFileName.Substring(extensionIndex).ToLower();
    
                // Map the .apitests extension to the right page.
                switch (incomingFileType)
                {
                    case ".apitests":
                        return new Uri("/Pages/FileAssociationPage.xaml?fileToken=" + fileID, UriKind.Relative);
                    default:
                        return new Uri("MainPage.xaml", UriKind.Relative);
                }
            }
            // Otherwise perform normal launch.
            return uri;
        }
    }
    

    Une fois dans la page, il faut utiliser les APIs SharedFolder pour récupérer le fichier passé en paramètre :

    protected async override void OnNavigatedTo(NavigationEventArgs e)
    {
        try
        {
            var fileToken = NavigationContext.QueryString["fileToken"];
            this.fileName = SharedStorageAccessManager.GetSharedFileName(fileToken);
                    
            var storageFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
                    
            var localFile = await SharedStorageAccessManager.CopySharedFileAsync(storageFolder, this.fileName, NameCollisionOption.ReplaceExisting, fileToken);
    
            using(var content = await localFile.OpenReadAsync())
            {
                using (DataReader dr = new DataReader(content))
                {
                    await dr.LoadAsync((uint)content.Size);
                    fileContent = dr.ReadString((uint)content.Size);
                }
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
        finally
        {
            base.OnNavigatedTo(e);
        }
    }
    
    S’associer avec des schemas d’URI

    L’association avec des schémas d’URI fonctionne sur le même principe que l’association avec des extensions de fichier. On déclare le support dans le manifest :

    <Protocol Name="apitests" NavUriFragment="encodedLaunchUri=%s" TaskID="_default" />
    

    Puis on utilise un UriMapper pour capturer le lancement éventuel avec une URI en paramètre, afin de le traiter :

    class ApiTestsUriMapper : UriMapperBase
    {
        private string tempUri;
    
        public override Uri MapUri(Uri uri)
        {
            tempUri = System.Net.HttpUtility.UrlDecode(uri.ToString());
            
    if (tempUri.Contains("apitests:UriAssociation?Parameter=")) // URI assocation launch
            {
                // Get the category ID (after "CategoryID=").
                int paramIndex = tempUri.IndexOf("Parameter=") + 10;
                string param = tempUri.Substring(paramIndex);
    
                // Map the show products request to ShowProducts.xaml
                return new Uri("/Pages/UriAssociationPage.xaml?Parameter=" + param, UriKind.Relative);
            }
    
            // Otherwise perform normal launch.
            return uri;
        }
    
    }
    

    Une fois la page chargée, il suffit de récupérer le paramètre dans le NavigationContext :

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        try
        {
            parameter = NavigationContext.QueryString["Parameter"];
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
        finally
        {
            base.OnNavigatedTo(e);
        }
    }
    
    Lancer une application tierce depuis un fichier ou une URI dans l’application

    Pour lancer une application tierce depuis un fichier ou une Uri, il suffit d’appeler une API du système, qui automatiquement proposera à l’utilisateur de télécharger une appli ayant la capacité d’ouvrir ce type du contenu si il n’y en a pas déjà d’installée. Ça tient en une ligne de code :

     

    await Windows.System.Launcher.LaunchUriAsync(new Uri("apitests:UriAssociation?Parameter=" + tbParameter.Text));
    

    Il est également possible de lancer des pages de l’interface native (paramètres, etc) en suivant le même principe, avec les schémas d’uri réservés du système documentés.

    Devenir une « Lens app » et s’intégrer à l’expérience de prise de photo

    La photo est de plus en plus au cœur de Windows Phone : dorénavant, il existe un petit bouton (matérialisé par deux flèches) dans l’application-bar de l’application photo native, qui permet de choisir une application pour prendre la photo, en y appliquant des filtres par exemple pour modifier l’apparence de la photo, y appliquer un traitement, la partager directement… A vous d’inventer ces nouveaux usages !

    Pour cela, vous devez vous enregistrer cette extension dans votre manifeste, puis vérifier au lancement de l’application, à l’aide d’un UriMapper par exemple, si la chaine de caractère « ViewfinderLaunch » est présente dans l’URL. et si c’est le cas, c’est que votre application est lancée depuis l’appareil photo. Dans ce cas-là, un simple UriMapper vous permettra de rediriger l’utilisateur vers une page de votre application qui appliquera votre traitement, tout en veillant de respecter les recommandations de design spécifique à ce type de page qui sont disponibles ici :

    Lens Design Guidelines for Windows Phone

    Voici l’exemple d’extension à rajouter dans le fichier WMAppManifest.xml :

    <Extension ExtensionName="Camera_Capture_App" ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5631}" TaskID="_default" />
    

    Et celui de l’UriMapper :

     

    PrFont34Bin0BinSub0Frac0Def1Margin0Margin0Jc1Indent1440Lim0Lim1class ApiTestsUriMapper : UriMapperBase
    {
        private string tempUri;
    
        public override Uri MapUri(Uri uri)
        {
            tempUri = System.Net.HttpUtility.UrlDecode(uri.ToString());
            // Look for a URI from the lens picker.
            if (tempUri.Contains("ViewfinderLaunch"))
            {
                // Launch as a lens, launch viewfinder screen.
                return new Uri("/Pages/Lense.xaml", UriKind.Relative);
            }
    
            // Otherwise perform normal launch.
            return uri;
        }
    
    }
    

    En enregistrant cette extension et cet UriMapper, la page « Lense.xaml » contenue dans le dossier « Pages » sera automatiquement lancée, si l’application est lancée depuis l’appareil photo. Attention à ne pas oublier d’inclure également l’iconographie correspondante pour que votre application apparaisse correctement dans la liste des lentilles (le LensPicker) : à savoir :

    Phone resolution

    Icon size (pixels)

    Folder

    File name

    WVGA

    173 x 173

    Assets

    Lens.Screen-WVGA.png

    HD720p

    259 x 259

    Assets

    Lens.Screen-720p.png

    WXGA

    277 x 277

    Assets

    Lens.Screen-WXGA.png

     

    En plus de pouvoir être identifié dans le hub photo comme une application qui peut prendre des photos en entrée (PhotoViewer), ou les partager, vous pouvez maintenant également faire identifier votre application comme éditeur de photo, ou mieux, « appliquant un traitement riche sur une image ». Dans ce cas, les photos que vous aurez prise depuis votre application pourront être rééditez dans votre application directement depuis leur fiche dans le hub photo. Dans tous les cas, cela passe par un ajout d’extension à votre manifest :

    <!-- Extend the photo edit picker. -->
    <!-- This is only for Windows Phone 8 apps. -->
    <Extension ExtensionName="Photos_Extra_Image_Editor" 
                ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5632}" 
                TaskID="_default" />
    
    
    <!-- Integrate as a rich media app. -->
    <!-- This is only for Windows Phone 8 apps. -->
    <Extension ExtensionName="Photos_Rich_Media_Edit" 
                ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5632}" 
                TaskID="_default" />
    

     

    Puis un bout de code dans un UriMapper pour rouvrir la bonne page (vous allez commencer à connaitre le système ;)) :

     

    PrFont34Bin0BinSub0Frac0Def1Margin0Margin0Jc1Indent1440Lim0Lim1// Launch from the photo edit picker.
    // This is only for Windows Phone 8 apps.
    // Incoming URI example: /MainPage.xaml?Action=EditPhotoContent&FileId=%7Bea74a960-3829-4007-8859-cd065654fbbc%7D
    if ((tempUri.Contains("EditPhotoContent")) && (tempUri.Contains("FileId")))
    {
        // Redirect to PhotoEdit.xaml.
        mappedUri = tempUri.Replace("MainPage", "PhotoEdit");
        return new Uri(mappedUri, UriKind.Relative);
    }
    
    
    // Launch from the rich media "Open in" link.
    // This is only for Windows Phone 8 apps.
    // Incoming URI example: /MainPage.xaml?Action=RichMediaEdit&token=%7Bed8b7de8-6cf9-454e-afe4-abb60ef75160%7D
    if ((tempUri.Contains("RichMediaEdit")) && (tempUri.Contains("token")))
    {
        // Redirect to RichMediaPage.xaml.
        mappedUri = tempUri.Replace("MainPage", "RichMediaPage");
        return new Uri(mappedUri, UriKind.Relative);
    }
    

    Pour comprendre tout ce qu’on peut faire avec le hub photo, le mieux est encore de se référer au code d’exemple dédié à ça :

    Photo Extensibility Sample

    Il existe encore plein d’autres sujets et nouveautés, qui méritent des articles à part entière pour en faire le tour : In-App Purchase, Intégration avec le Wallet, Utilisation de NFC que ce soit avec des tags ou bien pour appairer des appareils entre eux et échanger des données… sans compter les nouveautés du support C++ (et l’arrivée de frameworks type Unity ou Havok) ou HTML5 avec IE10 ! Beaucoup d’autres articles en prévision donc ;)

  • Pierre's Embedded and Mobile Blog

    Internationalisez votre application Windows Phone 7

    • 8 Comments

    Le Marketplace de Windows Phone 7 autorise une diffusion mondiale de l’application, mais aussi des diffusions spécifiques dans des marchés localisés. Par exemple vous pouvez avoir envie de diffuser une version Française de votre application sur les terminaux en langue française, et en Allemand sur les terminaux allemands. C’est ce qu’on appelle la localisation. De la même manière, certaines valeurs se représentent différemment d’un pays à l’autre : par exemple la date s’écrit au format mm/jj/aaaa dans les pays anglo-saxons mais jj/mm/aaaa dans les pays francophones. En utilisant les bons outils, on peut indiquer au téléphone d’adapter son affichage en fonction des options choisies par l’utilisateur. C’est ce qu’on appelle la globalisation. Localisation et globalisation forment les deux mamelles de l’internationalisation d’une application, et se servent de plusieurs notions qu’il faut connaitre :

    La notion de culture se réfère à un ensemble de préférences (langage, monnaie, affichage des dates…) qu’on identifie par un code en deux parties : <langage>-<region>. Par exemple, en-us pour anglais-états-unis ou fr-fr pour français-France qui n’est pas la même chose que fr-ca (français-canada). Ce code peut aussi porter le nom de « Locale ».

    Il y a 3 types de « culture » dans le framework : « invariant » qui désigne justement l’absence de culture choisie, «  neutral » qui représente un langage sans association à une région particulière (fr par exemple) et specific qui représente une culture associée à la fois à un langage et une région.

    La classe CultureInfo nous permettra de récupérer les informations à propos de la culture comme celle qui a été paramétrée dans le système, le formatage des différents types de données (date, monnaie, etc) et jusqu’à un calendrier spécifique (et oui, le calendrier hébreu est différent du calendrier japonais !!)

    La notion d’encodage, qui est un outil pour représenter les différents caractères utilisés par une langue de façon numérique : les plus connus sont ASCII, UTF-8, Unicode… Il est bon de savoir que Windows Phone 7 utilise l’Unicode. La classe Encoding vous aidera à vous abstraire des problèmes potentiels d’encodage (par exemple lors du téléchargement de données qui ne sont pas encodées en Unicode)

    La globalisation et l’utilisation de la classe CultureInfo

    La première (et peut-être la seule) chose à savoir est qu’il existe deux instances de la classe CultureInfo dont se sert votre application : il s’agit des propriétés CurrentCulture et CurrentUICulture de l’objet Thread.CurrentThread. Cela permet de savoir par exemple comment un objet de type DateTime sera affiché lors de l’appel à sa méthode ToString(). Pour choisir la façon d’afficher ces types de données d’une manière qui n’est pas celle choisie à l’échelle du système (dans le menu Settings du terminal Windows Phone 7) il suffit de créer une nouvelle instance de la classe CultureInfo en lui passant en paramètre la locale souhaitée (par exemple fr-FR) et assigner cette instance aux propriétés CurrentCulture et CurrentUICulture.

    CultureInfo ci = new CultureInfo("fr-FR");
    Thread.CurrentThread.CurrentCulture = ci;
    Thread.CurrentThread.CurrentUICulture = ci;

    La localisation – bien répartir ses ressources pour supporter proprement différents langages

    Comme par le passé avec le .NET Compact Framework, la première étape de la localisation consiste à utiliser des fichiers de ressources (extension .resx). On peut ajouter ces fichers avec dans le menu « Add -> Add New Item » en choisissant « Resource File ».

    clip_image002

    Attention, pour que le framework retrouve ses petits il faut adopter une stratégie de nommage particulière : d’abord un fichier de ressources par défaut qu’on nomme <NomDuFichierRessources>.resx  puis ensuite les fichiers de ressources localisées qu’on nommera de la façon suivante : <NomDuFichierRessources>.<Locale>.resx.

    Je vous conseille de commencer par créer uniquement le fichier par défaut, y insérer toutes vos chaines de caractères, et ensuite seulement, une fois que toutes les ressources par défaut sont créées, copier/coller et renommer le fichier pour les différentes cultures à supporter, avant de changer le contenu des chaines de caractères : de cette manière vous êtes sûr que toutes les chaines de caractères localisées ont le même nom indépendamment de la culture…

    Il faut ensuite définir la culture par défaut supportée par l’application (celle qui utiliser la fichier <NomDuFichierRessources>.resx). Pour cela dans l’explorateur de solution, cliquez sur le nom du projet et choisissez ses propriétés (Properties). Dans l’onglet Application, cliquez sur le bouton Assembly Information et dans la liste Neutral language choisissez la culture par défaut.

    clip_image004

    Dernière opération « manuelle » s’il en est, fermez votre projet et ouvrez le fichier .csproj dans un éditeur de texte : c’est fait un fichier xml. Trouvez le tag  <SupportedCultures> et ajoutez toutes les locales que votre application doit supporter (y compris la locale par défaut) dans ce tag, séparées par des points-virgules.

    <SupportedCultures>en-US;fr-FR;</SupportedCultures>
    

    Il ne reste plus qu’à utiliser ces fichiers de ressources dans votre projet : là encore, il faut suivre quelques étapes : c’est un peu plus compliqué qu’avec le .NET Compact Framework car il faut que ces chaines de caractères localisées soient accessible à la fois depuis le code et le XAML sous forme de ressources.

    D’abord, ouvrez chacun de vos fichiers ressources et dans la liste « Access Modifier » en haut de l’éditeur sélectionnez la valeur « Public ». Il faut le faire pour chacun des fichiers ressources.

    clip_image006

    Ensuite, il faut créer une nouvelle classe dans votre application (qu’on appellera comme on veut, j’utilise ici « LocalizedStrings » car c’est ce qui est suggéré par la documentation MSDN) dans laquelle on créera une propriété qui reverra vers ces fichiers de ressources fraichement créés : dans le bout de code suivant, LocalizedResources est le nom que j’ai choisi pour mon fichier de ressources, on retrouve donc une classe de ce type dans l’espace de nommage de mon application.

    public class LocalizedStrings
    {
        public LocalizedStrings()
        { }
    
        private static LocalizedResources locTestResources = new LocalizedResources();
        public LocalizedResources LocTestResources { get { return locTestResources; } }
    }

    Après ça, il faut ouvrir le fichier App.xaml et dans la section « <Application.Resources> » il faut rajouter le bout de code suivant :

    <Application.Resources>
        <local:LocalizedStrings xmlns:local="clr-namespace:LocalizationTest" x:Key="LocalizedStrings" />
    </Application.Resources>
    

    Si votre projet dispose de plusieurs fichiers de localisation, il suffit de rajouter des propriétés dans la classe LocalizedStrings.

    Enfin, il n’y a plus qu’à utiliser ces ressources dans le code XAML avec un simple Binding de la façon suivante :

    {Binding Path=LocTestResources.PageName, Source={StaticResource LocalizedStrings}}

    Et dans le code C#, c’est d’une simplicité déconcertante : il suffit d’accéder à la classe LocalizedResources :

    PageTitle.Text = LocalizedResources.PageName;

    Vous voilà maintenant en mesure de supporter plusieurs langages dans une même version de votre application, effort qui saura sans aucun doute séduire vos utilisateurs. Attention cependant à bien réfléchir à vos traductions !!

  • Pierre's Embedded and Mobile Blog

    [Windows Phone 7.5] Ce que signifie la mise à jour 7.1.1 (Tango) du SDK pour votre application

    • 0 Comments

    Une CTP de la version 7.1.1 du SDK Windows Phone “Tango” a été annoncée au Mobile World Congress, et sur le blog de l’équipe Windows Phone. Au menu, plutôt des bonnes nouvelles: la mise à jour “Tango” ouvre la porte à des terminaux plus low-cost, particulièrement utiles dans les pays émergents, ajoute le support d’un certain nombre de langues et de pays pour le marketplace, et cela se traduit par un nombre d’utilisateurs potentiels de vos apps qui grossit d’environ 60% d’un seul coup…

    Parmi les concessions faites sur le châssis hardware pour diminuer les coûts des téléphones, il y a la possibilité de faire des terminaux avec seulement 256Mo de RAM. Ce choix a pour conséquence qu’une application qui consommerait plus de 90Mo de mémoire serait coupée automatiquement… Cela concerne moins de 5% des applications du Marketplace et nous travaillons avec ces développeurs pour les aider à revenir sous cette barre fatidique.

    Pour tester si c’est votre cas, la CTP de la version 7.1.1 du SDK Windows Phone amène une version “bridée” à 256Mo de l’émulateur. il n’y a en gros que ça d’intéressant dans cette version, qui n’est de toutes façons pas encore mure pour publier des applications sur Marketplace (pas de licence dite “go live”). Pas besoin de se jeter dessus, donc, surtout pour votre machine de production, mais si vous êtes dans les 5% à consommer plus de 90Mo, il peut être bon de le tester rapidement.

    Si vous savez que vous avez systématiquement besoin de plus de 90Mo, vous pouvez l’indiquer dans votre manifest, et alors l’application n’apparaitra plus aux utilisateurs des téléphones low-cost, évitant l’expérience “j’installe mais ça plante”.

    Il suffit de rajouter, dans le fichier WMAppManifest.xml, sous les capabilities les 3 lignes suivantes:

    <Requirements>
      <Requirement Name="ID_REQ_MEMORY_90" />
    </Requirements>
    

     

    Si on résume, soit vous utilisez moins de 90Mo, et tout va bien, soit vous utilisez plus de 90Mo de RAM, et là 2 options:

    1. Vous optimisez
    2. Vous décrétez que vous ne voulez pas que votre application soit installable sur les téléphones ne disposant que de 256Mo de mémoire, avec les 3 lignes ci-dessus

     

    Attention aux background agents…

    Votre application n’est pas sensée dépendre d’un background agent pour fonctionner correctement: dès le début, vous deviez prendre en compte le fait que vos utilisateurs peuvent les désactiver manuellement dans le panneau de configuration. Sur les terminaux à 256Mo de RAM, ils ne tourneront pas, de toutes façons. Une raison de plus d’y penser, donc, en créant l’expérience de votre application…

    • Cela ne concerne que les background agents génériques (PeriodicTask/ResourceIntensiveTask).
    • Si vous n’avez pas encadré le lancement de votre background agent dans un block try/catch, une InvalidOperationException sera levée et fera éventuellement crasher votre application… (qui aurait crashé de la même manière si le nombre maximum de background agents sur un terminal “normal” est atteint)… Si vous n’avez pas envisagé ce cas, je vous conseille de le faire Sourire
    • Si vous avez besoin de background agents pour activer des options spécifiques (live-tile, par exemple) essayez de ne proposer cette option que si le terminal dispose de plus de 256Mo… ce qui m’amène à la question suivante:

     

    Comment savoir si un terminal dispose de plus de 256 Mo?

    Réponse: En utilisant les DeviceExtendedProperties:

    try
    {
        long result = 
        (long)DeviceExtendedProperties.GetValue("ApplicationWorkingSetLimit");
    }
    catch (ArgumentOutOfRangeException) 
    {
        // The device has not received the OS update, which means the device is a 512-MB device.
    }

     

    Comment optimiser l’usage de la mémoire?

    La racine de tout ce qui concerne les performances des applications Windows Phone est sur cette page:

     

    Si vous êtes dans le cas d’un jeu en XNA (particulièrement sensible à l’usage de la mémoire) vous pouvez vous tourner vers:

     

    Une session qui a été jouée au Techdays 2012 sur le sujet sera par ailleurs bientôt en ligne…

    Pour conclure, je dirais bien que pragmatiquement à partir du moment où on code propre, et où on avait regardé dès le début les contraintes de certification de Marketplace (qui incluent, depuis la première version, la limite de 90Mo), il n’y aura pas de problème. Et pour ceux qui auraient une situation particulière, lié à un usage spécifique ou à une erreur bénigne dans le code au lancement des background agents, la résolution est facile! A vous de jouer!

    Source: Developping for 256-MB devices sur MSDN

  • Pierre's Embedded and Mobile Blog

    [MIX10] Les outils de développement pour Windows Phone 7 sont disponibles!

    • 3 Comments

    C’est la grosse annonce de la keynote de la conférence MIX à Las Vegas: le kit de développement pour Windows Phone 7 est disponible!! Les points important:

    • Il est entièrement gratuit!
    • Il est basé sur Visual Studio 2010 RC et Expression Blend 4
    • Comme annoncé la semaine dernière, on utilisera Silverlight et XNA pour les applications et les jeux.
    • Un émulateur vous permettra de tester vos applications avant la sortie des terminaux – il supporte même l’accélération 3D! (il est en fait basé sur XDE)
    • Il est disponible sur le portail développeurs Windows Phone 

    Le kit de développement a été conçu pour être accessible et simple: vous pourrez très vite et très simplement faire de belles applications que les utilisateurs apprécieront dès la sortie des premiers téléphones!

    Quelques posts ont déjà fait surface sur les blogs de l’équipe de développement: de la lecture pendant le téléchargement :):

    Et bien sur de la doc disponible immédiatement sur MSDN, et des exemples de code

  • Pierre's Embedded and Mobile Blog

    [Windows Phone 7.5] Protéger les données sensibles dans l’Isolated Storage

    • 0 Comments

    Il arrive que l'’on doive échanger des données sensibles, par exemple à travers du réseau, ou entre des couches applicatives. Pour cela on a accès à toute une couche de sécurité qui est très simple à utiliser et qui inclue les algos les plus classiques, qu’il s’agisse de crypto (AES, RSA etc) ou du hashage (HMAC, SHA1, SHA256…). Cette couche permet de crypter un contenu à partir d’une clef secrète ou d’un couple clef publique / clef privée.

    Mais parfois on veut stocker ces données, et autant on peut utiliser ces algos pour stocker les crypter, on ne peut pas les utiliser pour stocker la clef de cryptage elle-même! Dans ce cas, on a la Data Protection API (DPAPI) qui utilise une clef secrète contenue dans le téléphone, impossible à récupérer et qui permettra de crypter n’importe quel type de contenu. Cette DPAPI est accessible depuis la classe statique System.Security.Cryptography.ProtectedData. Celle ci contient 2 méthodes, Protect et UnProtect, qui agissent tout simplement sur des tableaux de bytes:

    Un exemple de cryptage:

    byte[] dataBytes = System.Text.Encoding.UTF8.GetBytes(data);
    byte[] encryptedData = ProtectedData.Protect(dataBytes, null);

    Et un décryptage, aussi simple!

    byte[] decryptedData = ProtectedData.Unprotect(encryptedData, null);
    result = new string(System.Text.Encoding.UTF8.GetChars(decryptedData));

     

    En tout état de cause, si vous n’avez qu’à stocker des données cryptées et pas forcément à les partager, vous pouvez ne vous servir que de cette classe. Ca simplifie grandement l’écriture de certaines applications comme par exemple les coffres de mots de passe… mais n’oubliez pas de gérer, lors de vos cryptages/décryptages, les tombstoning correctement…  et n’écrivez jamais nulle-part un secret en clair!

  • Pierre's Embedded and Mobile Blog

    [Windows Phone 7] Toutes les nouveautés du SDK de Mango expliquées!

    • 8 Comments

    La future mise à jour de Windows Phone 7, nom de code « Mango », va apporter son lot de nouveautés en termes de fonctionnalités, et pour supporter ça, le SDK s’enrichit considérablement  : au programme, plus de 1500 nouvelles APIs, et pour commencer, le support de Silverlight 4 !! On va pouvoir profiter du multitasking, une base de données locale, des sockets, des nouvelles API pour les capteurs, plus de souplesse sur la gestion des tuiles et des notifications en push, l’intégration de Silverlight et XNA, de la réalité augmentée, l’accès aux contacts et au calendrier… et j’en passe.

    Le multitasking

    Le multitasking était interdit pour les applications tierces dans la première version du SDK, mais avec Mango il y a maintenant des scénarios spécifiques dans lesquels il sera possible de faire tourner du code en background.

    Un autre avantage avec le multitasking est la possibilité de revenir à une application sans temps de chargement. En fait par défaut avec Mango, l’application sera désactivée mais sa mémoire ne sera pas libérée : on dira que l’application sera « dormante ». La mémoire ne seralibérée que si c’est nécessaire, sachant qu’on peut avoir jusqu’à 5 applications dormantes en même temps. En revanche, il est possible qu’à un certain point, l’application soit tombstonée, c’est pouquoi quoi qu’il arrive il faudra faire de la sauvegarde de contexte. En revanche, au chargement, on pourra tester avec une simple API à tester si l’application est dormante ou tombstonée.

    En plus de « fast app switching », les API de multitasking introduisent 3 concepts :

    • Les services
    • Les agents
    • Le background processing « générique »

    Nous allons détailler ces 3 cas de multitasking dans les sous-parties suivantes.

    Les services

    Il devient avec Mango possible de piloter des services du système avec des API : par exemple, des alarmes (comme le réveil), et des reminders (comme ceux du calendrier). Un autre service accessible est la lecture audio en background (par exemple pour les applications radios) qui permettra d’utiliser l’API MediaStreamSource qui permet de customiser le pipeline audio (ce qui inclut la potentielle gestion des DRM ou des protocoles spéciaux). Le dernier service est le transfert de données en background qui permettra de télécharger des données même quand l’application sera dormante ou tombstonée. L’avantage de ce service est qu’il persiste même malgré un redémarrage du téléphone!

    Les agents

    Les agents permettent de faire tourner du code en background, dans un processus différent de l’application.

    On peut faire à peu près tout dans les agents : accéder au réseau, au GPS, mettre à jour les tuiles dynamiques, etc. En revanche évidemment on ne peut pas manipuler d’interfaces graphiques, ni le micro ou la camera.

    Les agents permettent d’ouvrir un certain nombre de scénarios comme la synchro de donnée, le tracking, la localisation sociale, etc.

    Le background processing générique

    Quand l’application ne tourne pas au premier plan (foreground) l’agent devra adopter l’un des deux types suivants :

    - Périodique : Exécute du code pendant 15 secondes toutes les 30 minutes

    - En mode inactif : quand le téléphone est branché sur le secteur, et sur une connexion qui n’est pas cellulaire.

    Les sockets

    Dans la première version du SDK le développeur ne disposait que des canaux http et https pour communiquer entre le téléphone et le cloud. Il sera maintenant possible d’utiliser des sockets, en TCP et en UDP, en Unicast et en multicast. Cette implémentation des sockets est donc elle-même plus riche que celle de Silverlight 4 !! Sur scène Jaime Rodriguez et Scott Guthrie ont démontré un client IRC qui, grâce à une librairie opensource déjà existante, aurait été codée (en tous cas c’est ce que veux la légende) en moins d’une heure ! Mais ce n’est pas la seule chose qu’on aura vu… car Joe Belfiore aura également annoncé Skype…

    Les tuiles et les notifications en push

    Avec la première version du SDK il y avait 2 moyens de manipuler les tuiles : avec des notifications en push, ou à intervalles réguliers avec l’API ShellTileScheduler. Et on avait 3 différents « champs » : le texte, un compteur, et l’image.
    Le SDK Mango introduit un nouveau modèle de programmation des tuiles, le modèle « local » qui permet d’éditer une tuile depuis l’application si elle est en foreground, ou depuis un background agent.

    Une autre nouveauté est de pouvoir avoir plusieurs tuiles par application : depuis l’application on pourra choisir d’afficher différentes tuiles, manipulables individuellement, et qui pourraient mener vers différentes parties de l’application.

    Dernière chose, il sera maintenant possible d’accéder aux deux faces de la tuile pour l’animer sur l’écran d’accueil et fournir plus d’infos aux utilisateurs !

    Les performances ont été grandement améliorées, à la fois entre le serveur et le téléphone, et à l’intérieur du téléphone. Et pour ceux qui se posent la question : non ce n’est pas du polling, oui c’est bien du Push.

    Enfin, la charge « embarquable » dans une notification passe de 1Ko à 4Ko, et le nombre maximal d’applications pouvant utiliser les notifications en push sur un terminal passe de 15 à 50.

    En ce qui concerne les toasts, il va maintenant être possible de « paramétrer » la notification afin de naviguer directement vers un endroit spécifique de l’application si on clique sur le toast.

    Des API d’accès à plus de ressources du téléphone : capteurs, contacts, calendrier…

    En premier lieu, de nouveaux launchers et choosers permettront d’accéder aux contacts, au calendrier, aux adresses des utilisateurs et de lancer l’application Bing Maps y compris pour des itinéraires. Il sera possible de manipuler des « alarmes » et des « reminders » pour enrichir l’expérience de votre application quand elle n’est pas lancée, et s’intégrer encore mieux dans le système. Mais ce n’est pas tout : il y aura également accès à plus de capteurs : la boussole, et même un gyroscope optionnel ! Non seulement aura-t-on accès à ces capteurs, mais aussi à un framework qui permettra de les manipuler et d’en intégrer facilement les données dans l’application. Enfin et ce n’est pas la moindre des nouveautés, les développeurs auront un accès direct à la caméra ! Les exemples de la keynote du MIX tournaient autour du scan de code-barres, mais aussi de la réalité augmentée! Dernier détail… il sera aussi possible de manipuler… les sonneries !

    L’intégration de Silverlight et XNA

    Dans la première version du SDK il fallait choisir entre une application XNA et une application Silverlight, avec Mango, on peut utiliser les deux dans la même application ! Non seulement il sera possible d’ouvrir, depuis une application Silverlight, une « page » qui utilise la game loop et le rendering XNA, mais il sera également possible de superposer des contrôles Silverlight au-dessus d’une scène XNA, et bien entendu, d’avoir des interactions entre les deux ! Je ne sais pas pour vous, mais moi quand je pense à ça et en même temps l’accès direct à la caméra, j’ai une grosse envie de réalité augmentée !

    Pour le fun, ce qui n’ont pas vu la keynote de MIX, vous pourrez la retrouver après l’évènement, vous devriez sauter directement vers 1h25 pour voir la démo énorme de Scott Guthrie à propos du sujet.. une bonne barre de rire en perspective !

    L’amélioration des outils de développement

    Les outils étaient déjà particulièrement sympas avec la v1 du SDK, mais nous avons reçu quelques feedbacks à propos de la simulation de l’accéléromètre et du GPS : avec Mango, ça sera possible !! La nouvelle version des outils incluera des outils pour simuler l’accéléromètre et le GPS dans l’émulateur. Les développeurs auront donc accès à une fenêtre en plus dans l’émulateur qui représentera le terminal en 3D et permettra de le manipuler dans l’espace, et pour le GPS, à une carte qui permettra de simuler des évènements GPS (nouvelle localisation, mais également, un trajet !).

    Une autre grosse demande que nous avons pris en compte est la possibilité d’instrumenter son code pour faire de l’analyse de performances, et directement dans Visual Studio, on pourra lancer une analyse de performance sur les temps d’exécution et les allocations mémoire, lorsque l’application tourne.

    La base de données locale

    Il est des applications qui ont besoin de manipuler de grandes quantités de données : que ce soit des applications avec des structures de données complexes (ce qui est le cas de beaucoup d’applications métiers), ou bien tout simplement avec de grandes quantités de données comme par exemple, une application dictionnaire. Dans ces cas, l’isolated storage, et le stockage de fichiers « à plat » n’est pas une option idéale. C’est pourquoi avec Mango nous rajoutons une base de données locale, et la possibilité d’interagir avec cette base de données avec des requêtes LINQ ! Les scénarios de requêtages vont bien sur être beaucoup plus performant et comme le démontrait Jaime Rodriguez sur scène à la keynote, l’implémentation par exemple de fonctions de recherches sera beaucoup plus simple !! Les fondations de cette base de données et de ce système de requêtage sont bien entendu SQL CE et ADO.NET.

    Il sera possible d’adopter une approche « code first » dans laquelle on créera les objets en code, qu’on « décorera » avec des attributs particuliers qui transformeront le modèle objet en une base de données, avec quelques API simples pour manipuler cette base à la main si besoin.

    Internet Explorer 9

    Le nouveau navigateur du téléphone intègre le support de HTML5, et même l’accélération hardware. Bonne nouvelle le contrôle WebBrowser d’une application Windows Phone se comportera de la même manière. Nous allons pousser les gens a utiliser les spécifications stables d’HTML5, et le navigateur intégrera le support de la geolocalisation par exemple. Comme avec Internet Explorer sur le PC la démarche de Microsoft est de supporter les standards stables qui garantissent l’expérience « same markup » pour tous les terminaux possibles et imaginables.

  • Pierre's Embedded and Mobile Blog

    [Windows Phone 7] 10 trucs pour passer facilement la certification

    • 0 Comments

    Avec les premières phases de certifications qui démarrent, et un an de recul sur la certifications des applications pour Windows Mobile 6.5, on se rend compte que finalement, la très grande majorité des échecs sont liés à des fautes d’inattention… ou un manque de lecture de la documentation ! Voici donc les 10 points à avoir toujours en tête lorsqu’on prépare la certification :

    1/ LISEZ LA DOC !!!!! tout est dans la documentation. Prendre une petite demi-heure pour lire et comprendre cette documentation vous sauvera peut-être d’un échec cuisant. Mon conseil : annotez la au fur et à mesure de votre lecture. Assurez vous d’avoir la dernière version du document, qu’on trouve sur le portail http://developer.windowsphone.com. Tout y est détaillé. Lisez la doc. (ou je me fâche !!)

    2/ Soignez l’iconographie. D’abord parce que votre iconographie (icônes et screenshots) représentent votre application sur Marketplace et dans le terminal de vos utilisateurs, mais aussi parce qu’une erreur d’iconographie peut vous coûter votre certification.

    • Cas de test 4.6 : les screenshots doivent provenir d’une capture d’écran du téléphone ou de l’émulateur, doivent avoir une résolution de 480x800 pixels et avoir les proportions largeur/hauteur normales de l’application sur le terminal.
    • Cas de test 4.5 : N’utilisez pas les icônes par défaut de Windows Mobile ou Windows Phone

    - Inclure une image de fond au format « panorama » n’est pas nécessaire, mais permettra à Microsoft le cas échéant de « skinner » Marketplace aux couleurs de votre application, et donc vous mettre à l’honneur. Pourquoi refuser ?

    3/ Informations de support (cas de test 5.6) : votre application doit avoir un nom et un numéro de version, et doit inclure des informations de support (url de site web, email) facilement découvrables par l’utilisateur final

    4/ Notifications de type Toast (cas de test 6.2)

    • Il faut fournir à l’utilisateur la possibilité de désactiver les notifications
    • Au premier usage de l’API HttpNotificationChannel.BindtoShellToast, l’application doit demander explicitement à l’utilisateur l’autorisation de recevoir des notifications.

    5/ Applications continuant leur exécution quand l’écran est verrouillé (cas de test 6.3)

    • Ce cas s’applique uniquement aux applications qui continuent à tourner quand l’écran est verrouillé, et ne s’applique pas aux applications dans l’état « suspended ».
    • Il faudra demander à l’utilisateur explicitement la permission d’avoir ce comportement lors du premier appel à l’API ApplicationIdleDetectionMode

    6/ Utilisation du bouton Back – cas de test 5.2.4 : voici un exemple typique d’échec qui aurait été simple à traiter : appuyer sur le bouton back doit ramener à la page précédente de l’application, pas la quitter (sauf si on est sur la première page) ou faire apparaitre un menu ou une boite de dialogue – le plus simple : gardez le comportement par défaut !!

    7/ Thèmes : cas de test 5.1.1 : Utilisez les ressources associées au thème du téléphone plutôt que de hardcoder les couleurs … et risquer de tomber dans un cas ou l’application n’apparaitra pas correctement quand le thème choisi par l’utilisateur est le thème « light » : Et donc testez aussi dans ce mode là avant de soumettre l’application !

    8/ Support des langues : Faites en sorte que la description et le texte dans l’application et dans la marketplace s’affichent dans le langage choisi par l’utilisateur (histoire d’éviter un menu en allemand pour un utilisateur français, et tant qu’on y est, évitez les traductions automatiques débiles du type « la tasse mondiale » quand on parle de « world cup »…

    9/ Erreur à l’upload du XAP : A l’upload du XAP un outil va vérifier son intégrité – l’erreur la plus commune est « Your XAP is missing an interop manifest » : dans votre manifest, spécifiez bien les paramètres d’interop, car même si votre compte développeur n’utilise pas l’interop (privilège réservé aux opérateurs), le message sera généré.

    10/ Version des developer tools : j’enfonce encore une porte ouverte, mais avant de faire certifier votre application, installez, testez et packagez la avec les outils de dev RTM… les applications faites avec des versions précédentes (CTP et beta, publiques et privées) ne passeront pas !

  • Pierre's Embedded and Mobile Blog

    [Techdays 2012] The Geek is in da House : le webcast, les slides et le code de la session

    • 0 Comments

    Suite à cette session mémorable dont le but était d’exposer les “petits projets” de quelques geeks bien fondus pour leur maison, voici le contenu de la session… le webcast, les slides, le code!

    Le Webcast

    image

    Pour retrouver la session il faut cliquer sur le 4ème chapitre dans la barre de défilement Sourire

    Contrôler son portail avec son téléphone (Fabien Tanquerel)

    Fabien (@ftanquerel) de D-Cube a commencé par nous faire une petite démonstration d’interfaçage avec du hardware à base de Netduino Plus : il nous explique le matériel utilisé, et nous fournit slides et codes sources sur le blog D-Cube

    Installer une infrastructure domotique pour pas cher et la piloter avec… n’importe quoi (Salah Amer)

    Salah (@proteus91300) nous montre quel matériel utiliser pour automatiser sa maison en X10 et le service WCF qu’il a développé pour interfacer sa maison avec son téléphone, son Nao, Kinect… bref un peu tout. Bonus à la fin, il nous parle de proteus, sa salle serveur chez lui, avec robot lego monté sur rails pour allumer/éteindre les machines, et serrure biométrique…  et vous pouvez retrouver à la fois ses slides et son code source sur cet article de son blog.

    Automatiser son climatiseur avec l’internet des objets… (moâ)

    Je montre dans cette partie comment on utilise un Netduino Plus et OpenSenSe pour mettre son climatiseur sur internet et pouvoir avoir des relevés de température réguliers, une automatisation de son démarrage en fonction de la chaleur dans la pièce, et un contrôle à distance. Les slides et le code sont sur ce skydrive là!

    L’infrastructure de streaming vidéo geek

    David (@deltakosh) et Stan (@squastana) ont fait des recherches avancées, field-testés et wife-proofées pour se débarasser de leurs dvds acquis légalement en les stockant sans pertes de qualité ou de données dans des gros NAS, et conçu à base de matériel (peu corporate on en conviendra) un mediacenter ultime et pas cher. Leur présentation est disponible dans ce même skydrive

    Pour terminer, je dirai que le futur de cette session est à écrire! on peut garder ce format avec d’autres projets, on peut imaginer des sessions “geek in the office”, “geek in the car”… j’ai même eu une proposition “geek in the kitchen” Sourire Alors lancez-vous, bidouillez, codez, racontez nous vos projets, faites vous connaitre, bref, partageons!

  • Pierre's Embedded and Mobile Blog

    [Windows Phone 7] Le Framework de Navigation

    • 0 Comments

    La plupart des applications mobiles sont (logiquement) multipages : que ce soit sur un contrôle de type pivot, panorama, ou une simple navigation entre des pages, il faut prévoir la meilleure façon possible pour l’utilisateur de naviguer entre les pages.

    La base de la navigation

    Le framework de navigation introduit dans Silverlight 3 a été repris dans Windows Phone 7. On dispose de deux types d’objets : PhoneApplicationFrame et PhoneApplicationPage. Chaque application possède une unique PhoneApplicationFrame et de multiples PhoneApplicationPages.

    Dans une application WindowsPhone, chaque PhoneApplicationPage est en général contenue dans sa propre page en XAML. Pour naviguer d’une page à l’autre, il suffit d’appeler la méthode Navigate() de la classe statique NavigationService, qui est contenue dans l’espace de nommage Microsoft.Phone.Navigation.

    La base de la navigation se fait donc très simplement de la façon suivante :

    NavigationService.Navigate(new Uri("/DetailsPage.xaml", 
    UriKind.Relative));

    Le passage d’argument entre les pages

    Il arrive (c’est même fréquent) qu’on doive passer des arguments entre les pages. Il y a pour cela deux manières de procéder.

    La première et la plus simple est de créer un objet qu’on assignera au datacontext de la page vers laquelle on navigue. On pourra ensuite directement binder les éléments de la page cible sur cet objet :

    _selectedItem = (sender as ListBox).SelectedItem;
    FrameworkElement root = Application.Current.RootVisual 
        as FrameworkElement;
    root.DataContext = _selectedItem;

    La seconde manière consiste à passer des arguments directement dans l’URI de la page cible. Dans ce cas, dans la page cible, il est possible de récupérer les arguments en utilisant une autre classe statique, le NavigationContext, et notamment sa méthode QueryString. Voici un exemple :

    Dans la page principale :

    NavigationService.Navigate(new Uri("/DetailsVille.xaml?Ville="
            + ((Ville)listBox1.SelectedItem).Nom + "&Pays=" 
            + ((Ville)listBox1.SelectedItem).Pays, 
            UriKind.Relative));

    Et dans la page cible :

    string ville = this.NavigationContext.QueryString["Ville"];
    stringpays = this.NavigationContext.QueryString["Pays"];

    Si l’on veut utiliser des URL « simples » ou de la logique de routage dans le code, il est possible d’utiliser des UriMappers pour refactorer les URL des pages au moment de la navigation. Voici un exemple simple (tiré de la librairie MSDN) qui illustre bien le principe des UriMapper :

    <navigation:Frame x:Name="ContentFrame" 
                      Style="{StaticResource ContentFrameStyle}"
    Source="/Home" Navigated="ContentFrame_Navigated" 
                      NavigationFailed="ContentFrame_NavigationFailed">
        <navigation:Frame.UriMapper>
            <uriMapper:UriMapper>
                <uriMapper:UriMapping Uri="" 
                                      MappedUri="/Views/Home.xaml"/>
                <uriMapper:UriMapping Uri="/{pageName}" 
                                      MappedUri="/Views/{pageName}.xaml"/>
            </uriMapper:UriMapper>
        </navigation:Frame.UriMapper>
    </navigation:Frame>
    

    La gestion du bouton back

    La plupart du temps, on peut laisser le système gérer le bouton back. Il reviendra automatiquement en arrière dans la pile des pages. Ceci étant dit, il peut être utile de capturer cet évènement, afin par exemple de reforger une url avec des arguments pour la page appelante, ou pour démarrer le storyboard d’une animation de changement de page.

    Dans le handler de l’évènement PhoneApplicationPage_BackKeyPressed, il faut commencer par annuler la navigation par défaut, avant de rajouter son code. Voici un exemple de gestion de l’appui sur le bouton back, tiré du template d’application Windows Phone List Application

    private void PhoneApplicationPage_BackKeyPress(object sender, 
        System.ComponentModel.CancelEventArgs e)
    {
        // Cancel default navigation
        e.Cancel = true;
        // Do page transition animation
        PageTransitionDetails.Begin();
    }

    Les différentes manières d’agencer les pages

    On peut imaginer plusieurs manières d’agencer les pages d’une application : le plus simple étant justement de ne pas les agencer. Une page remplace l’autre à l’écran et on navigue simplement entre elles de manière plus ou moins linéaire avec des boutons et des menus.

    Il est également possible avec Windows Phone 7 d’utiliser d’autres agencements pour vos données, que ce soit sous forme de page ou pas. Les deux contrôles d’agencement de pages les plus connus sont le pivot (comparable à un TabControl) et le panorama (dont les meilleurs exemples sont les hubs)

    Il convient cependant de ne pas utiliser ces contrôles n’importe comment : sans qu’il y ait de règle établie, on peut d’une manière générale considérer :

    - Le pivot est un moyen efficace d’afficher des données, alors que le panorama est un moyen immersif d’afficher du contenu

    - Le panorama peut être considéré comme la « couverture » de votre application, comme la couverture d’un magazine

    - Un pivot peut servir de filtre, un panorama peut servir pour naviguer à travers un contenu « éclaté » sur plusieurs vues, et de préférence varié.

    - Les panoramas sont faits pour attirer l’utilisateur à l’intérieur de l’application. Les pivots pour séparer les données en catégories, tris, etc.

  • Pierre's Embedded and Mobile Blog

    [Windows Phone 7] Adopter ou ne pas adopter “Metro”?

    • 0 Comments

    Indubitablement Windows Phone 7 arrive sur le marché avec une approche particulière de l’ergonomie du téléphone, avec la mission avouée de “placer l’utilisateur au centre du téléphone”. Loin de la liste d’icône qu’on peut retrouver chez certains concurrents (bien qu’il y en ait une quand même), l’écran d’accueil (start screen) et les hubs (ou panoramas) souhaitent glorifier le contenu, se débarrassant de tout élément “inutile” d’interface graphique. Quand on est développeur, on entend les designers parler de choses bizarres et leur donner une utilité ou une mission incompréhensible: qu’est-ce que “l’espace négatif”? comment “célébrer la typographie”? comment fait-on pour “délecter l’utilisateur par l’usage du mouvement”?!

    Qu’on aime ou qu’on déteste les idées qui construisent l’interface de Windows Phone 7, il faut se familiariser avec son “langage de design”, nom de code Metro. Même si l’on peut choisir de l’adopter complètement, d’en récupérer une partie des idées ou d’ignorer ses préceptes (Silverlight permet de faire exactement ce qu’on veut avec les éléments graphiques et ergonomiques) l’utilisateur va s’habituer à l’ergonomie de son Windows Phone 7 : ne pas porter attention, ou mal comprendre “Metro”, c’est risquer de créer des glitchs, des incohérences, des ruptures dans le processus de compréhension ou de navigation dans l’interface: dans le pire des cas, l’utilisateur est dérouté par votre application et ne l’utilise pas, voire l’évalue avec une mauvaise note dans le Marketplace.

    Pour autant nous n’avons pas tous la chance de travailler avec des designers, et en tant que développeurs nous avons rarement le bagage culturel et technique, l’état d’esprit, le background pour comprendre et concevoir une “interface naturelle”, qui est le propre de Windows Phone 7. C’est pour ça que l’équipe des designers Windows Phone 7 publie de nombreux documents et webcasts à propos des principes de “Metro”. Il faut s’astreindre à les regarder, les étudier, y réfléchir et les revoir encore, car c’est dans ces ressources qu’on trouve les petites phrases, les éléments clefs qui nous aident à comprendre ce qu’on peut faire bien ou mal. Voici quelques-unes de ces ressources indispensables:

    Voici quelques exemples de “prises de conscience” que j’ai eu en regardant ces webcasts et en repassant sur les documents:

    On ne doit concevoir le “panorama” de son application qu’en dernière étape! Le panorama est un moyen d’encourager l’utilisateur à plonger dans l’application, et ne doit présenter que des bribes d’informations qui résonnent naturellement auprès de l’utilisateur – les derniers usages qu’il a fait de l’application, le contenu récemment publié, les images les plus consultées… A concevoir le panorama en premier, on le surcharge et on rend l’application incohérente: c’est comme si on voulait créer un journal et qu’on commençait par concevoir la couverture! D’abord on fait les articles, ensuite on choisit ce qu’on met en couv’!

    Le contrôle pivot vous permet de présenter de l’information sous forme “classée”: que ce soit la même information ou une information différente: par exemple des points d’intérêts sous forme de liste dans une page du pivot, et sur une carte dans une autre page. N’hésitez pas à proposer plusieurs vues de la même information: votre application n’en sera que plus riche et vous laisserez à l’utilisateur le choix de l’usage.

    Tout élément de mon interface est “touchable”: car l’écran entier est tactile: chaque interaction de l’utilisateur avec son écran doit lui renvoyer un feedback: que ce soit pour se déplacer dans une page, pour agrandir une photo ou pour mettre à jour un statut, il faut pour chaque élément se poser la question “pourquoi l’utilisateur voudrait-il toucher cet élément? quel doit être le feedback?”

    Ce qui est évident à l’usage (le téléphone en main) n’est pas forcément visuellement évident à première vue: par exemple, le vide est une information en lui-même… Entendu à maintes reprises à propos de l’écran d’accueil: “pourquoi laisser une bande noire sur le coté droit de l’écran d’accueil? c’est de l’espace perdu!!”. Et après avoir laissé l’utilisateur toucher le téléphone “ha mais.. il y a quelque chose à droite de cette zone!” si cette zone non utilisée n’était pas là, comment naviguerait-on vers la liste d’icône? Il faut comprendre que Metro, c’est une interface “en mouvement” et qu’une vue statique de celle-ci (comme de votre application) ne reflète pas forcément l’usage.

    Les transitions visuelles doivent être pensées “dans le sens du mouvement” : si par exemple l’utilisateur change de page en faisant un geste de la droite vers la gauche, alors l’animation doit suivre, immédiatement et sans délai, le geste de l’utilisateur, de la droite vers la gauche. Et le retour à la page précédente doit se faire avec une animation de la gauche vers la droite. Le dire parait une évidence mais à l’implémentation on retrouve de nombreux développeurs faire la même animation de changement de page que ce soit pour aller chercher une nouvelle information ou pour revenir en arrière. Dommage! Qu’une transition soit jolie, c’est bien, qu’elle soit en plus utile et qu’elle permette de se repérer dans l’interface, c’est mieux!!

    Et des exemples comme ça, il y en a à foison: bien espacer les éléments pour qu’ils soient facilement manipulable au doigt, utiliser le “hors champ” pour suggérer qu’il y a du contenu en dehors du formulaire (comme dans les panoramas) etc.

    Dernier point à propos de Metro – je faisais la démonstration de l’interface à une designer, comme d’habitude en expliquant chaque étape et le rôle des différents éléments graphiques, transitions, etc… jusqu’au moment ou elle m’a gentiment fait remarquer que je n’avais pas besoin de l’expliquer parce que c’était “naturel”. Je vous laisserai donc avec ça, et en paraphrasant Bill Buxton: quoi que vous fassiez pour votre interface, faites en sorte qu’elle soit “naturelle”!

  • Pierre's Embedded and Mobile Blog

    [Windows Phone 7.5] Tutoriel simple sur la réalité augmentée, partie 1: les concepts, et les maths

    • 0 Comments

    Avec la version 7.1 du SDK Windows Phone (Mango), l’intégration de la réalité augmentée dans les applications mobiles va devenir beaucoup plus facile : de nouveaux composants font leur apparition et sont conçus pour rendre très simple le développement de ce type d’interface. Mais d’abord, intéressons-nous à ce qu’est la réalité augmentée, et aux concepts qu’il faut maitriser avant de s’attaquer au code.

    Le principe de base de la réalité augmentée est d’afficher en surimpression d’une image « réelle » (issue d’une caméra par exemple) des informations purement digitales. Les deux usages les plus courant de la réalité augmentée sont :

    • l’utilisation du téléphone en mode « viewfinder », par exemple pour repérer les directions de points d’intérêt autour de l’utilisateur qui pointe le téléphone dans une certaine direction.
    • L’utilisation du téléphone pour capter un « tag » ou un point visuel reconnaissable, sur lequel on affiche des informations en rapport avec ce point : c’est le cas de nombreux jeux par exemple qui se servent de ce principe pour intégrer le gameplay dans un environnement réel.

    Dans cet série d’articles, nous allons nous intéresser au premier cas d’utilisation, à savoir le téléphone en mode « viewfinder ».

    Les concepts de 3D et de mathématiques à comprendre

    La première chose à comprendre, c’est qu’il nous faut appliquer un certain traitement aux points d’intérêts : en effet nous voulons représenter dans un espace 2D (l’écran du téléphone) un certain nombre d’informations liées à des coordonnées 3D (le monde réel : latitude, longitude, distance, etc). Il faut donc projeter ces points sur l’écran. Et finalement, projeter dans un espace en 2D des points d’un monde en 3D, on le fait depuis longtemps dans le monde des jeux vidéos. On va donc reprendre le vocabulaire de ce monde :

    • L’œil de l’utilisateur correspond à une caméra : c’est un point, qui dispose de coordonnées dans un monde en 3D.
    • Le viewport, c’est l’écran du téléphone : la surface sur laquelle on va dessiner les éléments, s’ils sont dans une certaine zone.
    • Cette certaine zone s’appelle le frustum, et il a la forme d’une pyramide tronquée au sommet  (le sommet étant l’œil). C’est la zone qui est comprise entre l’écran, et une limite au loin qu’on appelle le far plane (l’écran devenant le near plane).

     

    Lorsqu’un objet sera contenu dans le frustum alors il sera projeté sur le viewport dans la direction de l’œil de l’utilisateur.

    Pour simplifier un schéma pas forcément trivial, on considérera que l’œil de l’utilisateur est à une distance fixe du viewport, dans l’axe de la normale à son centre (le vecteur qui part du centre du rectangle, perpendiculairement au plan du rectangle). Il n’existe de toute façon pas de moyen simple de savoir où se trouve l’œil de l’utilisateur par rapport à l’écran… A moins de faire du face tracking avec la caméra frontale, ce qui n’est pas l’objectif de cet article.

    Tout cela peut se résumer à ce schéma :

    Frustum

    Cette projection doit bien entendu également tenir compte de la position du téléphone : en effet, dans une localisation d’un objet en 3D (donc potentiellement, plus haut ou plus bas que l’utilisateur) il faut tenir compte de la position du téléphone (qu’il faut de toute façon connaitre pour savoir dans quel sens l’utilisateur regarde !!).

    Pour symboliser la position de la caméra, du téléphone, des points d’intérêt, et les transformations qu’il faut y appliquer pour les projeter sur l’écran, un seul outil… les matrices.

    Pas besoin de se replonger dans un cours d’algèbre linéaire pour faire de la réalité augmentée cependant ! il faut juste accepter le fait qu’une position peut être codée par un vecteur 3D (donc composé des 3 coordonnées x, y et z) auquel on adjoint en général une 4ème composante nécessaire pour les calculs qu’on appellera w. Par ailleurs il est possible de coder dans une matrice 4x4 à la fois des rotations, des translations, des mises à l’échelle (scaling), et des projections. Encore une fois pas besoin de comprendre pourquoi et comment ça marche (même si c’est très intéressant… si vous voulez en savoir plus, rendez-vous dans les ressources au bout de ce document, nombre d’articles intéressant y figurent pour avoir plus de contexte).

    Si on résume tout ça : je prends des points en 3D symbolisés par des vecteurs, que je multiplie par des matrices symbolisant des transformations, pour avoir de nouveaux vecteurs, dans un repère 2D : l’écran du téléphone. Nous verrons dans la suite que les API de Windows Phone 7 notamment dans XNA permettent de faire ça très simplement.

    Le prochain article de cette série sera consacrée aux APIs de Windows Phone dont on va se servir, à savoir la Caméra, la classe Motion (aussi appelée Spatial Framework) et le GPS

    Voici les liens vers les articles suivants:

  • Pierre's Embedded and Mobile Blog

    Le SDK Windows Phone 8 est disponible!

    • 1 Comments

    Windows Phone 8 SDK sur le Download Center Microsoft

    Il s’agit du web-installer: autrement dit, il installe les composants en même temps qu’il le télécharge. Si vous voulez une iso complète à installer offline, le lien est sur la même page, un peu caché en dessous, je vous le remet ici:  ISO Complète du SDK Windows Phone 8

    Des nouveaux outils

    Ce SDK amène évidemment énormément de nouvelles APIs, que j’aurai l’occasion d’exposer dans un article séparé. En ce qui concerne les outils en eux-même, sachez qu’on passe à Visual Studio 2012, à une nouvelle version de Blend, qu’on ajoute en plus des images 7.1 existantes des images d’émulateurs WVGA, WXGA et 720p. Ces émulateurs reposent sur la technologie Hyper-V, qui nécessite une machine avec Windows 8, en 64bits, et une fonctionnalité appelée SLAT qui améliore le support de la virtualisation. Si vous voulez tester votre machine pour savoir si elle supporte le SLAT, lisez ce petit how-to.

    Du coté de Visual Studio, on va retrouver un nouveau Simulation Dashboard permettant de déclencher des évènements comme les reminders ou le verrouillage du téléphone et de simuler l’état du réseau. Le profiler de performances s’améliore également au passage avec plus d’infos. Enfin, l’éditeur de pages repose maintenant sur Blend et permet de concevoir l’application d’un seul coup pour les différentes résolutions. On a au passage rajouté un éditeur de manifest un peu plus graphique que ce qu’on avait avant…

    Enfin les templates de projets ont été améliorés pour supporter nativement la localisation et la globalisation de l’application, et pour rajouter le support des nouveautés du runtime, notamment DirectX.

    Des exemples de code

    De nombreux exemples de code sont déjà disponibles ici pour illustrer les nouvelles fonctionnalités du SDK

    Le Toolkit Nouveau

    Le Windows Phone Toolkit est maintenant, pour plus de clarté, séparé du Silverlight Toolkit, sur codeplex. Certains contrôles sont devenus natifs (comme le LongListSelector) il faut donc cette nouvelle version pour en profiter dans les applications Windows Phone:

    http://phone.codeplex.com/

    Des sites plus clairs

    Au cas où vous les chercheriez… Voici…

     

    Et aussi au cas où, sur les blogs officiels

Page 1 of 10 (240 items) 12345»