“Help’Aged Mesh Camera” ou comment envoyer une photo sur Live Mesh CTP (LiveFx) depuis Windows Mobile
Lors du développement de notre projet Help’Aged, projet gagnant de la finale française Imagine Cup 2009 (plus d’info sur le projet), nous avons mis en place une démonstration qui était censée être “sympa” si seulement nous avions eu une bonne réception du réseau mobile (GPRS, EDGE ou UTMS) dans la salle de présentation 🙂
Pour faire court Help’Aged est une sorte d’OS ergonomique pensé principalement pour les personnes âgées ou ayant diverses pathologies. L’interface très simple et intuitive s’utilise au moyen d’un écran tactile. Help’Aged héberge ensuite différentes applications pensées “usage” : je veux je peux (et je n’ai pas besoin de cliquer sur X bouton avant de pouvoir faire mon action !).
Toutes les applications pour Help’Aged sont rassemblées dans un “Application Store”, un catalogue d’application hébergé dans le cloud Azure. Grace au SDK d’HelpAged, chaque développeur peut facilement, en WPF, venir développer son application Help’Aged et l’envoyer sur le cloud Azure pour la mettre à disposition de tous. Help’Aged offre ici une plateforme hautement extensible et à forte valeur ajoutée.
Autre point clé d’Help’Aged est son coté “ubiquitaire” ! En d’autre terme, vous pouvez accéder à votre environnement (données, applications, paramètres) depuis n’importe quelles “machines Help’Aged”. Pour ce faire nous utilisons les Live Services et plus particulièrement le Live Framework (Live Mesh Tech Preview) comme unité de stokage propre à chaque utilisateur (identifié au moyen d’un LiveID).
Help’Aged, LiveFX et Windows Mobile : la démo
Les applications de base de l’environnement Help’Aged propose une galerie photo permettant de parcourir ses albums photos, rien de plus normal comme fonctionnalité de nos jours 🙂
Au démarrage de l’application, celle-ci vient synchroniser manuellement les photos présentes sur le Live Mesh (version Tech Preview) de l’utilisateur pour les mettre en local (et permettre un accès en mode déconnecté et une rapidité de lecture). Si Live Mesh Tech Preview et son modèle de ressource ne vous sont pas familier, je vous invite à lire mes précédents posts pour plus d’informations : Nouvelle CTP Avril 2009 du Live Framework et le Resource Model et l’annonce du Live Framework Explorer.
Comme pour toutes ressources dans Live Mesh (MeshObject), nous pouvons aisément le partager avec d’autre pour que chaque membre de la famille, par exemple, puisse ajouter des photos afin qu’elles soient directement affichées dans la galerie de l’utilisateur.
Mais plutôt que devoir sortir un ordinateur pour envoyer la photo n’est-il pas plus simple de sortir notre téléphone portable que nous avons dans notre poche 80% du temps ? Vous sortez votre téléphone pour immortaliser une photo qui est envoyée illico sur votre compte Mesh, synchronisée sur tous vos périphériques et partagée avec vos amis.
Pour illustrer une de nos démos, nous avons donc développé un petit utilitaire pour Windows Mobile nommé “Help’Aged Mesh Camera” permettant de prendre des photos et de les envoyer dans un dossier Live Mesh :
Envoyer une photo depuis Windows Mobile sur Live FX en pratique
Pour un effet démo “live”, l’application sur Help’Aged (la galerie photo) s’abonne à l’événement ChangeNotificationReceived du datafeed “LiveMeshFiles” qui est déclenché dès qu’il y a un changement dans les DataEntries de ce feed. En d’autre terme, dès qu’une photo est ajoutée/supprimée dans dossier sur Live Mesh, l’application cliente est notifiée pouvant ainsi mettre à jour sa galerie photo.
La méthode de chargement est similaire à ce qui suit ci-dessous :
1 2 3 4 5 6 7 8 9 10 11 12 | var myPicturesFolder = liveFx.Mesh.CreateQuery<MeshObject>().Where(mo => mo.Resource.Title == "My Pictures").FirstOrDefault(); if (myPicturesFolder != null) { myPicturesFeed = myPicturesFolder.CreateQuery<DataFeed>().Where(d => d.Resource.Title == "LiveMeshFiles").FirstOrDefault(); if (myPicturesFeed != null) { // Update the gallery when received a change notification of the DataFeed myPicturesFeed.DataEntries.ChangeNotificationReceived += (s, e) => UpdateGallery(); // Update the gallery on the startup UpdateGallery(); } } |
Pour le téléchargement en tant que tel des images sur le disque local, il nous suffira d’appeler la méthode ReadMediaResource pour chaque DataEntry représentant chacun de nos fichiers.
1 2 | foreach (var dataEntry in myPicturesFeed.DataEntries.Entries) dataEntry.ReadMediaResource(...); |
Live Mesh Beta != Live Mesh Tech Preview
N’oubliez pas que “Live Mesh Beta” n’est pas ouvert sur des services REST; c’est pourquoi nous utilisons exclusivement Live Mesh Tech Preview (LiveFX) pour pouvoir interagir depuis nos applications. Mais aucun client sur LiveFx ne permet la synchronisation de répertoire (version CTP). Les clients Mac, Windows et Windows Mobile pour la synchronisation de répertoire sont seulement disponible pour Live Mesh Beta.
En d’autre terme pas possible de faire une démo du genre “je déplace ces fichiers dans mon dossier Mesh depuis mon bureau Windows et hop les photos sont dans le cloud” comme vous le faites avec Live Mesh Beta ! Pour cela il faut nous même écrire du code permettant d’envoyer un fichier sur LiveFX.
Comme je l’ai fais dans Live Framework Explorer avec le plugin “FileUploadingPlugin”, cela se résume à ces quelques lignes quand nous avons à disposition l’API .Net de Live FX :
1 2 3 | // Upload a file using LiveFX SDK .NET myDataFeed.DataEntries.Add(myFileStream, myFileName, myFileMimeType); myDataFeed.UpdateAsync(myFileName); |
Une API LiveFX sur Compact Framework ?
L’envoi de fichier comme montré ci-dessus semble très simple ! En quelques lignes seulement j’envoi mon fichier dans un DataFeed d’un MeshObject représentant mon dossier.
Cette simplicité est fournie par le SDK de Live FX. Ce SDK est actuellement disponible pour :
- Le .NET Framework
- Silverlight
- Javascript
Mais quant est-il du Compact Framework pour les systèmes Windows Mobile ? Rien à disposition ?
Et si vous tentez d’ajouter les références de l’API .net, vous obtiendrez des erreurs à la compilation car les signatures des assemblies de la BCL (base class library) du .NET Framework et du .NET Compact Framework ne sont pas les mêmes ! Donc “chocolat” : pas de LiveOperatingEnvironment et autre LiveItem depuis notre application Windows Mobile 🙁
La solution : Vive les standards, vive HTTP !
Si vous avez bien suivi la technologie Live FX / Mesh Tech Preview, vous n’êtes pas sans savoir que côté Service tout est exposé en REST sur le protocole HTTP standard d’Internet depuis bien longtemps. En retour, le service renvoi les résultats dans le format que vous avez choisi (dans l’entête HTTP de votre requête) avec au choix : ATOM, RSS, POX ou JSON.
Les assemblies .NET, SL ou JS fournit dans le SDK de LiveFX ne font qu’interfacer l’envoi des requêtes HTTP et interprètent les réponses dans un modèle objet permettant un développement simple et rapide pour le développeur.
Pour citer mon post précédent :
Votre Live Operating Environment n’est pas fermé aux technologies Microsoft : n’importe quel langage ou plateforme sachant créer une requête HTTP et parser du XML (ou JSON) peut accéder et interagir avec notre LOE
Le Compact Framework étant tout à fait apte à créer des requêtes HTTP et parser du XML, nous n’avons donc aucun frein pour accéder à Live Mesh depuis notre smartphone 🙂
Mission 1 : Récupérer un ticket LiveID
Avant de pouvoir interagir avec le service LiveFx il faut au préalable être authentifié. La démarche est la suivante :
- On envoi une requête SOAP (contenant le Live Id et le mot de passe) sur le service Live-Id (https://dev.login.live.com/wstlogin.srf)
- Si l’authentification est correcte nous récupérons un ticket d’authentification
- Lors de l’envoi de nos requêtes HTTP sur le service LiveFx, on ajoute dans l’entête HTTP une clé nommée “Authorization” qui contiendra comme valeur notre ticket Live
Le code permettant la récupération du ticket d’authentification Live est disponible au travers du SDK de LiveFX dans le répertoire : X:\Program Files\Microsoft SDKs\Live Framework SDK\v0.91\Samples\AtomPub\ProjectManager\App_Code\WindowsLiveIdentity.cs
Pour récupérer notre ticket rien de plus simple maintenant :
1 2 3 | var liveIdTicket = WindowsLiveIdentity.GetTicket( new Uri("https://user-ctp.windows.net/"), new NetworkCredential("myLiveId@live.fr", "myPassword")); |
Mission 2 : Prendre une photo et l’envoyer le fichier sur LiveFX
La prise de photo sous Windows Mobile est assez simple. Vous trouverez dans le namespace Microsoft.WindowsMobile.Forms la classe CameraCaptureDialog permettant d’afficher la boite de dialogue pour la Camera. Comme le montre le code ci-dessous il suffit simplement d’afficher la fenêtre de dialogue et si le retour est OK, récupérer le chemin du fichier complet.
1 2 3 4 5 6 7 | //Open the camera capture dialog var cameraCaptureDialog = new CameraCaptureDialog(); cameraCaptureDialog.Mode = CameraCaptureMode.Still; if (cameraCaptureDialog.ShowDialog() == DialogResult.OK) { var imageFilename = cameraCaptureDialog.FileName } |
Une fois la photo prise, il nous faut envoyer ce fichier sur Live Mesh. Comme le montre Oran Dennison sur le forum de Live Framework dans ce thread, il nous suffit de créer une requête HTTP de type POST qui contiendra le fichier sur l’URL des MediasResources de votre DataFeed “LiveMeshFiles”.
Et comment récupérer l’URL des MediasResources du datafeed de votre dossier ?
Pour cela nous allons nous servir de Live Framework Explorer (LFE) directement depuis notre Visual Studio pour récupérer l’URL de notre dossier. Il faudra au préalable, avoir créé le dossier, par exemple, en se connectant sur le Live Desktop :
Depuis LFE, se connecter et parcourir ses MeshObjects pour retrouver notre dossier et sur le click droit, afficher les DataFeeds “LiveMeshFiles” dans le navigateur (View in the browser) :
Il suffira alors de copier-coller l’URL et d’y rajouter “/MediaResources” :
Avec le code d’Oran (que j’ai encapsulé dans une méthode UploadFile), il nous restera plus qu’à poster le fichier sur l’URL trouvé ci-dessus avec notre ticket Live et le tour est joué :
1 2 3 | // Upload the file (using HTTP POST) to the MediaResources URI var result = WindowsLiveFx.UploadFile(liveAuthToken, new Uri(mediaResourcesUri), imageFilename); |
Mission 3 : Récupérer les LiveMeshFolder et permettre de sélectionner le dossier
Jusqu’a maintenant nous avons réussi notre mission à savoir : envoyer notre photo dans Mesh. Seulement cela n’est pas très “propre” : mettre en dur dans le code l’adresse URL de notre dossier n’est pas très flexible et pratique pour l’utilisateur !
Nous allons donc rendre cela dynamique en proposant à l’utilisateur le choix du dossier sur Live Mesh :
Mais comment récupérer la liste de nos dossiers Live Mesh et leurs URL des “MediaResources” ?
Reprenons LFE pour introspecter notre modèle de ressource sur notre liste de MeshObject à l’adresse : https://user-ctp.windows.net/V0.1/Mesh/MeshObjects/
Nous y retrouvons au format ATOM (format par défaut), notre dossier “DemoMesh” catégorisé “LiveMeshFolder” par la ligne :
1 | <category term="LiveMeshFolder" scheme="http://user.windows.net/MeshObject" label="LiveMeshFolder" /> |
Une fois nos dossiers identifiés nous pouvons récupérer le lien vers les DataFeeds. Nous garderons en mémoire le titre du dossier ainsi que l’URL complète des DataFeeds et nous afficherons cette liste dans une ComboBox pour laisser le choix à l’utilisateur du dossier de destination.
Pour cela, j’ai créé une méthode “GetMeshXDocument” qui permet d’envoyer un GET HTTP sur Mesh (en tenant compte de l’authentification avec notre ticket Live) et de renvoyer la réponse ATOM dans un XDocument afin d’utiliser la puissance de LINQ pour récupérer le titre et URL des DataFeeds de tous mes LiveMeshFolder que je possède dans mon Mesh :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | XNamespace nsAtom = "http://www.w3.org/2005/Atom"; // Get the MeshObjects feed var meshObjectsFeed = WindowsLiveFx.GetMeshXDocument(LiveIdTicket, Program.LiveFXRootURI + "/Mesh/MeshObjects/"); // Get the Title & DataFeeds Uri of each LiveMesh Folder var meshFolders = meshObjectsFeed.Descendants(nsAtom + "entry"). Where( // <category .... term="LiveMeshFolder" /> item => item.Descendants(nsAtom + "category").Any( cat => cat.Attributes("term").Any( term => term.Value == "LiveMeshFolder"))) .Select(item => new MeshFolderInfo { Title = item.Element(nsAtom + "title").Value, DataFeedUri = item.Descendants(nsAtom + "link").Where( lnk => lnk.Attribute("rel").Value == "LiveFX/DataFeeds").Single().Attribute("href").Value }).ToList(); // Add each folder in the combobox meshFolders.ForEach(folder => cbFolder.Items.Add(folder)); |
Une fois la photo prise et le dossier sélectionné, il me reste encore à récupérer l’URL exacte des MediaResources afin d’envoyer le fichier à cette URL comme montré plus haut.
Pour cela il me faudra récupérer la liste des DataFeeds du dossier sélectionné afin de retrouver le DataFeed “LiveMeshFiles” pour récupérer l’URL de ses MediaResources. En (X)Linq :
1 2 3 4 5 6 7 8 9 10 11 | // Get the DataFeed of the folder (MO) selected var feeds = WindowsLiveFx.GetMeshXDocument(LiveIdTicket, Program.LiveFXRootURI + folderSelected.DataFeedUri); // Find the MediaResources URI in the DataFeed selected var mediaResourcesUri = feeds.Descendants(nsAtom + "entry"). Where( item => item.Element(nsAtom + "title").Value == "LiveMeshFiles") .Select( item => item.Descendants(nsAtom + "link").Where( lnk => lnk.Attribute("rel").Value == "LiveFX/MediaResources").Single().Attribute("href").Value).Single(); |
La suite est un jeu d’enfant, je n’ai plus qu’à envoyer mon fichier sur l’URL de mes MediaResources !
1 2 3 4 5 6 | // Upload the file (HTTP POST) to the MediaResources URI var result = WindowsLiveFx.UploadFile(LiveIdTicket, new Uri(Program.LiveFXRootURI + mediaResourcesUri), currentImage.FullName); // Ok ! lblStatus.Text = result ? "Image sent !" : "Fail !"; |
Conclusion
Comme vous avez pu le constater, un des principaux atouts de Live Mesh (Tech Preview), comme pour beaucoup des services de la plateforme Azure, est son ouverture vers les standards Internet. Le fait que Live Mesh soit accessible au travers d’un service HTTP/REST lui permet une haute interopérabilité entre les technologies pourvu qu’elles sachent utiliser le protocole HTTP et les formats XML/JSON.
Même si nous n’avons pas à l’heure actuelle d’API LiveFx pour Windows Mobile, il est tout à fait possible d’interagir avec cette plateforme sans limite. Un ami à moi me fit la réflexion à l’issue d’une discussion autour de Live Mesh : “Dommage qu’il n’y ait pas de client pour iPhone”, après quoi je lui rétorquais “A toi de le développer si tu le souhaites, tu as tout ce qu’il faut pour !” 🙂
Vous retrouverez les binaires et sources de HelpAged Mesh Camera ci-dessous
Bon Mesh à tous 🙂