Cahier 5 : Terminal Android, Java et Industrie, Mémoire d’un Licence Pro – Partie 3 : Annexe

Introduction

Sujet

Ce rapport présente les travaux ainsi que les activités confiées à l’étudiant durant la période du stage.

L’activité qui m’a été confiée est de mettre en œuvre les fonctionnalités les plus utilisées dans une application WinDEV en Android.

Le sujet de l’application reste libre dans la mesure où l’application met en œuvre et utilise les fonctionnalités demandées.

L’objectif de ce projet est de faire découvrir Android au sein de l’entreprise Karelis, qui utilise WinDEV actuellement pour développer les applications pour ses clients.

Android commençant à apparaître sur le marché industriel, il est nécessaire d’étudier la puissance, les avantages et inconvénients de ce dernier.

Il m’est alors demandé de réaliser une application lourde mettant en œuvre les besoins du client.

C’est-à-dire écrire/lire un fichier de configuration, communiquer avec une base de données interne et externe. Mettre en place un web service pour effectuer des tests et en sécurisant ce dernier. D’établir une communication Bluetooth entre un terminal et une imprimante portable et d’imprimer une étiquette.

En dernier lieu de sécuriser l’application sur le point de vue fonctionnement et lors de son utilisation par l’utilisateur.

Pour conclure, le projet confié pendant la durée du stage est de réaliser un tutoriel sur le fonctionnement du monde Android et de familiariser, décrire les procédures de fonctionnement d’Eclipse et du SDK.

Il est d’une grande importance que le projet soit bien commenté, et que les fonctionnalités demandées soient bien expliquées.

Dans un dernier temps, il sera utile de faire une conclusion sur l’utilité d’Android dans le monde de l’industrie en portant un regard objectif et critique sur ce dernier afin de permettre à l’entreprise Karelis d’investir ou non dans cette technologie aussi bien sur le point de vue matériel, logiciel et humain.

PARTIE I

Installation et Configuration

Eclipse

Téléchargez la dernière version d’Eclipse sur le site officiel (Il est important de prendre la même version de plateforme pour des soucis de portabilité et de compatibilité d’exécution des projets).

http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/junosr1

Une fois téléchargé, décompressez le fichier dans C:\Eclipse\juno

Plugin Android pour Eclipse

Lancez Eclipse.

Définissez le dossier qui contiendra les projets à venir.

Une fois ouvert, vous devez obtenir l’interface suivante :

Dans la barre de menu, sélectionnez Help>Install New Software, puis cliquez sur le bouton Add et remplissez le formulaire.

Renseignez le champ Name par le nom que vous souhaitez (pour ma part, Android-SDK). Pour le champ Location saisissez l’adresse suivante :

https://dl-ssl.google.com/android/eclipse/

Dans le cas où le lien ne serait pas valide, utilisez le lien :

http://dl-ssl.google.com/android/eclipse/

Validez en cliquant sur OK.

Eclipse recherche les plugins. Une fois trouvés, cochez les packages Developer Tools et NDK Plugins et cliquez sur Next.

Étape N°1Étape N°2

Lisez (ou non) les Licences associées pour chaque package et sélectionnez si vous acceptez leur contenu la mention « I accept the terms of the licence agreements ». Puis cliquez sur Finish.

L’installation débute, il ne reste plus qu’à attendre la fin de cette dernière pour redémarrer Eclipse afin d’appliquer les changements.

Il se peut que le logiciel vous avertisse d’un problème de sécurité lié à l’intégrité des données que vous téléchargez (ne connaît pas le certificat). Ignorez ce message d’erreur et confirmez la poursuite de l’installation.

Après avoir redémarré Eclipse ce dernier ouvre une fenêtre de configuration du SDK. Eclipse ne trouve pas de SDK. C’est pourquoi il vous propose d’installer un nouveau SDK ou de lui indiquer un SDK existant.

Dans notre cas, nous installons un nouveau SDK en cochant les deux check-box et en indiquant le chemin cible qui contiendra le SDK.

Pour ma part C:\Eclipse\androïdSDK.

Validez l’étape en cliquant sur Next.

Choisissez ou non d’envoyer les statistiques d’utilisation à Google, puis validez l’installation en cliquant sur Finish.

Lisez (ou non) les licences de chaque paquet et acceptez afin de pouvoir installer ces derniers.

L’installation débute. Une fois finie, redémarrez une nouvelle fois Eclipse.

Configuration d’Android

Dans la barre de menu, sélectionnez

Puis cochez toutes les versions depuis la version Android 2.2 jusqu’à Tools (compris) ainsi que le dossier Extras. Puis appuyez sur Install XX packages.

De nouveau, il vous faudra lire (ou non) les licences associées à chacun des paquets afin d’accepter les droits et de pouvoir installer les versions SDK souhaitées.

Le téléchargement et l’installation prend un certain temps.

Attention :

Suivant la version d’Android présente sur le terminal, vous devez impérativement configurer la version JDK et JRE utilisée. En termes généraux, pour la version 2.3.4 (Version de l’OS de l’ET1 (Motorola) et Dolphin 7800 (Honeywell) à cette date) vous devez utiliser la version 1.6.

Pour cela dans la barre de menu, Window>Preferences>Java>Compiler, sélectionnez 1.6 dans la boîte de sélection.

Ensuite, configurez la version de la JRE dans Java>Installed JREs.

Cliquez sur le bouton Add et sélectionnez Standard VM et cliquez sur Next.
Renseignez le path de la JRE Eclipse se chargera du reste. Et cliquez sur Finish.

La JRE étant définie, il vous suffit simplement de cocher la JRE6 pour l’utiliser. Enregistrez les changements en appuyant sur Ok.

Dans le cas où vous ne posséderiez pas la jre6, vous pouvez télécharger cette dernière

http://www.oracle.com/technetwork/java/javase/downloads/jre6-downloads-1637595.html

Eclipse et le plugin Android sont maintenant configurés.

Installation des drivers matériels

L’installation des drivers ayant pour objectif de pouvoir exporter les projets afin de pouvoir tester et de débugger nos futures applications.

Nous verrons ici comment installer et configurer les drivers matériels pour les tablettes industrielles suivantes :

  • ET1 du constructeur Motorola tournant sous Android 2.3.4
  • Dolphin 7800 Android du constructeur Honeywell tournant sous Android 2.3.4

ET1

Spécifications matérielles

Installation

Pour commencer, reliez la tablette industrielle ET1 au poste de développement via le câble de connexion USB. L’ordinateur va rechercher à installer les pilotes du périphérique de manière automatique. L’installation échouera, donc ne perdez pas votre temps.

Pour installer les drivers, lancez l’exécutable MotoUsbDrivers (fourni en annexe dans le dossier Driver\Motorola). Suivez l’installation comme vous avez l’habitude de le faire.

Au cours de l’installation une fenêtre de sécurité vous informera d’un potentiel danger suite à une non reconnaissance du Driver par Windows. Ignorez ce message et choisissez d’installer le pilote quand même.

(Un test viral poussé a été effectué afin de détecter une quelconque menace ayant en résultat aucune menace).

Une fois l’installation finie, cliquez sur Finish.

Afin de vérifier que notre appareil est bien connecté et reconnu par Eclipse, sélectionnez dans la barre du menu, Window>Open Perspective>Other et sélectionnez DDMS puis validez.

Vous serez alors obligatoirement redirigé vers l’interface qui suit :

Si la procédure d’installation a été suivie correctement et que toutes les étapes d’installation se sont bien déroulées, nous retrouvons notre appareil connecté et reconnu par Eclipse (cadre rouge).

L’ET1 est donc prêt à être utilisé.

Dolphin 7800 Android

Spécifications matérielles

Installation

À l’heure actuelle, il n’est pas possible d’installer les drivers du terminal 7800. La documentation fournie par le constructeur ne permet pas l’installation et l’utilisation correcte de l’appareil.

Premier pas

Maintenant que nous avons installé et paramétré Eclipse et les différentes plateformes physiques qui supporteront nos futures applications nous allons voir en profondeur comment créer un projet Android. Ainsi que comprendre comment est structuré un tel projet, et comment utiliser l’interface de manière optimale.

Lancez Eclipse si ce n’est pas déjà fait.

Présentation basique de l’interface

Par défaut, vous devez vous retrouver sur l’interface suivante :

La fenêtre est divisée en 3 zones chacune ayant sa particularité ainsi qu’un but précis. Voyons maintenant plus en détail ces 3 zones en décrivant leurs fonctionnalités.

La zone 1 comporte l’historique ainsi que l’arborescence de chaque projet créé.

Dans cette sous fenêtre, il est possible de trouver des projets utilisant différents types de langage suivant les plugins installés.

Si vous avez installé la même version qu’au début de la documentation, vous pouvez donc vous retrouver avec des projets Java, Android, C, C++.

Nous verrons par la suite comment se structure un projet Android.

La zone numéro 2 quant à elle est le cœur de l’interface. C’est l’écran que vous utiliserez le plus souvent. Il permet d’afficher les différents fichiers de code (fichier.c ; fichier.java ; fichier.cpp ; fichier.xml ; fichier.txt etc.). Pour des meilleures conditions de codage, je vous conseille d’utiliser la zone d’agrandissement et/ou de réduction.

La zone 3 quant à elle est la sous interface que vous utiliserez le plus. Elle correspond à la zone de débogage. Il est possible d’ajouter des onglets d’information supplémentaire, nous verrons cela dans la présentation avancée.

Par défaut, la zone 3 comporte 4 onglets :

Après avoir vu les parties les plus importantes de l’interface, nous allons voir les outils essentiels proposés par Eclipse.

est le SDK Manager, il permet de mettre à jour les différentes versions d’Android ainsi que des APIs fournies par Google.

permet de lancer le simulateur Android sur le poste de développement afin de déployer les applications pour le débogage. Personnellement, je ne l’utilise pas car ce dernier demande des ressources et selon les projets, cela peut représenter une perte de temps considérable.

permet de créer un nouveau fichier Android.xml. Nous verrons dans la partie suivante à quoi servent les fichiers XML Android.

permet de supprimer tous les break points d’un projet.

permet de lancer le débogage du projet en cours, ou sélectionné.

permet de compiler et de déployer le projet en cours, ou le projet choisi. Il est nécessaire de paramétrer une configuration de déploiement avant de lancer la compilation d’un projet Android.

permet de créer un nouveau package dans un projet.

permet de créer une nouvelle classe dans un projet.

permet de faire des recherches, remplacer des séquences, etc. Plus utilisé dans le cas d’une recherche et est d’une grande utilité dans un projet comportant de nombreuses classes.

Il y a 2 icônes présentes sur cette interface que vous utiliserez assez souvent. Il s’agit des boutons situés en haut à droite de l’interface. La première de ces icônes (la plus à gauche) permet d’ouvrir une perspective. Cette fonctionnalité est intéressante pour nous seulement pour ouvrir la perspective DDMS. La seconde icône (au centre) permet d’avoir une vue sur l’interface de développement, soit l’interface par défaut lors du démarrage d’Eclipse. Quant à la dernière icône DDMS (Dalvik Debug Monitor Service) qui permet de basculer de l’interface de programmation vers l’interface de débogage et d’information système du périphérique Android connecté.

Par exemple :

Nous verrons plus en détail cette interface dans la partie suivante.

Maintenant que nous avons fini de découvrir l’interface de manière élémentaire, nous allons pouvoir créer un projet Android et s’intéresser à la structure de celui-ci.

Premier Projet Android

Afin de voir comment fonctionne Android, nous allons créer une application de base comportant un champ de saisie, que nous remplirons et qui affichera le résultat de ce dernier dans un champ d’affichage lors de l’action sur un bouton.

Création d’un projet

Pour créer un projet Android allez dans la barre du menu et sélectionnez File>New>Project. Une fenêtre de dialogue apparaît. Sélectionnez le dossier Android, puis Android Application Project.

Validez votre saisie en appuyant sur le bouton Next.

Dans cette nouvelle fenêtre, renseignez le premier champ en spécifiant le nom de votre application. Dans mon cas SaramandaTestu.

Automatiquement, Eclipse se charge de renseigner les autres champs. Modifiez le Package name : com.example.SaramandaTestu par com.SaramandaTestu.

Définissez le SDK minimum. C’est-à-dire la version minimum pour laquelle l’application pourra être déployée sur un appareil.

Définissez le SDK cible. C’est-à-dire la version sur laquelle l’application va être déployée.

Choisissez le compilateur SDK, en prenant soin de prendre la même version que celle du SDK cible.

En fonction du niveau de l’API choisie, choisissez ou non un thème.

Dans notre cas, nous choisissons de tous mettre compatible avec la version Android 2.3.3.

Avec cette configuration vous devez avoir exactement le même écran que ci-contre.

Validez la saisie, en appuyant sur Next.

La suite de la procédure consiste à configurer le projet. Laissez les choix par défaut, et cliquez sur Next.

Nous arrivons maintenant sur une fenêtre permettant de configurer l’icône de notre application.

Dans un premier temps, nous allons mettre une image, clipart ou un texte.

Il est possible de choisir si l’icône doit être centrée, ou prendre tout l’espace, si l’icône doit être ronde, ou carrée, et de choisir le fond de l’icône.

Ces paramètres ne sont pas très intéressants et ne méritent pas de s’attarder trop longtemps dessus.

Cependant, nous pouvons remarquer que nous avons un rendu de notre icône sur le côté droit.

Il y a plusieurs fois la même image avec des extensions différentes :

mdpi, hdpi, xhdpi, xxhdpi

Ces différents formats permettent d’afficher notre icône sur n’importe quel format d’appareil compatible avec la version de l’API définie précédemment.

En conclusion, notre application aura une icône quelle que soit la taille de l’écran.

Une fois cette phase renseignée et terminée, validez l’étape en cliquant sur le bouton Next.

Dans cette fenêtre, nous allons choisir le type d’activité que nous souhaitons réaliser. Naturellement, la nature de l’activité est liée à la version de l’API définie au début de la phase de création du projet.

Nous laissons la check box Create Activity cochée, et nous sélectionnons le seul choix possible soit Blank Activity avant de passer à l’étape suivante en cliquant sur Next.

Ce qui nous amène à la dernière phase de la procédure de création de projet.

Dans cette dernière phase de paramétrage, nous devons fournir un nom à notre activité ainsi qu’au Layout.

Il est important de renseigner ces champs avec des « noms parlants ». Toute négligence à ce niveau peut être une perte de temps dans une application qui demande du multifenêtrage, ainsi qu’un risque non négligeable de corrompre le fichier de ressource.

Validez l’étape de création en cliquant sur Finish.

L’opération va prendre un certain moment, le temps de générer les fichiers ressources nécessaires.

Par défaut l’IDE s’ouvrira sur l’interface de création graphique de l’interface.

Une fois le projet créé et chargé, nous allons nous intéresser à la structure de notre projet créé.

Architecture d’un projet

Le projet comporte une architecture particulière.

Nous allons décrire et définir l’usage et le rôle de chaque dossier et fichier.
Dossier source

Le dossier est le dossier comportant tous les fichiers sources. C’est-à-dire les fichiers natifs java. Ce dossier est organisé en package qui eux vont contenir les fichiers .java. L’utilisation et la création de package s’apparente plus ou moins à des sous-dossiers. Un projet bien organisé comporte plusieurs packages. (Ce qui facilite grandement le travail collectif par la même occasion).

Dossier de génération de fichier java

Attention : Il est d’une importance capitale de ne modifier en aucun cas le contenu de ce dossier. Car ces derniers sont des fichiers auto-générés par Eclipse. La modification volontaire de ces fichiers peut endommager le projet et ne garantira plus son bon fonctionnement.

Le dossier va contenir des fichiers .java organisés et répartis dans un ou plusieurs packages. Le fichier qui nous intéressera le plus est le fichier R.java. Ce fichier auto généré contient toutes les descriptions graphiques des objets présents dans la ou les interfaces de notre application. Il sera mis à jour à chaque modification et enregistrement d’un layout.

Les Librairies

Les librairies sont représentées par l’icône. Il y a par défaut 3 types de librairies.

  • qui contient la version d’Android que nous avons définie lors de la création de notre projet. Soit plus précisément les méthodes existantes pour cette version du SDK.
  • qui contient quant à lui les librairies graphiques et autres dépendances nécessaires pour la version du SDK utilisée.
  • qui contiendra toutes les dépendances que nous viendrons ajouter lors de la création et construction de notre projet. Par exemple les librairies JDOM, JDBC, etc.

Il existe dans le même genre le dossier qui contiendra les librairies que nous importerons et utiliserons dans notre projet. La différence est que ce dossier a une existence physique dans le projet sur notre disque ce qui n’est pas le cas pour les librairies énumérées ci-dessus. Nous stockerons nos librairies dans ce dossier, nous verrons plus tard à travers certains modules comment.

Le Dossier Binaire

Le dossier contient le fichier. Ce fichier est le cœur de l’application et de notre projet. Il a pour tâche de contenir toute la configuration de notre projet ainsi que la déclaration des permissions.

Les permissions permettent lors de la compilation et du déploiement de l’application sur un appareil d’autoriser notre APP à utiliser certaines couches matérielles. (Android étant basé sur un noyau UNIX, il suit la même philosophie que ce dernier en fonctionnant avec des permissions pour utiliser certaines fonctionnalités).

Nous verrons par la suite comment et quand modifier ce fichier.

Le Dossier de Ressources

Le dossier contient tout ce qui touche à nos interfaces. Il y a une multitude de dossiers hdpi/ldpi/mdpi/xhdpi/xxhdpi qui ont pour but de contenir les éléments qui nécessitent un redimensionnement en fonction de la taille de l’écran. (Exemple, les images).

Le dossier contient toutes nos fenêtres et interfaces de la simple boîte de dialogue, jusqu’au plein écran. Il contient des fichiers au format XML comme suivant nous verrons la structure d’un tel fichier prochainement.

Le dossier contient à la différence du dossier layout les fichiers graphiques singuliers au menu. Soit l’interface lors d’une action sur le bouton. Comme pour le layout, nous verrons plus loin comment modifier et créer une interface spécifique au menu.

Le dossier contient 3 fichiers XML contenant pour le fichier toutes les variables « textes » présentes dans les fichiers graphiques .xml. Le fichier contient les dimensions des éléments composant les fichiers graphiques quand ces derniers sont définis en tant que variables de type ressources. Le fichier contient le changement de style tel que la couleur ou les formes des interfaces graphiques.

Importation d’une librairie

Dans certains projets l’utilisation de technologie spécifique n’est pas présente dans les librairies par défaut d’Eclipse. C’est pourquoi il nous sera nécessaire de télécharger ces dernières et de les importer dans notre projet. Par exemple ce sera le cas, pour la bibliothèque JDBC, JDOM etc.

Attention : L’importation d’un grand nombre de librairies peut surcharger la Machine Virtuelle. De plus, lors du calcul et de la compilation avant l’exportation sur le terminal cible, cette phase peut échouer si celui-ci n’a pas les ressources nécessaires pour exécuter le programme. C’est pourquoi l’utilisation des librairies externes s’utilise si et seulement si les méthodes et classes natives en java ne permettent pas de traiter et/ou de solutionner le problème rencontré.

Positionnez-vous sur le projet et effectuez un clic gauche sur celui-ci. Sélectionnez alors dans la liste, et choisissez ensuite (dernier élément de la liste déroulante).

Sélectionnez l’onglet puis cliquez sur le bouton Add Variable… .

Une interface de configuration apparaît. Il vous est alors demandé de choisir dans la liste ci-dessous une variable à ajouter au build path.

Dans le cas où la variable n’existe pas appuyez sur le bouton Configure Variables… .

Une nouvelle fenêtre s’ouvre. Cliquez sur New… à droite de l’interface.



Choisissez un nom de variable, et renseignez le champ Path en définissant le path d’un fichier, ou celui d’un dossier. Une fois fait cliquez sur le bouton OK.

Notre variable est ajoutée dans la liste de sélection que nous avions précédemment. Sélectionnez la variable que nous venons de créer dans la liste. Et cliquez sur OK.



Sélectionnez de nouveau la variable dans la liste (image ci-contre). Puis cliquez sur le bouton OK.


La variable est donc ajoutée au build path du projet et apparaît dans la liste sous l’image suivante :

Validez en cliquant sur le bouton OK.

Un nouveau fichier de librairie vient d’apparaître dans la structure de notre projet. Si l’on développe le contenu de ce dossier, nous retrouvons la librairie que nous venons de créer et d’ajouter. Toutes les librairies que nous ajouterons seront placées dans ce dossier.

Pour exclure une librairie du projet choisissez la librairie à supprimer dans le dossier. Puis faites un clic droit sur cette dernière et cliquez sur le champ Build Path>Remove from Build Path. La librairie sera supprimée du projet.

Ajout d’éléments graphiques

Nous allons ajouter des éléments de base à notre première interface pour voir le fonctionnement du fichier XML. Dans cette démonstration (comme spécifié en début de partie) nous allons ajouter un bouton, un champ d’affichage et un champ de saisie.

Dans le dossier SaramandaTestu>res>layout>activity_main.xml double-cliquez sur le fichier XML.

Une nouvelle sous interface est chargée dans la zone de développement (zone 2 de l’interface principale). Nous allons voir avant de créer notre interface comment fonctionne cette sous-interface.

Présentation de l’interface de création

L’interface de création (ci-dessous) se divise en 6 zones. Nous en présenterons seulement 5 en détails, la 6 (non notée) ne présente pas d’intérêt majeur.

La zone principale (non allouée de numéro) permet d’avoir un rendu de notre future interface et de positionner des widgets et d’organiser l’ergonomie de l’application.

La zone 1 s’appelle Palette. Elle contient tous les éléments graphiques par défaut contenus dans le pack SDK Android en fonction des versions. Pour ajouter un élément sur l’interface il suffit de faire un « drag and drop » sur la partie centrale ou dans la zone 4.

Il existe 2 types de widgets :

  • Les conteneurs qui vont contenir des éléments de base et permettre d’organiser ces éléments sur l’interface. Voici une liste non exclusive des éléments conteneurs avec une brève description :
ÉlémentsDescription
Permet de contenir et d’organiser les éléments les uns en dessous des autres.
Permet de contenir et d’organiser les éléments les uns à côté des autres.
Permet de positionner les éléments les uns par rapport aux autres de manière relative.
Permet de bloquer une zone sur l’écran pour afficher UN seul élément. Généralement utilisé sur des layout-child.
Permet d’inclure des éléments dans différentes faces que l’utilisateur va faire défiler.
Organise et va contenir des colonnes et des lignes.
Permet d’afficher et de contenir plusieurs éléments informatifs en affichant celui-ci dans une liste déroulante
Permet d’inclure un ascenseur vertical. Qui peut contenir des éléments graphiques.
Tab Host permet de contenir sur un Layout plusieurs Child Layout. Idéal pour les pages de configurations et les options ou pour un traitement procédural en n étapes.
  • Les champs d’informations et de saisie, qui permettent comme leurs noms l’indiquent de saisir des informations, d’indiquer des informations sur l’état de l’application et les éléments permettant de déclencher des informations. Voici une liste allégée et non exhaustive des éléments avec une brève description de chacun des widgets:
ÉlémentsDescription
Les champs de saisie, à choisir en fonction du type de saisie que l’on souhaite entrer : Integer, Double, Date, Heure, Password…
Les champs d’affichage qui permettent d’afficher une zone de texte. Aussi bien statique que dynamique (exemple : résultat d’une saisie).


Les Boutons ainsi que les boîtes de sélection (radio ou check box) qui permettent le déclenchement de traitement lors d’une action sur ces derniers.

Il existe différentes actions que nous verrons plus loin dans cette partie.
Les barres de chargements, qui indiquent l’avancée d’une procédure en détail.
Les champs de saisie pour une date.

Attention : Il est déconseillé (voire même interdit) de mettre un contrôle d’écran dans un contrôle d’écran déjà existant. Par exemple un scrollView dans un scrollView.

La zone 2 permet de faire la bascule entre la zone de création graphique (familièrement appelée « clic clic souris ») et la représentation graphique de notre interface sous le format XML.

L’onglet Graphical Layout n’a d’utilité que de créer notre page et l’interface de manière grossière afin de gagner du temps. L’onglet activity_main.XML quant à lui permet de modifier et de perfectionner l’affichage et l’orientation de chaque élément en définissant le nom de chaque champ. C’est-à-dire d’attribuer pour chaque champ un identifiant afin de pouvoir manipuler et retrouver facilement celui-ci par la suite. Il est capital de donner des noms d’identifiant parlants.

La zone 3 contient la barre d’outils qui permet de paramétrer l’écran de rendu selon les critères de l’interface que nous possédons et/ou sur lequel nous souhaitons émuler ou exporter notre APP.

Il permet aussi d’afficher le rendu graphique d’une version à une autre. Et ainsi de voir le rendu et surtout la stabilité et la compatibilité des widgets.

OutilsDescriptions
Permet de configurer l’écran de rendu en fonction de la taille de l’écran (émulateur ou device). D’où la présence en partie des spécifications techniques des terminaux.
Permet de basculer l’affichage de l’interface de Portrait à Paysage.
Permet de choisir un thème pour notre APP en fonction de la compatibilité de la version d’Android utilisée lors de la création de notre projet.
Permet de choisir la version pour laquelle nous souhaitons voir le rendu de notre interface.
Permet de manipuler le zoom sur la zone de rendu. Il n’offre rien de bien particulier si ce n’est pour le bien-être du développeur.
Ces icônes permettent de modifier les marges, d’activer ou non les relations et les contraintes entre les éléments etc.

La zone 4 permet d’afficher et de représenter le contenu de notre création sous forme d’une arborescence (soit l’encapsulation des données propriétés du fichier XML). De cette façon, il est plus aisé de sélectionner un élément. Cette zone est importante pour son rôle informatif. Un double-clic sur un élément nous renvoie directement à sa définition en XML. De plus il permet de choisir avec précision un élément que l’on souhaite modifier via l’interface de la zone 5.

La zone 5 permet d’ajouter et/ou de modifier des propriétés ou contraintes liées au widget préalablement sélectionné.

La modification des propriétés s’étend dans la quasi-totalité au même ensemble de règles que le CSS et XSL. Il n’est pas nécessaire de voir en détail lesdites règles. Car ces dernières sont compréhensibles.

Après s’être familiarisé avec l’interface. Nous allons parler rapidement des formats d’affichage avant de réaliser l’interface de notre programme.

Les Formats

Comme pour le langage CSS, il est possible d’utiliser des unités de mesure pour définir la taille et adapter cette dernière à la taille d’un conteneur, d’un écran etc.

Dans le fichier XML, il est possible de définir une unité de mesure pour la taille de la police ainsi que pour tout ce qui peut être modifiable sur le point de vue de la dimension.

Sous Android, les unités de mesure sont différentes de celles utilisées par les feuilles de style traditionnelles (CSS, XSL). Android possède 6 formats :

UnitéDescription
dpDensity independent Pixel (Densité de pixels indépendant) unité abstraite qui est basée sur la densité physique de l’écran. Cette unité est égale à 160 DPI (Points par pouce) par écran. Cette dimension sera utilisée pour la mise en page des éléments.
spScale independent Pixel (Échelle de pixels indépendant) utilisé pour les tailles de polices. On pourrait comparer cette unité aux em du développement web. La police peut être plus ou moins grosse suivant les préférences de l’utilisateur.
ptPoint 72 points par pouce. Basé sur la taille physique de l’écran.
pxPixels correspond aux pixels réels de l’écran. Cette unité de mesure n’est pas recommandée car le rendu sur les différents types d’écran peut être différent. Le nombre de pixels par pouce peut varier suivant les appareils.
mmMillimètre basé sur la taille physique de l’écran.
inInches basé sur la taille physique de l’écran.

Après avoir vu les différents types de format et s’être familiarisé avec l’interface de réalisation, nous pouvons commencer notre interface.

Réalisation de l’interface

Pour commencer, supprimons le « Hello world » présent. Sélectionnez l’élément, puis appuyez sur la touche Supprimer de votre clavier. Dans la zone 4 de l’interface de création faites un clic droit sur et sélectionnez Change Layout… . Dans l’interface qui vient de s’ouvrir choisissez dans la liste déroulante LinearLayout(Verticale). Puis validez en cliquant sur OK.

Vous devez donc avoir dans votre arborescence l’unique élément suivant.

Nous allons maintenant ajouter un titre à notre application. Pour cela sélectionnez dans la zone 1 de l’interface de création le dossier Text Fields et choisissez Large. Faites un « drag and drop » sur la zone de rendu pour ajouter l’élément.

Faites un double-clic sur l’élément contenu dans l’unique conteneur pour accéder à sa définition XML.

Champ non modifié

Champ modifié

Nous avons donc modifié l’id du champ afin de pouvoir identifier ce dernier plus facilement comme il l’a été dit plus haut.

Personnellement, je recommande d’utiliser la notation suivante pour définir l’id d’un champ.

NomDuLayout_TypeDeChamp_SonDescriptif principale_txt_titre

Nous avons ajouté qui nous permet de centrer le titre.

Nous avons modifié la valeur du texte en indiquant le nom de notre application. Puis nous avons modifié la taille de cette dernière en ajoutant.

Si nous regardons le rendu en revenant dans l’onglet Graphical Layout, nous obtenons l’image ci-dessous :

Maintenant, nous allons créer un libellé indiquant ce que nous attendons dans le champ de saisie et donc par la même occasion un champ de saisie de type Texte.

Dans un premier temps, nous allons ajouter un conteneur horizontal dans le conteneur vertical afin de pouvoir rendre le libellé du champ et le champ de saisie l’un en face de l’autre.

Pour cela dans la zone 1 de l’interface de création dans le dossier Layouts sélectionnez LinearLayout (Horizontal) puis faites un drag and drop de cet élément dans la zone 4 de l’interface de création.

Vous devez obtenir la structure suivante :

Attention : Notez attentivement l’alignement du LinearLayout. Celui-ci n’est pas au niveau du premier LinearLayout, mais bien en dessous. Cela vient donc confirmer son appartenance au conteneur.

Une fois avoir créé notre second conteneur, nous allons ajouter une zone de texte (libellé) et un champ de saisie de type texte. Cependant, nous allons cette fois-ci faire un « drag and drop » dans le conteneur LinearLayout (Horizontal). Vous devez obtenir la structure suivante :

Double-cliquez sur textView1 pour pointer directement sur sa description XML dans le fichier layout afin de modifier les paramètres et d’ajouter des contraintes sur les deux champs.

N’hésitez pas à revenir à l’interface de création pour configurer les marges dans la zone 5. Comme nous traitons des champs (positionnement) nous utiliserons l’unité de mesure dp.

Champs non modifiésChamps modifiés

Nous remarquons la présence d’une balise . Cette balise informe que ce champ sera immédiatement ciblé par l’application quand nous souhaiterons saisir des données. Dans le cas d’un formulaire, la présence de cette balise marquera le point de départ de la saisie.

Vous devriez avoir si tout se passe bien un rendu similaire à l’image ci-dessous :

Nous allons ajouter un nouveau conteneur Horizontal dans le conteneur Vertical (le conteneur initial) à la suite de celui que nous avons ajouté dernièrement. De la même manière que précédemment, ajoutez le LinearLayout (horizontal). Puis ajoutez deux zones de texte (libellé) dans le conteneur que nous venons de créer. L’architecture doit être la suivante :

Faites un double-clic sur le widget textView1 comme précédemment pour avoir accès au document XML.

Champs non modifiésChamps modifiés

Il ne nous reste alors qu’à ajouter un bouton pour déclencher un événement lorsque nous cliquerons dessus par la suite.

Dans la zone 1 de l’interface de création dans le dossier Form Widgets faites un « drag and drop » du widget Button sur le même niveau que les deux conteneurs que nous avons ajoutés plus haut.

La structure doit être la suivante :

Double-cliquez sur le widget pour avoir accès à sa description XML (possibilité de changer d’onglet à travers la zone 2 bien que moins rapide) et modifiez les propriétés.

Champ non modifiéChamp modifié

Nous venons donc de finir de créer notre interface. Cette dernière devrait ressembler à l’image ci-dessous :

Sauvegardez la création. La conséquence de cette sauvegarde va mettre automatiquement à jour le fichier de ressource R.java dont nous avons l’extrême interdiction de modifier. Fermez la fenêtre activity_main.xml.

Astuce : Lorsque vous tapez Eclipse vous propose une liste de propositions due à l’auto-complétion. Vous pouvez avoir cette dernière n’importe quand en utilisant la combinaison Ctrl+Espace. Ce qui permet un gain de temps, et de voir toutes les méthodes proposées par la classe.

Réalisation des traitements

L’étape de création de l’interface étant terminée, nous pouvons nous atteler maintenant à la réalisation des traitements sur l’interface. Pour cela nous allons ouvrir le fichier MainActivity.java présent dans le dossier src>com.saramandatestu de notre projet.

Le fichier n’est pas vierge. Le système lors de la création du projet a déjà généré automatiquement du code. Dont nous allons expliquer le contenu.

Les premières lignes jouent le rôle d’import.

Notre classe est définie par public class. Notons la présence d’un extends à la classe Activity. Cela signifie que notre classe MainActivity hérite de la classe Activity.

La présence des @Override permet au système de savoir que l’on va faire une surdéfinition de la classe parente.

La méthode protected void onCreate(Bundle saveInstanceState) a pour but d’effectuer tous les traitements liés au lancement de l’interface que cette classe instancie. Il en est de même pour la méthode public boolean onCreateOptionMenu(Menu menu) qui elle a pour but de charger l’interface du menu.

Après avoir présenté rapidement le code auto-généré, nous allons déclarer les variables liées à notre interface afin d’établir les relations entre l’interface et la page de traitement.

Dans un premier temps, nous allons définir notre bouton en instanciant un objet de la classe Button et en liant celui-ci à l’id que nous lui avons attribué dans la partie précédente (d’où l’importance de donner des noms « parlants » afin de bien faire le lien).

Ainsi, nous instancions bt_Valider de la classe Button en lui attribuant la valeur R.id.principale_bt_validez à travers la méthode findViewById() qui est castée par la classe Button.

Une fois notre bouton créé de manière logique, nous devons ajouter un événement sur ce bouton. Pour cela, nous allons mettre un événement de type « appui » sur le bouton.

Techniquement, nous utilisons l’objet que nous venons d’instancier bt_Valider et nous appelons la méthode setOnClickListener(). Le this signifie que c’est sur lui-même donc sur bt_Valider.

Une fois la ligne achevée, Eclipse vous signale la présence d’erreur dans la ligne.

Cliquez sur la petite ampoule dans la colonne de gauche. Eclipse nous propose alors plusieurs solutions. Le fait d’avoir déclaré un événement implique une implémentation de la classe MainActivity.

Faites un double-clic sur Let « MainActivty » implement « OnClick Listener ».

Ce qui viendra ajouter le code manquant « implements OnClickListener » à la suite de « extends Activity ».

Cependant, Eclipse vous signale de nouveau une erreur dans la ligne. Faites de nouveau un clic sur la petite ampoule. Eclipse propose de nouveau des solutions qui pourraient résoudre cette erreur. Dans notre cas, il est nécessaire d’ajouter la méthode manquante. Eclipse va générer automatiquement le code manquant et l’ajouter à la suite du code existant.

Expliquons le rôle de la méthode public void onClick(View arg0). Cette méthode va permettre de lancer les traitements suite à l’action sur le bouton. C’est dans cette méthode que nous allons déclarer et récupérer l’élément EditText et le TextView.

Dans un premier temps, nous allons déclarer notre champ de saisie de la même façon que le bouton sauf que nous casterons le résultat de la méthode avec la classe EditText.

Puis nous allons récupérer la valeur du champ de saisie à travers l’objet et_SaisieNom de la classe EditText. Pour cela nous allons appeler la méthode getText() puis pour être sûr de bien récupérer une chaîne de caractères, nous appelons la méthode toString() de la manière suivante :

(Au préalable, nous créons la variable valueNom de type String pour récupérer le résultat)

Après avoir récupéré la valeur du champ de saisie, nous allons transmettre le contenu de la variable valueNom dans le TextView prévu à cet effet.

Nous allons déclarer comme nous l’avons fait précédemment un « lien » entre l’objet que nous allons créer et le libellé qui nous intéresse. En recherchant ce dernier par son id et en castant ce dernier comme un objet de la classe TextView :

Une fois avoir fait le lien entre l’élément graphique et notre objet, nous pouvons transmettre la valeur récupérée dans le champ de saisie pour afficher cette dernière dans le champ libellé. Nous allons utiliser la méthode setText() pour attribuer la valeur :

Nous venons donc de terminer notre premier projet. Il est temps de tester ce dernier sur un terminal en suivant la procédure de déploiement expliquée dans la prochaine sous-partie.

Information : Le code source du projet ainsi que tout son contenu est disponible dans le dossier Codes\Tutoriel. Vous y retrouverez le code XML, le fichier JAVA etc.

Déploiement du projet

Afin de déployer un projet Android sur un terminal, il est nécessaire de configurer le projet pour cette action. Cette étape est nécessaire que ce soit pour émuler notre projet ou déployer celui-ci sur un appareil.

Pour cela, sélectionnez dans la barre d’outils et cliquez sur.

Dans la fenêtre qui vient de s’ouvrir sélectionnez dans la colonne de gauche, puis cliquez sur en haut de cette même colonne afin de paramétrer un projet Android.

Dans le champ Name : indiquez le nom que vous souhaitez. Je vous conseille d’indiquer le nomDevice_nomProjet afin de pouvoir se retrouver plus facilement dans le cas où plusieurs projets seraient en cours de développement.

Puis dans la section Android, dans le champ Project : cliquez sur le bouton Browse… pour choisir le projet que vous souhaitez exporter.

Sélectionnez l’action Launch Default Activty. Puis cliquez sur Apply.

Après avoir cliqué sur Run, regardez la zone 3 et ouvrez l’onglet Console. Vous devriez avoir une interface similaire à celle ci-dessous.

Le projet a été déployé sur le terminal. Regardez l’écran de ce dernier pour voir qu’il est sur l’interface par défaut de notre application.

Il ne reste alors qu’à tester notre application. Remplissez le champ de saisie, puis validez.

Information : Petit rappel sur les différents types ainsi que la portée des variables, méthodes ou d’une classe.

TypesPortéeRemarques
PublicLes variables, méthodes ou classes publiques sont accessibles par tout objet.Il ne peut y avoir qu’une seule classe publique par .java et celle-ci doit obligatoirement porter le nom du fichier .java
ProtectedLes variables, méthodes ou classes définies comme protégées ne sont accessibles que par les classes filles et classes du même package.
PrivateLes variables, méthodes ou classes définies comme privées ne sont accessibles que par la classe dans laquelle elles sont définies.Il est fortement conseillé de déclarer comme privés tous les attributs d’une classe, et de créer des méthodes getters/setters pour y accéder.
Les variables, méthodes ou classes définies sans modificateur sont accessibles par toute classe appartenant au même package.Attention : les variables sans modificateur ne sont pas accessibles aux classes filles définies dans un autre package.
StaticSe trouve devant une variable (ou méthode) indique que celle-ci n’appartient pas à une instance particulière de la classe. Les variables ou méthodes statiques appartiennent à la classe elle-même.On peut aussi manipuler une variable ou méthode statique à partir d’une instance de la classe. Pour faire des variables statiques des constantes, il faut combiner le mot-clé static avec le mot-clé final. Les méthodes statiques, étant indépendantes de toute instance, n’ont pas accès aux variables ou méthodes non statiques.
FinalDevant une méthode :

On indique que cette méthode ne pourra plus être redéfinie dans une classe fille. Ce qui entraîne une certaine optimisation dans les appels à cette méthode.

Devant une classe :

On ne peut pas créer de classe dérivée de celle-ci. Par exemple il est impossible de dériver une classe à partir de la classe String de la bibliothèque de base. La solution consisterait à « encapsuler » String dans une classe de notre conception.

Devant une variable membre ou une variable locale :

La variable ne peut plus être modifiée après son initialisation, et doit obligatoirement être initialisée une fois.

Débogage

Le débogage est d’une importance capitale lorsque l’on développe en Java, et encore plus lorsque nous sommes amenés à tester une application sur un terminal. Pour cela il est nécessaire d’autoriser le débogage USB de l’appareil.

Activation du débogage sur un terminal

Sur le terminal, cliquez sur le bouton Settings. Puis recherchez dans la listView l’élément suivant. L’écran bascule vers une nouvelle listView. Recherchez dans cette liste l’élément suivant (dernier élément de la liste).

Cochez les 2 check box comme ci-dessous :

De cette façon, nous venons d’activer le débogage USB. Nous allons voir maintenant comment interpréter le LogCat.

Interpréter le LogCat

Positionnez-vous dans la zone 3 de l’interface principale (cf. précédemment). Sélectionnez l’onglet LogCat . Nous avons donc l’interface suivante :

La zone 1 permet de sélectionner le paquet que l’on souhaite analyser dans le projet que nous venons de compiler. Il est utile dans le cas de projet volumineux de filtrer les paquets afin de ne pas être submergé d’informations.

La zone 2 permet de choisir le type de message que l’on souhaite faire apparaître dans la zone 3.

Chaque type d’information a un code couleur particulier ainsi qu’un niveau d’affichage :

  • Verbose en noir, affiche toutes les informations.
  • Debug en indigo, affiche toutes les informations sauf la couche Verbose.
  • Info en vert, affiche toutes les informations sauf la couche Verbose et Debug.
  • Warning en orange, affiche seulement les erreurs et les avertissements.
  • Errors en rouge n’affiche que les erreurs.

Afin de pouvoir faire la différence entre ces messages d’erreurs, voici un exemple de chaque cas :

Pour une information de type debug du display :

Pour une information de type information :

Pour une information de type warning :

Pour une information de type erreur :

De cette façon, il est possible en testant l’application sur le terminal de récupérer les événements et les informations que celui-ci retourne. Là où le LogCat est puissant c’est qu’il permet d’afficher les System.out.println(); ce qui permet de faire du débogage ligne par ligne (qui est parfois la seule solution face à certaines erreurs rencontrées).

PARTIE II

À partir de ce stade, nous considérerons la découverte d’Android ainsi que de son environnement comme acquis. Les présentations et les explications qui vont suivre ciblent des fonctionnalités bien précises demandant une connaissance avancée de Java ainsi que de la programmation orientée objet. Les méthodes et fonctions de base utilisées seront décrites brièvement et non en profondeur. Pour plus d’informations sur Java je vous renvoie à la section Bibliographie de la partie Source à la fin de ce document ainsi qu’à la Javadoc.

Manipulation et utilisation des éléments graphiques

Dans cette partie, nous verrons comment utiliser et créer certains éléments graphiques qui permettent de rendre une interface ergonomique et agréable pour l’utilisateur. Certains éléments sont plus difficiles à mettre en place et à utiliser que d’autres. De plus, certains éléments sont utilisables en tant que conteneur et d’autres comme contenu. Libre à vous selon vos idées et vos goûts de chercher à mettre en œuvre votre solution.

Les Boîtes de dialogue

Les boîtes de dialogue sont des outils indispensables pour informer l’utilisateur et pour aider ce dernier à choisir l’issue d’une action lors d’une opération critique (suppression de données par exemple). Nous verrons par la suite deux types de boîte de dialogue. Les boîtes de dialogue standard qui ont pour but d’informer l’utilisateur et les boîtes de dialogue permettant de réaliser une saisie.

Boîte Standard

Ci-contre, nous avons la méthode qui permet de créer les boîtes de dialogue (mais pas de les afficher). Par défaut, cette méthode ne prend pas de paramètre. Or une application doit gérer plusieurs situations en fonction des erreurs levées.

Dans l’application où est extraite cette partie de code, nous avons choisi d’attribuer chaque type d’erreur par un identifiant numérique. Car nous ne réalisons pas une boîte de dialogue pour chaque erreur.

Nous utilisons un seul layout que nous adapterons en fonction du code d’erreur.

Dans un premier temps, nous instancions un objet box de la classe Dialog. Nous allons faire le lien entre notre objet box et le layout souhaité. Dans notre cas, ce sera le layout créé pour notre boîte de dialogue.

Suivant le code d’erreur, il suffira de modifier le libellé de description via  et le titre de notre boîte de dialogue via. Finalement, nous retournerons la boîte de dialogue après avoir renseigné les champs.

Pour afficher notre boîte de dialogue, nous utiliserons la méthode en remplaçant 30 par l’id de la boîte de dialogue que nous souhaitons afficher.

Boîte d’Alerte

Graphique

Créons un nouveau fichier xml de type layout en ne définissant qu’un champ de saisie et un champ libellé. (Code ci-contre). Nous ne définissons pas de bouton.

Traitement

Dans un premier temps, nous allons instancier notre layout en tant que vue :

Nous allons créer notre alertbox, puis nous allons affecter la vue personnalisée que nous avons créée à notre AlertDialog à travers la méthode.

Maintenant, nous allons personnaliser notre boîte de dialogue en modifiant le titre de celle-ci. Puis nous allons ajouter deux boutons à notre boîte de dialogue en affectant un évènement de type clic sur les boutons.

Nous allons ajouter un bouton Valider avec l’évènement que nous souhaitons :

Nous ajoutons dans cet évènement les traitements à effectuer sur ce champ.

Créons maintenant le bouton Annuler sur le même type d’événement :

Il ne nous reste alors qu’à afficher la boîte de dialogue via la méthode à la suite des parties de code présentées ci-dessus.

Ainsi nous venons de déclarer et de créer une boîte de dialogue de type alerte avec un bouton permettant de confirmer l’action souhaitée et un bouton permettant d’annuler l’action.

(Ci-dessous nous pouvons avoir un rendu du code présenté)

Astuce : Rien ne nous empêche de faire une boîte de dialogue à 3 voire 4 boutons. Généralement au-delà de 3 boutons, il faut adapter une solution plus adaptée et plus ergonomique.

TabHost

Cet élément graphique est assez important lorsque nous souhaitons réaliser une interface de paramétrage.

L’ajout d’onglet permet sur une interface d’afficher plusieurs vues. La manipulation de ce widget est assez lourde à mettre en place car elle nécessite de nombreux processus de création. D’une manière générale, voici la structure d’une interface comportant un TabHost :

Graphique

Création du TabHost : Conteneur

Dans un premier temps nous allons définir l’interface graphique de notre conteneur TabHost qui sera notre Layout principal comportant un titre et le conteneur (notre TabHost).

(Ci-dessus en rouge notre TabActivity principale :: conteneur, en violet l’Activity contenue dans la tabActivty)

Création d’un onglet

Nous allons définir le fond et le style de notre onglet dans un fichier xml différent.

Nous allons mettre dans ce dernier un textView afin d’indiquer dans quel onglet nous sommes. Il est possible d’ajouter une image si nous le souhaitons.

Par exemple :

Création des onglets : Vues

Ci-contre nous avons le code permettant de réaliser le contenu de nos onglets.

Ce code est abrégé car nous nous servons de cette interface pour de nombreux écrans (il suffit de changer la valeur de ces champs et d’activer ou non la visibilité de ces derniers afin de l’adapter au contexte dans lequel nous sommes).

Comparé au code précédent, celui-ci va contenir tous les champs libellés, saisies, boutons etc.

Ainsi, il sera nécessaire de créer autant de Layout que nous souhaitons mettre d’onglets dans notre TabHost.

Il est possible de créer un seul Layout et d’adapter celui-ci pour chaque action sur un onglet, bien que déconseillé dans la mesure où un changement graphique de notre Layout entraîne de lourdes modifications.

Traitement

Afin de ne pas faire une erreur critique lors de l’exécution de notre application, il est nécessaire de déclarer nos Layout dans le fichier AndroidManifest.xml de notre projet afin de pouvoir appeler et utiliser ces derniers.

Dans les parties qui vont suivre, nous allons expliquer comment manipuler et gérer les traitements sur notre Tab Host en héritant notre classe de la classe TabActivity. Dans un second temps nous verrons comment appeler et gérer les traitements contenus dans notre TabHost.

Nous allons prendre comme exemple la création de l’interface de paramétrage système comportant 2 onglets :

  • Un onglet comportant les paramètres actuels
  • Un onglet comportant les paramètres à modifier
TabActivity : Conteneur

Comme nous avons l’habitude de faire, nous créons une nouvelle classe. Nous allons étendre cette dernière à la classe TabActivity et non Activity.

Nous allons définir un objet tabHost de la classe TabHost en tant qu’attribut de notre classe afin de manipuler le widget que nous avons créé.

Dans la méthode onCreate() nous appelons le layout principal soit notre TabHost (conteneur) . Nous établissons la relation entre l’élément graphique et notre logiciel en récupérant l’élément graphique.

Maintenant, nous créons les deux onglets via la méthode setupTab() prenant en paramètre le nom que nous souhaitons donner à l’onglet, en identifiant l’onglet et la vue (le contenu) qu’il doit charger en précisant l’interface dans laquelle nous sommes vers l’interface cible.

La méthode createTabView() va permettre de charger le fond que nous avons défini pour nos onglets dans notre tabHost. Pour cela, nous allons créer un objet view de la classe View en indiquant le context de notre tabActivity et en précisant le layout de notre onglet.

Puis nous modifierons le champ de texte afin de mettre le titre d’onglet que nous souhaitons.

Activity : Contenu
Nous créons une classe par vues que nous appellerons. Cette dernière héritera de la classe Activity. Les traitements qui seront effectués sont les mêmes que pour une activité standard.

C’est pourquoi nous ne nous étendrons pas sur le contenu de cette classe.
Si nous déployons notre application, nous devrions obtenir les interfaces ci-dessous. Naturellement, il y a la possibilité de personnaliser les onglets selon les contraintes demandées.

Bouton radio

Graphique

Ci-contre, nous avons la section de code permettant de définir des boutons de type radio.

Il est nécessaire de contenir ces derniers dans un conteneur RadioGroup afin de gérer ces derniers de manière cohérente.

Il est possible de définir la valeur par défaut des boutons via.

Traitement

Dans la méthode onCreate() nous allons déclarer un objet group1 de la classe RadioGroup. Puis nous allons relier cet objet avec l’id de notre radioGroup. Afin de pouvoir modifier ces valeurs.

Nous déclarons un évènement sur ce champ via la méthode onCheckedChanged(). Il sera nécessaire d’implémenter notre classe afin de rendre cette dernière sensible au type d’événement que nous utilisons.

Dans la méthode onCreate() :

Méthode qui gère les événements :

De manière globale, la mise en place de ce type de saisie ne pose aucune difficulté. Le seul point sensible est de bien gérer l’état des boutons une fois cochés.

(Ci-dessus la représentation graphique d’un RadioGroup à 2 éléments)

Menu

Lors de la création d’une Activité, cette dernière ne comporte pas de menu. Pour cela, nous allons créer un menu composé de boutons permettant par exemple de quitter l’application (en tuant l’activité).

Pour créer un menu nous allons comme d’habitude créer un nouveau fichier android.xml. Nous préciserons cependant lors de la procédure de configuration de notre fichier que nous souhaitons un fichier de type menu :

Une fois la procédure de création terminée, nous remplirons ce fichier en rajoutant des boutons dans notre menu.

Information : Il est possible de faire des sous-menus dans notre menu. Pour ça, il suffira entre les balises <menu><item>…</item></menu> de rajouter une balise <menu/> contenant des balises <item/>

Graphique

Dans notre cas, nous souhaitons avoir 4 boutons.

Nous allons donc déclarer 4 items. En donnant un libellé pour chaque item.

Il sera nécessaire de définir le type d’action sur lequel chaque bouton se déclenchera.

Traitement

Pour la phase de traitement, nous aurons automatiquement comme pour la création de l’interface une méthode de type onCreate(). Dans le cas d’un menu, cette méthode s’appelle onCreateOptionsMenu() et prend en argument un objet de la classe Menu.

Dans cette méthode, nous instancierons un objet inflater de la classe MenuInflater, puis nous appellerons le menu que nous avons créé précédemment via la méthode inflate() de notre objet inflater.

Cette méthode permet d’afficher l’interface de notre menu quand nous appuyons sur le bouton physique du terminal.

Cependant, nous n’avons pas encore mis en place l’action sur les boutons.

Méthode Création du menu

Méthode qui gère les événements sur le menu

Pour déclarer et manipuler les événements sur les items de notre menu, nous allons créer une autre méthode :

Nous récupérerons en premier lieu l’ID de l’item sélectionné via la méthode getItemId() de l’objet item. Puis nous suivrons la même procédure expliquée plus loin dans cette recette pour changer d’Activité.

En guise de résultat, nous devrions lors d’une action sur la touche faire apparaître le menu suivant :

Si rien ne s’affiche ou si l’application est tuée suite à une fatale error, vérifiez que vous avez bien déclaré le fichier menu.xml dans le fichier AndroidManifest.xml de votre projet.

C’est un oubli récurrent, qui s’identifie assez rapidement (LogCat et évidence).

Manipulation de fichier XML

Dans le monde industriel, il est impensable de fournir une application qui ne comporte pas de fichier de configuration. Bien qu’il existe plusieurs types de fichier de configuration (fichier.sys, fichier.bat, fichier.ini, fichier.conf, fichier.rc, fichier.xml etc.), nous verrons comment générer et manipuler un fichier XML.

L’avantage qu’offre l’extension XML permet de mettre en œuvre une hiérarchisation des données via l’encapsulation des balises. Ces dernières jouant un rôle de clef dans le fichier permettant de retrouver rapidement une valeur.

Fichier XML

(vide)
Fichier XML

(comportant des valeurs)

Il n’existe pas de librairie par défaut dans Eclipse pour manipuler les fichiers XML. Pour pouvoir écrire et lire un fichier XML, il sera nécessaire d’utiliser deux API :

  • SAX (Simple API for XML)
  • JDOM (Java Document Object Model).

Vous trouverez la librairie dans le répertoire :

Librairies\jdom-2.0.4

Dans le cas où celle-ci ne serait pas présente, vous pouvez télécharger cette dernière en suivant le lien ci-dessous:

http://www.jdom.org/dist/binary/

Pour ajouter une librairie, veuillez vous reporter à la section traitant ce sujet dans la partie I.

Avant de voir les différentes phases de manipulation d’un fichier XML, nous allons expliquer et décrire les attributs ainsi que le constructeur de la classe permettant de mettre en œuvre cette fonctionnalité.

Créez une nouvelle classe CXML.java.

Nous déclarons un attribut static org.jdom2.Document afin de déclarer un objet document qui contiendra notre future structure XML.

Nous déclarons un objet racine de la classe Element qui sera la racine de notre XML.

Nous instancions un objet sxb de la classe SAXBuilder afin de créer une instance de SAXBuilder().

Notre constructeur prendra en paramètre le chemin où nous souhaitons écrire/ lire notre fichier XML et qui initialisera notre objet fichierConfig de la Classe File.

Création de l’arborescence, Vérification d’existence

Dans notre classe, il va falloir vérifier dans un premier temps si le fichier config.xml existe dans le répertoire que nous avons ciblé. Afin de savoir si nous devons créer le fichier XML ou non. Avant de vérifier l’existence de notre fichier de configuration, nous devons vérifier si nous avons accès à la zone de stockage externe (SDCARD). C’est en fonction du résultat de cette méthode que nous pourrons chercher l’existence ou non du fichier config.xml.

Ajoutez les permissions suivantes (si elles ne sont pas déjà présentes) au fichier AndroidManifest.xml de notre projet:

La méthode ci-contre permet de vérifier si l’accès à la mémoire externe est possible ou non.

La méthode retournera un booléen en guise de résultat. True si l’accès à la mémoire externe fonctionne et False dans le cas contraire.
Nous devons donc savoir à quel état notre zone de stockage externe est accessible. Est-elle accessible en lecture et écriture ? Seulement en lecture seule ? ou tout simplement inaccessible ?

Pour cela, nous allons comparer la valeur de Environment.MEDIA_MOUNTED avec la valeur retournée par la méthode Environment.getExternalStorageState(). Si la comparaison est vraie, alors nous avons un accès total à la zone de stockage externe.

Dans le cas où la SDCARD serait en lecture seule, il nous faudrait alors comparer la valeur retournée par la méthode Environment.MEDIA_MOUNTED_READ_ONLY() avec Environment.getExternalStorageState(). Dans ce cas nous saurons que la zone de stockage externe est en lecture seule.

Sinon, la zone de stockage externe est inaccessible. Cela relèverait d’un problème matériel et/ou d’un problème logiciel (confrontation logicielle, malware, virus etc). Bien que dans la majorité des cas le problème reste d’ordre matériel.

La méthode ci-contre comme dit ci-dessus permet de vérifier l’existence du fichier xml dans le répertoire indiqué.

Cette fonction retournera une liste de chaîne de caractères de la méthode lectureXML().

Dans la première condition, nous vérifions l’accès à la zone de stockage externe via la méthode décrite précédemment. Si la condition est réalisée nous déterminerons si le fichier de configuration existe grâce à la méthode exists() de l’objet fichierConfig. Si le fichier existe, alors nous initialiserons la variable arg à True.

Si ce n’est pas le cas, alors le fichier n’existe pas. Nous devons le créer via la méthode createNewFile() de l’objet fichierConfig, puis appeler la méthode ecrireArborescence() pour générer notre fichier xml (cf. ci-dessous). Nous actualisons la valeur de notre booléen. En cas d’erreur, le bloc try/catch lèvera un message d’erreur.

Il ne reste alors qu’à retourner le résultat de la lecture du fichier config.xml pour exploiter les valeurs que celui-ci contient en appelant la méthode lectureXML() en passant en argument la valeur de notre booléen.

Pour l’écriture de l’arborescence, nous ne présenterons que la création de la racine principale <CONFIGURATION> … </CONFIGURATION> et de la sous-racine <SGBDD> … </SGBDD> et de son contenu. Pour créer d’autres sous-racines contenant d’autre(s) élément(s), il suffira de reprendre la procédure décrite.

La méthode ecrireArborescence() comme son nom l’indique permet de générer l’arborescence de notre fichier xml.

Nous créons un nouvel objet configuration de la classe Element en initialisant celui-ci via le constructeur new Element(« Configuration »). Ainsi nous venons de créer notre balise Configuration.

Il nous reste alors à ajouter notre balise à notre document. Cela se fait en déclarant un nouvel objet document de la classe org.jdom2.Document en l’initialisant via son constructeur (new Document())en lui passant en paramètre l’objet configuration.

Maintenant, nous allons ajouter une sous-racine SGBDD à la racine que nous venons de créer.

Comme précédemment nous créons un nouvel objet sgbdd de la classe Element en définissant celui-ci par new Element(« SGBDD »).

Nous venons de générer notre balise SGBDD.

Il faut maintenant que nous ajoutions cet élément à l’élément Configuration créé ci-dessus.

Pour cela il suffit d’appeler la méthode addContent() de l’élément qui va contenir notre élément passé en paramètre. Dans notre cas l’objet configuration va contenir notre objet sgbdd :

configuration.addContent(sgbdd)

Ainsi nous venons d’ajouter la balise <SGBDD\> dans la balise <CONFIGURATION>…</CONFIGURATION>.

Nous allons ajouter les éléments à la sous-racine <SGBDD\> en suivant la même méthode que précédemment. Pour ajouter l’élément HOST, nous allons créer un objet host de la classe Element en définissant celui-ci par new Element(« HOST »). Puis pour ajouter cet élément à la sous racine SGBDD. Il suffira de spécifier le nom de l’élément parent qui va contenir notre balise HOST.

Via la méthode addContent().

Soit :

sgbdd.addContent(host)

Ensuite nous réitérerons l’action autant de fois que nous aurons d’élément à ajouter dans la sous-racine SGBDD.

Puis il faudra créer de nouvelle sous-racine dans notre racine CONFIGURATION, etc.

En dernier lieu, nous devons enregistrer notre arborescence dans le répertoire que nous avons spécifié. Nous déclarons un objet sortie de la classe XMLOutputter que nous initialisons par son constructeur en fournissant en argument le format que nous souhaitons en appelant la méthode Format.getPrettyFormat(). Pour enregistrer notre fichier, il suffira d’utiliser la méthode output() de l’objet sortie en indiquant en paramètre l’objet document, et en second argument le flux de sortie de notre fichier contenu dans l’objet fichierConfig.

Nous venons ainsi d’écrire l’arborescence de notre fichier XML.

Maintenant que nous avons vu comment contrôler l’accès à la mémoire externe du terminal et en vérifiant si le fichier est déjà présent ou non nous allons voir comment lire et écrire dans ce fichier.

Lecture

Cette méthode va nous permettre de pouvoir lire notre fichier xml. Il prend en paramètre la variable booléenne renvoyée par la méthode existence(). La méthode retournera le résultat des données contenues entre les balises dans une liste de chaîne de caractères.

Si l’argument passé en paramètre est vrai alors nous pouvons lire le fichier xml.

Dans un premier temps nous allons parser le fichier à travers la méthode build() de l’objet sxb en passant en paramètre le constructeur new FileInputStream(fichierConfig).

Nous initialisons la racine de notre arborescence en appelant la méthode getRootElement() de l’objet document.

Puis nous allons initialiser et instancier une liste d’objet Element contenant tous les nœuds de la sous-racine SYSTEM via la méthode getChildren() de l’objet racine en fournissant en paramètre le nom de la balise. Soit pour récupérer le contenu de la balise SYSTEM :

List<Element> listSYSTEM=racine.getChildren(« System»)

Nous allons déclarer un objet i de type Element de la classe Iterator que nous instancierons par le contenu de notre objet listSGBDD par la méthode iterator(). De cette façon nous créons un Iterateur sur notre liste. Puis nous allons créer un objet courant de la classe Element que nous initialiserons par le contenu de notre iterator. En castant celui-ci en tant qu’objet Element et en parcourant tout son contenu par la méthode next().

Il ne nous reste alors qu’à récupérer la valeur de chacune de nos valeurs contenues dans la sous-racine SYSTEM.

Par le biais de la méthode add() de notre liste maListe nous spécifions en paramètre l’index de notre liste, puis la valeur que nous voulons ajouter.

La valeur que nous souhaitons ajouter, (c’est-à-dire la valeur contenue entre nos balises) nous devrons passer par la méthode suivante :

getChild(«nomDeLaBalise»).getText() de l’objet courantSystem

Si le nom de la balise ne correspond pas, nous lèverons une erreur via le bloc try/catch.

Ainsi nous venons de lire toutes les valeurs contenues dans la sous racine SYSTEM. Pour récupérer le contenu des autres éléments des sous-racines de notre fichier xml, il suffit de suivre le même principe.

Puis nous retournerons la liste que nous venons de remplir à la fin de notre méthode.

Écriture

Pour l’écriture de données dans le fichier de configuration la méthode est la même d’une sous-racine à une autre à l’exception que le nombre de champs à renseigner lors de l’écriture va varier. Nous verrons ci-dessus comment écrire les données relatives à la sous-racine SYSTEM.

La méthode ecritureSystem() présentée ci-dessous prend plusieurs arguments. Il prend l’état d’accessibilité et d’existence du fichier xml sur la SDCARD, une liste de chaîne de caractères contenant les paramètres à écrire et un second booléen qui a pour but de confirmer l’enregistrement.

Pour les options systèmes, nous demandons lors du changement du mot de passe à l’utilisateur de bien vouloir confirmer son souhait de modifier ce dernier (présence du dernier booléen).

Si l’argument passé en paramètre est vrai alors nous pouvons lire le fichier xml.

Nous allons parser le fichier à travers la méthode build() de l’objet sxb en passant en paramètre l’objet fichierConfig.

Puis nous initialisons la racine de notre arborescence en appelant la méthode getRootElement() de l’objet document.

Nous déclarons comme vu ci-dessus un iterator sur notre liste d’élément. Puis nous allons créer un objet courant de la classe Element que nous initialiserons par le contenu de notre iterator. En castant celui-ci en tant qu’objet Element et en parcourant tout son contenu par la méthode next().
Si la condition est réalisée, nous allons écrire dans le fichier les données saisies et/ou retournées par le terminal. Nous allons utiliser la méthode getChild() de l’objet courant en spécifiant en argument le nom de la balise que nous souhaitons modifier. Puis nous utilisons la méthode setText() afin d’écrire la valeur correspondante dans notre liste.

Par exemple pour saisir la valeur de l’adresse IP nous aurions :

courant.getChild(« IP »).setText(listParam.get(0))

En dernier lieu, nous devons enregistrer les données que nous avons modifiées/créées dans le répertoire spécifié.

Nous déclarons un objet sortie de la classe XMLOutputter que nous initialisons par son constructeur en passant en argument le format que nous souhaitons par la méthode Format.getPrettyFormat(). Pour l’enregistrement il suffira d’utiliser la méthode output() de l’objet sortie en passant en paramètre l’objet document et en second argument le flux de sortie de notre fichier contenu dans l’objet fichierConfig.

Nous venons d’écrire dans notre fichier de configuration les valeurs saisies et/ou fournies par le terminal sur l’action de l’utilisateur.

Attention : Pour des raisons pratiques, nous ne pouvons pas crypter les données du fichier de configuration. Car en cas d’intervention les données ne seraient pas lisibles. Le fichier étant visible de tous, une solution simple serait de limiter la navigation de l’utilisateur sur le terminal ou d’attribuer/limiter les droits d’accès au répertoire contenant ces données. Étant sur une architecture UNIX cela devrait être réalisable.

Base de données

Pour mettre en œuvre les fonctionnalités demandées, il est nécessaire d’utiliser une base de données. Afin de bien comprendre les parties suivantes que ce soit du côté de la base de données interne ou de la base de données externe, il est important d’avoir une représentation de la structure de la base de données à travers le modèle conceptuel de données (MCD) suivant :

À partir de ce MCD, nous allons être capables de mettre en place la BDD mère (côté serveur) et d’établir la BDD fille (côté client). Comme nous réaliserons par la suite une synchronisation entre la BDD mère et la BDD fille, la structure des deux BDD doit être identique.

Base de données interne : SQLite 3

Android permet de stocker et d’organiser des données en interne. Ainsi, chaque APP (application) peut posséder une base de données, aussi bien qu’une APP peut partager le contenu de sa BDD (base de données) avec une ou plusieurs autres APPs.

Pour cela, Android comporte un moteur de base de données léger et assez puissant, nommé SQLite.

Dans cette sous partie, nous allons voir comment générer une base de données SQLite, comment effectuer des requêtes sur une BDD (SELECT, UPDATE, DELETE etc.).

Mais avant de voir comment réaliser tout cela, nous allons installer un plugin permettant d’afficher le contenu ainsi que la structure d’une base de données embarquée sur le terminal.

Plugin SQLiteManager

Le plugin se trouve dans le dossier Plugin\SQLiteManager. Dans le cas où ce dossier serait vide ou inexistant, vous pouvez télécharger ce dernier via le lien suivant :

http://www.coderzheaven.com/android1/com.questoid.sqlitemanager_1.0.0.jar

Une fois en possession du fichier com.questoid.sqlitemanager_1.0.0.jar, déplacez celui-ci dans le dossier C:\Eclipse\juno\dropins. Si Eclipse est démarré, redémarrez-le. Sinon lancez l’IDE.

Connectez un de vos appareils Android (préalablement installé et fonctionnel sous Eclipse) et dans la zone d’information (zone 3) sélectionnez l’onglet File Explorer. Afin de voir le contenu ou la structure de la base de données sélectionnez une base de données (fichier.db), représentée par 1 (image ci-dessous).

Vous verrez alors que l’icône représentant une data base représentée par un 2 est devenue active ( ).

Cliquez sur ce bouton.

Cette action va ouvrir un nouvel onglet Questoid SQLite Manager. Comportant 2 sous-onglets : DataBase Structure et Browse Data.

Dans l’onglet DataBase Structure, nous allons retrouver la structure de la base de données contenue dans le fichier que nous avons sélectionné. Nous retrouvons ainsi la syntaxe SQL de création de la table dans la colonne Schema, ainsi que la structure sous forme d’arborescence.

Dans l’onglet Browse Data, nous pouvons voir le contenu d’une table en sélectionnant cette dernière grâce à la liste box.

Quel est l’avantage d’un tel outil ? La réponse est simple, un fichier .db comporte une quantité de caractères non affichables qui rend le parcours de celui-ci dans un éditeur de texte très difficile.

De plus il est plus facile lors de manipulation de la base de données de vérifier les insertions et autres actions en utilisant cet outil que de créer une méthode de requête spécifique en guise de débogage.

Création et Manipulation d’un fichier .db

Avant de commencer l’explication du code de création et de manipulation de la base de données, quelques explications sont nécessaires.

La création d’une base de données sous Android se découpe en 3 types de classes ayant chacune un rôle précis :

  • Le premier type de classe va permettre de générer la base de données, de mettre à jour les données, d’ouvrir la base et de vérifier l’existence de la BDD sur le terminal.
  • Le second type de classe va permettre de construire les requêtes, de préparer les insertions de données et d’appeler les méthodes d’ouverture et de fermeture de la BDD du premier type de classe.
  • Le troisième type de classe est particulier. Il y aura autant de fichier.java de ce type qu’il y a de table dans notre BDD (contrairement aux 2 types de classe présentés ci-dessus qui ne comportent qu’un seul fichier). Ce type de fichier comportera tous les champs de chaque table, de telle façon que lorsque nous réaliserons une insertion nous instancierons un objet en renseignant les champs de cette classe (donc de notre table) par les valeurs saisies par l’utilisateur. Inversement, nous instancierons un objet lorsque nous rechercherons un objet dans la base de données. Nous utiliserons alors les getters et les setters.

Au final, nous utiliserons essentiellement le second type de classe pour communiquer avec la BDD.

Avant de commencer à coder, il est intéressant de créer un nouveau package dans notre projet. Cela rendra ce dernier plus lisible et mieux organisé. Donc dans le dossier src\ créez le package suivant.

Information : Par défaut, la base de données est générée dans le répertoire \data \com.nomProjet\data\monFichier.db. Cependant, pour avoir accès à ce dernier via l’explorateur de fichiers, le terminal doit être rooté (cette mesure de sécurité est fréquente et bien connue du monde UNIX, où il est demandé à l’utilisateur de passer en mode super-utilisateur). Ne pouvant rooter le terminal, nous allons indiquer à notre application de générer le fichier de BDD sur le périphérique de stockage externe : la SDCARD.

L’avantage qu’offre cette solution, est qu’elle permet l’utilisation et le partage des données à d’autres applications que l’application l’ayant créée.

Ce qui demande d’ajouter une permission à notre fichier AndroidManifest.xml :

Création des tables de notre BDD

Nous allons donc commencer à créer toutes les classes en relation avec notre MCD. Nous ne réaliserons et expliquerons la construction d’une telle classe qu’une seule fois. Il suffira d’adapter la méthode pour les autres classes.

Nous créons la classe CAdresse dans le package que nous venons de créer. Nommez le CAdresse.

D’après le MCD, nous savons que la table « adresse » comporte :

Nom du champType (BDD)DescriptionType (Java)
IDInt(11)Identifiant de l’adresse dans la table.Int
NUMEROInt(11)Numéro de rue/avenue/boulevard etc.Int
NOMRUEVarchar(255)Nom de la rue.String
NOMVILLEVarchar(255)Nom du village, ville, hameau etc.String
CODEPOSTALInt(11)Code Postal de la ville, hameau, etc.Int
PAYSVarchar(255)Nom du pays.String
HMODIFdatetimeHeure de création et de modification.String
Pour le moment, notre classe CAdresse de notre fichier CAdresse.java ressemble à l’image ci-contre.
Nous allons donc ajouter les attributs à notre classe nous aidant du tableau ci-dessus. Puis ajouter notre constructeur. Vous devriez avoir la classe ci-contre :

Ayant défini nos attributs en tant qu’attributs private, il ne nous reste plus qu’à créer nos getters et setters.

Astuce : Lorsque vous utilisez des attributs « private » l’icône apparaît dans la marge. Eclipse peut alors générer pour vous les getters et setters. Faites un clic sur l’icône et sélectionnez.

Personnellement, je vous conseille d’ajouter une méthode supplémentaire à votre classe CAdresse. La méthode. Cette méthode permet de retourner une chaîne de caractères en affichant le contenu de tous les attributs de l’objet que vous aurez instanciés et renseignés :

Ainsi vous pouvez appeler cette méthode avant de vérifier le contenu de votre objet et avoir une trace dans le LogCat en guise d’information (débogage).

Au final, votre fichier CAdresse.java doit être similaire à l’image ci-dessous :

(Image 1/2)(Image 2/2)

Maintenant que nous venons de terminer la classe CAdresse permettant de renseigner le contenu de la table adresse de notre base de données usagiAka. Créez les classes manquantes en suivant la procédure ci-dessus.

Une fois avoir créé toutes les classes nécessaires vous devriez avoir dans votre package les fichiers « .java » suivants, chacun avec leurs propres attributs :

De manière globale, nous pouvons retenir :

  • Une classe (en java) est équivalente à une table (en SQL).
  • Les attributs d’une classe (en java) sont équivalents aux champs d’une table (en SQL).
Génération de la BDD

Maintenant nous allons créer une nouvelle classe CUsagiAkaBDD qui va nous permettre de définir les tables qui seront produites lors de l’instanciation de cette dernière. La classe que nous avons créée hérite de la classe SQLiteOpenHelper qui est une classe d’assistance pour gérer la création de bases de données.

Dans cette partie, nous allons définir les attributs comme des constantes pour les noms des tables et les champs de ces dernières.

Constantes (nom des tables)Constantes (nom des champs)

Puis nous allons déclarer 2 attributs de type String que nous initialiserons à null. Ces attributs contiendront le nom de la BDD (SQLite) et le path de cette dernière.

Puis nous allons créer un objet de la classe Context.

Une fois avoir déclaré et initialisé les constantes et attributs, nous devons déclarer les constantes qui permettront de créer les tables. Pour cela, nos constantes de type String doivent contenir les requêtes SQL.

Par exemple avec la table adresse :

Nous retrouvons dans notre requête SQL les constantes définies précédemment. L’avantage de cette méthode de travail permet en cas de modification de la structure de la BDD mère de modifier rapidement le code source de la BDD fille.

Comme vous vous en doutez, il est nécessaire de définir une constante pour chaque ordre de création de table.

Attention : Lors de la définition des requêtes SQL faites attention à ce que les types des champs soient bien identiques à ceux de la BDD mère. Sans quoi il pourrait y avoir par la suite des problèmes d’échanges entre les deux BDD.

Une fois avoir défini toutes vos constantes de création de table, vous devriez avoir à la suite de la création de l’objet context les lignes suivantes :

Pour le moment nous n’avons fait que définir des attributs de chaîne de caractères constants. Maintenant, nous allons créer les méthodes de la classe.

Pour commencer nous allons créer le constructeur de la classe.

Dans le constructeur, nous passons en paramètre le context de l’application qui appelle la méthode, le nom de la BDD, le path de la BDD, la version de la BDD. Pour ce qui est du CursorFactory nous n’avons pas à nous en soucier, celui-ci restera à l’état null quoi qu’il arrive.

La méthode ci-contre permet de vérifier si le fichier .db existe.

Pour cela, nous essayons d’ouvrir le fichier à l’emplacement souhaité. Si l’ouverture est différente de null, c’est que la BDD existe. Dans ce cas la méthode retournera true.

Sinon, elle n’existe pas et il faudra créer la BDD.

La méthode retournera false.

La méthode checkDataBase() est indispensable pour la méthode suivante qui sert à ouvrir la base de données en lecture/écriture.

Dans la méthode openDataBase(), cette dernière essayera d’ouvrir la base de données ciblée en lecture ou en écriture en fonction du résultat retourné par la méthode checkDataBase() vu ci-dessus. Dans l’optique où le fichier .db existe déjà, nous n’avons qu’à ouvrir le fichier et autoriser le droit de lecture et d’écriture.

S’il n’existe pas nous le créerons puis retournerons un objet de type SQLiteDatabase.

Or dans le cas où le fichier n’existe pas, nous créerons ce dernier avec la méthode onCreate(). Comme nous pouvons nous y attendre, cette méthode est surchargée.

Elle prend en argument un objet SQLiteDabase. Nous appellerons ensuite la méthode execSQL de l’objet passé en paramètre qui exécutera une chaîne de caractères en requête SQL.

C’est ici que nous passerons les constantes de création de table déclarées en tant qu’attribut.

De manière générale, cette classe une fois définie n’a plus à être modifiée à moins de changer la structure de notre base de données. Et même si la structure vient à changer il suffirait seulement de modifier/définir les constantes et modifier la méthode onCreate(SQLiteDataBase db).

Interroger et manipuler des données

Maintenant que nous avons vu comment générer la base de données, nous allons voir comment manipuler cette dernière en ajoutant des données, mettre à jour ces données et exécuter des requêtes sur notre BDD fille. Pour cela dans notre packagecréez une nouvelle classe CSqlite.java.

Déclarez de nouveau des constantes pour le nom des tables (faites un copier/coller) :

Puis déclarez à la suite les constantes suivantes :

Les constantes ci-dessus et les attributs sont d’une importance capitale. Nous définissons ici la version de la BDD, ce qui permet en cas de modification du numéro de version d’indiquer au système de mettre à jour la base. Nous indiquons aussi le nom de la base que nous allons manipuler et son chemin.

Puis nous instancierons un objet de la classe SQLiteDatabase que nous initialiserons à null ainsi qu’un objet de la classe CUsagiAkaBDD que nous avons créé précédemment.

Notre constructeur va prendre en paramètre le contexte de l’interface qui l’appelle.

Puis nous initialiserons l’objet usagiAka que nous avons instancié en lui précisant les paramètres (cf constructeur de la classe CUsagiAkaBDD).

Nous appellerons la méthode openDatabase() de cet objet. Puis nous refermerons celui-ci en appelant la méthode close().

Après avoir défini les attributs de notre classe ainsi que son constructeur, nous allons maintenant définir et créer les méthodes permettant de construire les requêtes et manipuler ces dernières. Nous verrons des méthodes universelles pour n’importe quelle base de données et des méthodes non-universelles qui sont propres à la base, mais dont la structure à appliquer reste la même.

Il faut voir le fichier d’une base de données comme l’établissement d’une connexion. Chaque ouverture nécessite obligatoirement une fermeture.

C’est pourquoi ci-contre nous avons la méthode d’ouverture open() et de fermeture close().

La méthode open() permet d’initialiser l’objet bdd initialisé par défaut à null.

Quant à la méthode getBDD() elle permet de retourner la base de données.

Regardons maintenant comment effectuer une requête interrogeant la base de données. (Cette méthode peut être codée autrement. Pour ma part, je préfère retourner le résultat dans un tableau 2D. À vous d’adapter la méthode en fonction de vos habitudes).

Nous passons en paramètre de cette fonction une chaîne de caractères contenant la requête que l’on souhaite exécuter.

Nous exécutons cette requête à travers la méthode rawQuery(requete, null) de l’objet bdd initialisée précédemment qui nous permet d’initialiser l’objet c de la classe Cursor. c va donc contenir le(s) résultat(s) de la requête exécutée.

Nous initialisons notre tableau 2D en récupérant le nombre de lignes et le nombre de colonnes de c.

Nous positionnons le curseur sur la première valeur que celui-ci contient, puis nous remplissons notre tableau 2D en récupérant la valeur du curseur que nous convertissons en chaîne de caractères.

Puis nous incrémentons le curseur jusqu’à ce que celui-ci atteigne la dernière ligne c.moveNext().

Nous retournons le tableau 2D en guise de résultat.

(Pour plus d’informations sur les curseurs voir Programmer en Java)

Après avoir présenté la méthode permettant d’interroger la base de données, nous allons voir la méthode permettant de réaliser l’insertion de données dans la BDD.

Astuce : Privilégiez les structures try/catch à la structure de type throw Exception. Sauf si vous créez vos propres classes d’Exception. L’utilisation du bloc try/catch permet de personnaliser le retour d’erreur de manière assez rapide.

Nous avons fini d’expliquer les méthodes universelles. Maintenant, nous allons voir les méthodes non universelles. Nous allons faire une méthode créant les requêtes d’insertion de chaque classe (c’est pour cela que ces méthodes sont dites non-universelles). Nous allons créer autant de méthodes de génération de requête que de tables dans notre BDD.

(Nous présenterons le fonctionnement d’une seule méthode de génération de requête. Il suffira d’adapter la procédure avec la structure de chaque table).

Nous reprenons notre exemple et nos explications sur la création de la requête d’insertion d’une adresse.

Notre méthode insertAdresse() prend en paramètre un objet de la classe CAdresse que nous avons défini précédemment et initialisé au préalable.

Nous déclarons une variable querry de type String que nous allons initialiser.

Pour la construction de la requête d’insertion, il suffit de suivre la syntaxe de création standard en SQL. Les valeurs à insérer seront accessibles à travers les méthodes getters que nous avons définis dans la classe. Il suffira juste de saisir ces derniers dans le bon ordre afin de ne pas avoir d’erreur lors de l’insertion.

Puis nous appelons la méthode insert() que nous avons expliquée plus haut en passant en argument la requête que nous venons de construire.

Base de données externe

Dans le cas de notre étude, et afin de pouvoir tester la fonctionnalité de web service, il est nécessaire de mettre en place une base de données sur un serveur. Cette BDD sera appelée BDD mère.

C’est-à-dire que toutes les données créées sur les bases de données Filles seront synchronisées avec la BDD mère si ces données n’existent pas déjà.

Or la présence d’une base de données sur un serveur (web dans notre cas) nécessite de mettre en place des règles de sécurité au niveau du firewall ainsi que de la gestion de droits sur la base de données utilisée et non les autres bases présentes.

Information : Le code source du web service est disponible dans le répertoire Codes\serveurWeb\webService. Le code complet de la BDD, ainsi que la structure initiale de la BDD est disponible dans le répertoire Codes\serveurWeb\BDD.

Côté Serveur

Sur le serveur, nous utiliserons la dernière version de WAMP Server. L’installation et le paramétrage de ce dernier n’étant pas cruciaux pour l’accessibilité de ce dernier, nous ne nous attarderons pas sur le sujet. Nous verrons seulement comment configurer l’accessibilité à la base de données et la configuration de PHPMyAdmin. Puis comment ajouter une règle au pare-feu Windows. Nous verrons en dernier lieu, le comportement et le fonctionnement d’un web-service côté serveur.

Paramétrage de WAMP Serveur, PHPMyAdmin

Cette étape est indispensable car le serveur MYSQL ne possède pas de mot de passe pour le compte super-utilisateur : root.

C’est pourquoi, une fois avoir installé WAMP Server sur le poste de développement ouvrez votre navigateur Web.

Saisissez dans votre barre URL l’adresse locale soit puis validez. Sur la page chargée, cliquez sur afin d’être redirigé vers la page de configuration et de gestion des bases de données du serveur Web.

Dans la barre de navigation en haut de page, cherchez le lien suivant et cliquez sur celui-ci.

Vous verrez alors une liste des utilisateurs apparaître. Nous allons modifier les utilisateurs ayant pour nom « root » car ces derniers n’ont pas de mot de passe.

Cochez alors les check box pour tous les utilisateurs identifiés comme root et cliquez sur. Pour définir un mot de passe. Dans la page qui vient de s’ouvrir, rendez-vous dans la section Modifier un mot de passe. Remplissez le champ mot de passe puis ressaisissez-le pour confirmer la modification. Cliquez sur le bouton Exécuter de cette section pour valider les changements.

Réitérez l’opération pour chaque compte root.

Une fois l’opération effectuée, rechargez la page dans votre navigateur. Vous devriez obtenir l’écran suivant :

Ce qui confirme la bonne protection de notre serveur WAMP pour le compte root.

Un problème se pose. Nous avons configuré un mot de passe pour l’utilisateur root, mais nous ne pouvons pas nous connecter. Cela s’explique par le fait que PHPMyAdmin ne connaît pas le mot de passe que nous venons d’attribuer.

Il nous faut alors modifier le fichier config.inc.php se trouvant dans le répertoire.

Ouvrez ce dernier dans un éditeur de texte.

Dans la section /*Server : localhost [1] */ commentez les lignes (// pour commenter en php) et. Puis ajoutez à la suite des deux lignes commentées les lignes suivantes :

Vous devriez avoir la section suivante (image ci-contre) :

La méthode de connexion au service PHPMyAdmin se fera désormais à travers une boîte de dialogue en demandant à l’utilisateur de saisir son login et password.



Enregistrez le fichier que nous venons de modifier et redémarrez les services.

Nous venons donc de sécuriser notre serveur web. Nous allons voir maintenant comment configurer celui-ci pour qu’il puisse être accessible depuis un poste externe.

Dans un premier temps, il va falloir passer le serveur web (WAMP) en ligne. Pour cela, allez dans la barre des tâches de Windows chercher l’icône dans la zone de notification (il se peut que l’icône soit ou si le serveur n’est pas démarré, si c’est le cas démarrez le serveur).

Faites un clic gauche sur l’icône, puis un clic sur afin de passer le serveur en ligne.

Dans un second temps, il sera nécessaire de modifier le fichier phpmyadmin.conf contenu dans le répertoire. Les modifications que nous allons apporter vont permettre d’autoriser les connexions à notre serveur depuis un poste externe.

Pour cela, nous allons autoriser la connexion de n’importe quel appareil.

Supprimez les lignes « Deny from all » et « Allow from 127.0.0.1 » pour les remplacer par la ligne « Allow from all ».

Changez la ligne « Order Deny,Allow » en « Order Allow,Deny ».

Vous devriez avoir le contenu suivant :

Fichier phpmyadmin.conf

(non modifié)
Fichier phpmyadmin.conf

(modifié)

Une fois l’opération de modification effectuée, redémarrez les services.

Nous venons ainsi de rendre le serveur accessible depuis l’extérieur. Cependant, pour pouvoir avoir accès au service PHPMyAdmin, il sera nécessaire de s’identifier (d’où l’importance d’avoir mis un mot de passe sur l’utilisateur root).

Information : Pour tester la connexion depuis un poste externe et/ou un terminal, ouvrez un navigateur web, puis saisissez l’url suivante :

http://adresse_ip_serveurWeb/phpmyadmin

(En remplaçant l’adresse_ip_serveurWeb par l’adresse de votre serveur)

Une fenêtre de dialogue vous demandera comme précédemment de vous identifier pour avoir accès au service.

Pour parfaire la sécurité touchant notre serveur web, nous allons créer un utilisateur qui puisse seulement manipuler et interroger une base de données spécifique parmi toutes celles présentes sur notre serveur.

Dans l’interface de PHPMyAdmin, cliquez sur le bouton. Une nouvelle vue s’affiche. Cliquez alors sur le lien. Une fenêtre s’ouvre en premier plan. Renseignez les champs.

Pour le nom de l’utilisateur, choisissez le nom que vous souhaitez mettre.

Dans la section client, définissez l’adresse ou une plage d’adresses pour laquelle l’utilisateur sera autorisé à se connecter.

Saisissez un mot de passe pour ce compte utilisateur.

Dans la section qui suit, définissez les droits sur la/les base(s) de données. Comme nous créons le compte de manière globale, nous ne choisissons aucune base pour cet utilisateur pour l’instant.

La section suivante permet d’ajouter des droits. Nous ne cochons aucune case.

Puis cliquez sur le bouton Exécuter pour créer cet utilisateur.

Nous venons de créer un utilisateur en contraignant ses actions au niveau global (image ci-dessous).

Maintenant, nous allons autoriser et donner les droits à l’utilisateur « User » d’utiliser la base usagiAka. Cliquez sur Changer les privilèges de la ligne que nous avons créée (image ci-dessus). Puis recherchez la section suivante :

Dans la liste déroulante sélectionnez la base de données « usagiAka ». Puis cliquez sur le bouton de cette section.

Attention : Ne donnez et sélectionnez aucun droit avant d’avoir sélectionné le nom de la BDD et d’avoir confirmé le changement en ayant appuyé sur le bouton Exécuter. Sans quoi vous ne donnez pas les droits d’utilisation sur la base, mais les droits globaux !

Après avoir appuyé sur Exécuter vous vous retrouverez sur l’écran suivant (ci-dessous) cochez les cases permettant d’attribuer les droits sur la base usagiAka. Dans mon cas, j’ai choisi de lui donner tous les droits cochés ci-dessous.

Une fois terminé, cliquez sur le bouton de cette section.

Nous allons vérifier que notre utilisateur créé ci-dessus a bien les droits sur la BDD sélectionnée. Pour cela cliquez sur dans la colonne gauche de l’interface. Puis sur le bouton dans la barre d’outils de la vue principale.

Nous retrouvons l’utilisateur que nous avons créé. Ainsi qu’un récapitulatif des droits sur la base et des privilèges que celui-ci jouit sur le serveur web.

En conclusion, notre serveur ainsi que notre base de données sont bien sécurisées. Cependant, il sera nécessaire de vérifier le fichier de log pour contrôler les connexions et maintenir un niveau de sécurité suffisant et réadapter les règles de sécurité déployées jusqu’à présent.

Règle de Firewall

Notre serveur web qui hébergera notre futur Web Service, il est nécessaire de configurer le firewall. Notre web service sera établi sur le langage PHP/SQL. Donc nous devons ouvrir le port utilisé par MySql pour envoyer une requête et récupérer le résultat de cette dernière.

Le serveur utilisant Windows comme système d’exploitation, nous allons voir comment ajouter une règle.

Rendez-vous dans le Panneau de Configuration et sélectionnez Pare-feu Windows.

Une fois dans l’onglet du Pare-feu, sélectionnez Paramètres avancés dans la colonne gauche de la fenêtre.

Dans la fenêtre qui vient de s’ouvrir, nous pouvons distinguer 3 zones. La zone principale, listant toutes les règles qui sont appliquées, une zone d’action et une zone permettant de choisir la nature de la règle que nous souhaitons appliquer.

Une fenêtre de procédure pour la création d’une nouvelle règle s’affiche à l’écran. La procédure se déroule en 5 temps, la définition du type de règle, les paramètres du protocole utilisé, les actions que va autoriser cette règle, le profil de cette règle et le nom de cette règle avec un descriptif de cette dernière.

Nous choisissons le type de règle. Dans notre cas, MySql utilise le port 3306.

Donc, nous sélectionnons une règle de type Port.

Cliquez sur Suivant pour passer à l’étape suivante.
Dans cette seconde étape, nous choisissons une règle basée sur le protocole TCP (car nous sommes en mode connecté).

Nous précisons le port à ouvrir. Soit pour MySql 3306.

Cliquez sur Suivant pour passer à la troisième étape de la procédure.
Dans cette phase, il faut choisir le type de connexion.

Devons-nous autoriser la connexion, la bloquer ou l’autoriser si elle est sécurisée ?

Dans notre cas, nous utiliserons la première proposition soit une simple autorisation.

Cliquez sur Suivant pour passer à la prochaine étape de la procédure.
Dans l’étape de profil, nous pouvons choisir pour quel type de réseau nous souhaitons appliquer cette règle.

Pour notre application, nous choisissons de rendre opérationnelle cette règle pour les réseaux de type Domaine et Privé. Et non Public.

Cliquez sur Suivant pour passer à la dernière étape de la procédure.
La dernière étape de la procédure de création de règle permet de nommer cette dernière et de décrire sa fonction.

Cliquez sur Terminer pour finaliser la création de la règle WAMP-MySql.

Ainsi, nous venons de créer notre règle pour notre Firewall. Cependant, celle-ci peut être optimisée afin d’augmenter la sécurité lors de l’accès à notre Web Service.

Cherchez dans la liste des règles de trafic entrant la règle que nous venons de créer et sélectionnez-la.

Dans la colonne de droite vous devez retrouver la liste ci-contre. Sélectionnez l’élément Propriétés qui nous permettra d’ajouter des contraintes supplémentaires sur la liste que nous avons créée.

Une fenêtre avec plusieurs onglets s’ouvre. Sélectionnez l’onglet Étendu puis dans l’encadré intitulé Adresse IP locale, changez l’état du bouton radio de N’importe quelle adresse IP à Ces adresses IP. Puis cliquez sur Ajouter.

Une nouvelle fenêtre de dialogue apparaît et il ne reste alors qu’à choisir si nous souhaitons ajouter une adresse IP particulière ou un sous-réseau.

Il est également possible de définir une plage d’adresses.

Puis il suffit de confirmer en cliquant sur OK.
Ci-contre, le rendu de la fenêtre de dialogue après avoir configuré l’onglet étendu.

Il ne reste alors qu’à valider cette fenêtre en cliquant sur le bouton OK pour appliquer les paramètres avancés à notre règle WAMP-MySql.
Web Service

Le principe d’un web service est d’exécuter des traitements et autres calculs sur le serveur, en envoyant à ce dernier une requête ou un/plusieurs paramètre(s).

Information : Un web service ne comporte pas d’interface graphique en temps normal. Cependant, afin de pouvoir effectuer des tests de débogage, une interface graphique existe pour ce web service.

Notre application étant une application lourde, il est intéressant d’effectuer les traitements côté serveur afin de « soulager » le terminal.

Cependant, il est nécessaire d’utiliser des fonctions de sécurité afin d’éviter les attaques classiques telles que l’injection de code malveillant, injection SQL.

Le web service qui a été mis en place est construit sur le fonctionnement suivant :

L’application envoie au web service la méthode que nous souhaitons utiliser (avec ou sans paramètre(s))

Le web service regarde si la variable passée en paramètre est null ou non. Pour cela nous utilisons la fonction :

.

Puis dans un second temps, nous allons éviter l’introduction de code malveillant, notamment l’injection SQL qui est l’une des attaques les plus fréquentes sur les serveurs web.

L’injection SQL est une technique où un pirate modifie une requête SQL existante pour afficher des données cachées, ou pour écraser des valeurs importantes, ou encore exécuter des commandes dangereuses sur la base. Cela se fait lorsque l’application prend les données envoyées par l’internaute, et les utilise directement pour construire une requête SQL.

La protection contre les requêtes SQL est effectuée grâce à cette fonction :

Information : La fonction «htmlentities()» est identique à la fonction « htmlspecialchars() », à l’exception que les caractères qui ont des équivalents en entités HTML sont effectivement traduits.

Une troisième mesure de sécurité est déployée sur chaque requête dans le cas ou cette dernière échoue. L’utilisation de la fonction permet d’afficher (seulement sur le web service) la source de l’erreur en affichant une chaîne de caractères. Le message affiché doit être parlant pour l’administrateur, mais pas suffisamment parlant pour un individu externe afin que celui-ci ne puisse interpréter l’indication comme un indice dans une optique d’attaques malhonnêtes.

Dans le cas de communication entre l’application et notre web Service, le retour des données calculées sur le serveur est encapsulé dans un tableau unique contenant la/les information(s). La réponse retournée se fait par la fonction.

Côté client

Du point de vue client (côté terminal), il existe plusieurs manières d’interroger une base de données distante. La première manière est d’interroger celle-ci en utilisant JDBC (Java DataBase Connectivity) ou de se connecter à un web-Service en ouvrant une connexion http.

Utilisation du Web-Service

Pour utiliser un web service au niveau client, nous allons nous connecter et envoyer les données via la méthode post en connexion http. Le résultat renvoyé par le web service sera sérialisé. C’est pourquoi nous devrons désérialiser ces derniers afin de pouvoir les exploiter. Pour désérialiser ces données, nous aurons besoin de la librairie GSON (Google Script Object Notation) qui pourra convertir les données JSON (JavaScript Object Notation) que vous pouvez télécharger ici :

http://code.google.com/p/google-gson/downloads/detail?name=google-gson-2.2.4-release.zip&can=2&q=

Vous pouvez aussi trouver ce dernier dans le répertoire :

Librairies\gson-2.3.3-sources

Pour ajouter une librairie, veuillez vous reporter à la section traitant ce sujet dans la partie I.

Dans un premier temps, nous verrons comment établir une connexion http en envoyant des données en argument via la méthode post, puis nous verrons comment convertir un flux en chaîne de caractères. Dans un second temps nous verrons comment parser les datas JSON afin de pouvoir utiliser ces données.

Voici la méthode qui nous permet d’établir la connexion vers notre serveur et d’envoyer des données. La méthode prend en argument l’url du serveur soit dans notre cas :

http://192.168.2.163/UsagiAkaServices/testWebService.php3

Ainsi que les paramètres que nous souhaitons passer via une ArrayList <NameValuePair>. L’avantage d’utiliser une liste permet d’envoyer plusieurs paramètres en une fois. Afin de pouvoir trouver ces derniers facilement au niveau du web service nous attribuons chaque valeur à une clef. Ce qui rend plus facile l’extraction des paramètres au niveau du serveur.

Nous déclarons et initialisons un objet stream à null de la classe InputStream. De la même façon nous déclarons un objet httpclient de la classe HttpClient que nous initialisons via le constructeur DefaultHttpClient() et un objet httpost de la classe HttpPost que nous initialisons par le constructeur HttpPost() en passant l’URL de notre serveur en paramètre.

Une fois avoir déclaré et initialisé nos objets, nous pouvons essayer de nous connecter et d’envoyer nos paramètres.

Dans un premier temps à travers la méthode setEntity() de l’objet httpost nous allons passer en paramètre le constructeur URLEncodedFormEntity() avec les paramètres que nous souhaitons transmettre en guise d’argument.

En cas d’erreur, notre LogCat indiquera une erreur d’encodage.

Puis dans un second temps nous allons instancier un objet httpreponse de la classe HttpResponse afin de récupérer la réponse à notre requête de transmission à travers la méthode execute() de l’objet httpclient prenant en paramètre l’objet httppost.

Dans un troisième temps, nous déclarerons un objet entity de la classe HttpEntity qui va récupérer l’entité de l’objet httpreponse en appelant la méthode getEntity().

Finalement, nous allons initialiser notre objet stream avec le résultat de l’objet entity par la méthode getContext() afin de retourner ce dernier.

Une fois avoir retourné l’objet stream, nous devons convertir ce dernier en chaîne de caractères afin de pouvoir exploiter les valeurs qu’il contient.

Cette méthode prend en paramètre un objet de type InputStream.

Nous déclarons une chaîne de caractères ainsi qu’un objet reader de la classe BufferedReader.

Puis nous allons « buffériser » notre Stream avec la norme « iso-8859-1 » en initialisant le constructeur BufferedReader() en passant en paramètre de celui-ci l’argument InputStreamReader().

Nous déclarons un objet sb de la classe StringBuilder ainsi qu’une chaîne de caractères line.
Ainsi, nous allons maintenant convertir le contenu de notre stream en chaîne de caractères. Tant que la ligne lue par le buffer est différente de null nous allons concaténer un saut de ligne au contenu de notre variable line.

Lorsque nous sortirons de notre boucle While(), nous fermerons le stream is en appelant la méthode close() dans le bloc finally de notre structure try/catch.

En dernier lieu, nous initialiserons notre variable result avec le contenu de notre objet sb via la méthode toString().

Nous retournons la variable resutl. Ce qui se traduit par la conversion de notre flux retourné par notre web service en chaîne de caractères.

Cependant, le résultat ne reste pas encore exploitable car la chaîne de caractères est encore sérialisée.

Information : Nous traitons un exemple de la désérialisation dans le cas de la récupération du nom des tables car cette méthode est moins volumineuse et plus facile à décrire et à expliquer. Notez que le principe reste le même qu’importe les données à parser. Nous pouvons retourner une liste ou un tableau unidimensionnel, le code s’adaptera au type de la valeur que nous souhaitons retourner.

Nous devons alors désérialiser la chaîne de caractères.

La méthode ci-contre va nous permettre de parser (désérialiser) la chaîne de caractères que nous avons convertie précédemment.

Nous retournerons le résultat dans un tableau de string 1D.

Nous allons déclarer nos variables dans un premier temps ainsi qu’un objet map de la classe HashMap<String, String>.

Pour faire simple, la valeur du premier string sert de référence, le second string contient la valeur référencée.

(Pour plus d’informations sur cette fonction référencez-vous à la javadoc).

Dans un bloc try/catch nous allons instancier un objet obj de la classe JSONObject en renseignant en argument notre chaîne de caractères string. Déclarons un objet tabNomTable de l’objet JSONArray initialisé par la méthode getJSONArray() de l’objet obj en précisant en argument la clef référent du tableau. Dans notre cas :

JSONArray tabNomTable=obj.getJSONArray(«nomTable»)

De cette façon nous venons de signaler que nous avons un tableau de JSON référencé par la clef nomTable.

Nous initialisons notre tableau grâce à la méthode length() de notre objet tabNomTable afin de connaître le nombre d’éléments que celui-ci contient. Ce qui permet aussi de renseigner notre structure itérative afin de recueillir les éléments en fonction de leur clef.

Nous déclarons un nouvel objet jsonData de la classe JSONObject qui va contenir la valeur à l’index « i » de l’objet tabNomTable en appelant la méthode getJSONObject().

Il ne nous reste alors qu’à initialiser notre variable (String) nom en récupérant la valeur référencée par la clef qui nous intéresse en utilisant la méthode getString() de l’objet jsonData. Dans notre cas :

String nom=jsonData.getString(«NOM»)

Puis nous utiliserons la HashMap map pour associer la variable nom à la clef NOM. Nous mettons cette valeur dans notre tableau. Une fois l’itération terminée, nous retournons le résultat de notre désérialisation. Les données qui alors étaient inexploitables peuvent être exploitées.

Attention : Les clefs de référence utilisées pour désérialiser doivent être identiques aux clefs utilisées lors de la sérialisation des données par le serveur sans quoi les données ne pourront jamais être extraites.

JDBC

Avant toutes choses, la librairie JDBC permettant de se connecter et d’effectuer des requêtes sur un serveur MySQL n’est pas présente dans les librairies par défaut d’Eclipse. Vous pouvez télécharger cette dernière sur le site :

http://dev.mysql.com/downloads/connector/j/

Vous pouvez aussi trouver ce dernier dans le répertoire :

Librairies\mysql-connector-java-5.1.24-bin.jar

Pour ajouter une librairie, veuillez vous reporter à la section traitant ce sujet dans la partie I.

Nous allons donc créer 2 classes afin de manipuler une base de données distante. La première classe contiendra les méthodes d’établissement de connexion, d’ouverture de BDD, fermeture de BDD et d’exécution de requête.

Dans un premier temps, nous instancions 2 objets des classes Connection et Statement que nous initialiserons à « null ».

Nous déclarons un tableau de chaîne de caractères 2D.

Nous créons aussi le constructeur de notre classe. Celui-ci ne contiendra rien. Il permettra d’allouer l’espace mémoire lors de l’instanciation d’un objet de la classe CMysql().
La méthode ci-contre permet d’initialiser et de charger le Driver MySQL (JDBC). Nous utilisons un try/catch qui lèvera les erreurs dans le cas où la classe com.mysql.jdbc.Driver n’est pas trouvée. Cette exception est déclenchée sur le levé du Throws Exception.

La méthode retournera un entier qui nous permettra de gérer le succès ou l’échec de l’initialisation.

La méthode ci-dessus permet d’ouvrir une connexion à un serveur MySQL. Cette fonction prend en paramètre l’adresse de notre serveur, le port d’accès, le nom de la BDD ciblée, le login et le mot de passe de l’utilisateur (tous ces arguments doivent être de type chaîne de caractères).

Puis nous initialiserons l’objet con initialisé précédemment en utilisant la méthode getConnection() de la classe DriverManager.

Par exemple :

« jdbc :mysql://192.168.2.163 :3306/usagiAka,utilisateur,password »

Nous retrouvons donc l’adresse de notre serveur, le port MySQL (3306) le nom de la BDD, un des utilisateurs autorisés à utiliser la BDD ainsi que son password.

Nous retournerons un entier qui jouera le rôle de code d’erreur. Si une exception est détectée la méthode à travers le Throws SQLException déclenchera l’erreur dans le bloc try/catch.

Astuce : Nous traitons ici la connexion à un serveur MySQL, mais il est possible d’attaquer un serveur Oracle, ODBC etc. Pensez à télécharger les librairies et drivers nécessaires. Et d’inclure ces dernières dans le projet.

La méthode suivante permet quant à elle de fermer la connexion via JDBC. Pour cela, nous utilisons la méthode close() de l’objet con de la classe Connection que nous manipulons depuis l’ouverture de la connexion. Comme précédemment, nous récupérons un code de succès ou d’échec. En gérant les erreurs de la même manière que pour les méthodes ci-dessus.
Pour l’exécution des requêtes, nous passons en argument une requête en chaîne de caractères.

Nous déclarons et initialisons nos variables.

Puis nous initialisons l’objet stm (que nous avons instancié de la classe Statement) par le retour de la méthode createStatement() de l’objet con.

Nous exécutons maintenant la requête.
Pour cela, nous allons exécuter notre requête via la méthode executeQuery() de l’objet stm. Nous initialisons et instancions un objet de la classe ResulSet, resultat qui contiendra le retour de la requête que nous avons exécutée.

(Par préférence, je préfère récupérer le résultat des requêtes dans un tableau 2D).

Nous récupérons le nombre de colonnes contenues dans l’objet résultat par la méthode getMetaData().getColumnCount(). Pour récupérer le nombre de lignes retournées par notre requête, nous devons nous positionner sur le dernier élément de l’objet resultat via la méthode last() puis de récupérer le numéro de ligne en appelant la méthode getRow(). Avec ces informations, nous pouvons alors initialiser notre tableau 2D avec ces deux informations.

Maintenant, nous allons remplir le tableau. Nous allons repositionner notre pointeur avant la première ligne retournée par notre résultat en utilisant la méthode beforeFirst(). Puis dans une boucle imbriquée, nous allons récupérer les valeurs retournées par la requête exécutée tant qu’il existe une valeur dans l’objet resutlat (via la méthode next()). Pour accéder au résultat de notre requête, il faudra utiliser la méthode getString() en précisant l’index en paramètre.

Nous retournons par la suite notre tableau 2D une fois celui-ci initialisé. Pour gérer les exceptions, nous utilisons le même précédemment que les méthodes d’initialisation, d’ouverture et de fermeture d’une connexion via JDBC.

Bluetooth

Dans cette partie, nous allons voir comment établir la connexion entre un terminal industriel et une imprimante industrielle via la technologie Bluetooth. Dans un premier temps, nous vérifierons la présence de la technologie sur notre appareil, puis nous activerons ou désactiverons la carte Bluetooth. Nous verrons aussi comment rendre visible notre terminal pendant un certain temps. Ensuite, nous verrons alors comment réaliser l’association et gérer une connexion Bluetooth, et en dernier lieu comment envoyer des données.

Information : Un projet unique a été généré spécialement pour mettre en œuvre les fonctionnalités Bluetooth. Vous trouverez ce projet compressé dans le répertoire Codes\Bluetooth\ZelenZajak.zip.

Attention : Pour pouvoir manipuler la carte Bluetooth, il est nécessaire de déclarer deux permissions dans le fichier AndroidManifest.xml de notre projet.

Existence

La méthode qui permet de vérifier si notre appareil comporte un périphérique Bluetooth. Cette méthode retournera en guise de résultat un booléen :

  • false si notre terminal ne comporte pas de carte Bluetooth
  • true s’il est équipé de la technologie

Pour vérifier si notre device comporte un périphérique Bluetooth, nous instancions un objet mAdpBluetooth de la classe BluetoothAdapter que nous initialisons grâce à la méthode suivante :

Si mAdpBluetooth est null alors cela signifie que notre appareil ne comporte pas d’équipement Bluetooth puisque nous n’avons pas pu faire le lien entre notre couche logicielle et matérielle.

Activation/Désactivation

En fonction de la présence d’un périphérique Bluetooth, nous activons le périphérique Bluetooth si celui-ci n’est pas déjà actif, et désactivons celui-ci si ce dernier n’est pas déjà désactivé.

Activation de la carte

La méthode activationBluetooth() permet d’activer la carte Bluetooth de notre terminal.

Dans un premier temps, nous allons vérifier si la carte n’est pas déjà activée et récupérer l’état de la carte grâce à la méthode isEnabled() de l’objet mAdpBluetooth (objet de la classe BluetoothAdapter).

Nous déclarons un objet enableBtIntent de la classe Intent en initialisant ce dernier avec le constructeur new Intent() en passant en argument BluetoothAdapter.ACTION_REQUEST_ENABLE afin de faire apparaître une boîte de dialogue système demandant la confirmation d’activation du Bluetooth.

Puis nous lançons la procédure d’activation avec une message box pour l’utilisateur informant que le Bluetooth est en cours d’activation grâce à la méthode startActivtyForResult() en passant en paramètre notre objet enableBtIntent avec la constante permettant d’activer la carte radio REQUEST_ENABLE_BT (déclaré comme constante de notre classe ).

Ainsi, afin de vérifier que le Bluetooth est activé sur notre appareil l’icône du Bluetooth doit apparaître en haut à droite de notre écran. Nous devons alors passer de l’image suivante à l’image.

Désactivation de la carte

Pour désactiver l’équipement Bluetooth de notre terminal nous utilisons la méthode desactivationBluetooth().

Dans un premier temps, nous regardons si la carte Bluetooth est activée.

Si la carte est activée, alors nous désactiverons cette dernière en appelant la méthode disable() de l’objet mAdpBluetooth (objet de la classe BluetoothAdapter).

Visibilité

La méthode visible() va permettre de rendre visible le terminal pour une durée d’une minute. Par mesure de sécurité la visibilité du terminal n’est pas activée. Ainsi, lors d’une recherche d’appareil Bluetooth si la visibilité de l’appareil n’est pas activée, ce dernier ne sera pas vu. Ce qui empêchera toutes tentatives de connexion non souhaitées.

Comme pour l’activation de la carte Bluetooth, nous allons faire apparaître une boîte de dialogue permettant d’activer ou non la visibilité du terminal.

Comme vu précédemment, nous instancions un objet discoverableIntent de la classe Intent en initialisant celui-ci en appelant le constructeur new Intent() en passant en paramètre la constante ACTION_REQUEST_DISCOVERABLE de la classe BluetoothAdapter. Ensuite, nous déclarons la durée de la visibilité de notre terminal. Via la méthode putExtra() de l’objet discoverableIntent en passant en paramètre BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION puis 60.

En dernier lieu, nous allons afficher une message box demandant à l’utilisateur de rendre visible ou non l’appareil (image ci-dessus) en appelant la méthode startActivityForResult() en donnant comme paramètre l’intent discoverableIntent paramétré précédemment.

Association

Cette partie n’est pas consacrée à l’association entre 2 périphériques, mais à l’obtention des appareils qui ont déjà été reliés et sont toujours associés dans la mémoire de notre terminal.

Pour cela, nous utiliserons la méthode getAssocie() qui retournera le nom et l’adresse des appareils qui ont déjà été associés à notre terminal dans une liste d’objets appartenant à la classe que nous avons créée CDevice.

L’objet de cette classe n’est ni plus ni moins qu’une adaptation plus légère de la classe BluetoothDevice.

Dans un premier temps nous allons récupérer tous les périphériques qui sont associés à notre terminal.

Pour cela nous avons au préalable déclaré en début de notre classe l’objet : qui va récupérer les spécifications des appareils gardés en mémoire grâce à la méthode getBondedDevices() de notre objet mAdpBluetooth.

Nous regardons ensuite si le nombre d’appareils retournés est supérieur à 0. Si la taille de cette liste est inférieure à 0 c’est tout simplement que notre terminal ne contient pas d’appareil avec lequel il est associé. Dans le cas contraire, nous allons ajouter chacun des appareils associés dans notre liste puis retourner cette dernière après avoir ajouté les spécifications du dernier appareil.

Par exemple :

Avant action sur le bouton « Déjà Associé »

Après action sur le bouton « Déjà Associé »

Avant action sur le bouton « Déjà Associé »

Après action sur le bouton « Déjà Associé »

Rechercher des équipements

Pour rechercher de nouveaux périphériques nous allons utiliser le code ci-dessous :

Nous allons effectuer la recherche d’autres équipements dans un thread séparé du thread de l’application afin de ne pas entraîner une fatale erreur dans notre application.

Pour cela nous allons surcharger la méthode onReceive() prenant en argument le context de l’application et un intent.

Nous déclarons une chaîne de caractères en initialisant cette dernière en récupérant l’action de l’intent passé en paramètre.

Puis si un terminal est trouvé, via la méthode BluetoothDevice.ACTION_FOUND.equals() prenant en paramètre notre chaîne de caractères.

Nous allons récupérer l’objet Bluetooth trouvé depuis l’intent passé en paramètre. Nous afficherons en guise d’information pour le développeur le nom et l’adresse MAC des équipements trouvés.

Ensuite, nous ajouterons les équipements trouvés à la liste listDevice en passant en paramètre de la méthode add() le nom du périphérique comme un nouvel objet.

Puis nous afficherons ce dernier dans la listView présente dans notre interface.

Nous allons déclarer un objet de la classe IntentFilter qui va avoir pour but de trouver les équipements Bluetooth.

Puis nous appellerons notre méthode registerReveiver() en précisant en paramètre l’objet receiver qui va contenir les périphériques et l’objet filter. Il nous restera alors qu’à démarrer la recherche de périphériques en appelant la méthode startDiscovery() de l’objet mAdpBuetooth.

Le Thread de Connexion/Déconnexion/Envoi de données

Il existe deux types de connexion. La connexion en tant que serveur Bluetooth, et la connexion en tant que client.

Dans notre cas, nous utiliserons la connexion en tant que client. Cependant, dans le code, la méthode permettant de mettre en œuvre la connexion en tant que serveur est présente.

Pourquoi la connexion en tant que Client ?

Simplement parce que nous demandons la connexion depuis le terminal vers l’imprimante. Donc notre imprimante ne pouvant émettre de demande de connexion, cette dernière demandera de saisir un code pour accepter la connexion.

En récapitulant, l’imprimante Bluetooth QL320+ est en mode slave mais se comporte comme un serveur Bluetooth.

Pour mettre en œuvre la procédure d’ouverture, fermeture de connexion ainsi que l’envoi de données, nous devrons créer et utiliser une nouvelle tâche (Thread). Auparavant, nous utilisions le Thread de l’application. Cela n’était pas gênant car la tâche n’était pas bloquante. Or lors de l’établissement d’une connexion la tâche est bloquante et peut entraîner lors de l’échec de l’établissement d’une connexion un arrêt de l’application.

Nous allons voir comment déclarer une telle méthode.

Le thread permettant d’établir une connexion se déroule en 3 étapes :

  • La définition et initialisation des objets, variables dans un constructeur
  • La définition de la méthode run() permettant de lancer le thread
  • La méthode cancel qui permet de tuer le thread

Dans notre classe, nous allons définir une classe interne définie comme private que nous faisons hériter de la classe Thread.

Puis nous instancierons un objet mmServerSocket de la classe BluetoothServerSocket comme private final. Cet objet va permettre de gérer la communication entre les 2 appareils. Soit dans notre cas le terminal ET1 et l’imprimante QL320+.

Nous définissons dans la classe que nous venons de créer notre constructeur qui va prendre en paramètre l’objet device (classe BluetoothDevice) de l’appareil qui aura été sélectionné.

Dans un premier temps, nous allons créer un objet temporaire tmp de la classe BluetoothServerSocket. Ainsi qu’un objet MY_UUID de la classe UUID de type private que nous initialisons à null.

Puis nous allons essayer de construire l’objet qui va permettre la communication entre nos 2 appareils via un UUID (Universally Unique Identifier). Nous souhaitons établir une connexion en série entre notre imprimante et notre terminal. Nous utiliserons alors un UUID spécifique.

L’UUID à utiliser est le suivant :

00001101-0000-1000-8000-00805F9B34FB

Nous allons initialiser un String avec cette valeur. Puis nous allons attribuer cette valeur à notre objet MY_UUID en utilisant la méthode fromString() de la classe UUID en passant en paramètre le String contenant notre identifiant. Il sera nécessaire de communiquer cet identifiant au serveur afin de pouvoir établir la connexion. Pour cela nous utiliserons.

En dernier lieu, si lors de la construction, l’application n’a pas levé d’erreur, nous initialiserons notre objet mmSocket avec la valeur de l’objet tmp (tous deux de la même classe BluetoothServerSocket).

Après avoir expliqué le constructeur de notre thread, nous allons expliquer la tâche permettant d’établir la connexion à notre serveur à travers la méthode run().

Dans notre méthode nous allons appeler la méthode cancelDiscovery() de l’objet mAdpBluetooth. Cette méthode va permettre d’arrêter la recherche de périphériques couverts par notre terminal si celui-ci a été activé auparavant. Car le service de recherche réduit considérablement l’autonomie de l’appareil.

Nous allons essayer d’établir la connexion entre le terminal et l’imprimante en utilisant la méthode connect() de l’objet mmSocket initialisé dans le constructeur comme vu précédemment.

La connexion va chercher à s’effectuer jusqu’à réussir. Puis nous initialisons l’objet sendStream de la classe OutputStream déclarée au début de notre classe en récupérant le flux d’entrée de notre imprimante grâce à la méthode getOuputStream() de l’objet mmSocket contenant les paramètres de communication entre nos 2 appareils.

Dans le cas où la connexion n’aboutirait pas, nous lèverons une exception puis fermerons la connexion. Or dans le cas où nous ne pourrions pas fermer la connexion, nous lèverons une nouvelle exception.

Avec cette méthode nous pourrons établir la communication entre nos deux appareils.

Pour clore une connexion entre 2 appareils, nous aurions besoin de déclarer la méthode cancel().

Puis d’essayer de fermer la connexion ouverte grâce à la méthode close() de l’objet mmSocket.

En cas d’échec de la fermeture de connexion nous lèverons une erreur comme précédemment.

Maintenant, que nous venons de créer les fonctions de notre classe privée, nous allons générer les méthodes permettant d’appeler les méthodes présentées ci-dessus.

Ouvrir une connexion

Pour ouvrir une connexion, il suffira d’appeler la méthode connect() que nous allons créer à l’extérieur de la classe imbriquée.

Dans cette méthode, nous allons essayer d’établir une connexion.

Nous allons initialiser notre objet mConnectThread de la classe imbriquée que nous avons créé ConnectThread en appelant son constructeur. Il sera nécessaire de passer un objet de la classe BluetoothDevice. Puis nous démarrons la tentative de connexion en appelant la méthode start() de notre objet mConnectThread qui va exécuter la méthode run() de notre classe.

Naturellement, nous lèverons une Exception dans le cas où nous n’arriverons pas à établir la connexion.

Dans le cas où un appareil sur lequel nous souhaitons nous connecter n’a jamais été associé auparavant à notre tablette, l’application demandera de confirmer la tentative de connexion via le port série, ou dans le cas de l’imprimante Bluetooth de saisir le mot de passe permettant d’établir la connexion et donc d’associer le matériel.

Exemple :

Connexion vers ImprimanteConnexion vers téléphone

Envoi de données

Pour envoyer des données vers notre imprimante nous allons utiliser la méthode ci-dessous envoyerData(). Cette dernière prend en paramètre la chaîne de caractères à transmettre à l’imprimante.

Nous allons convertir dans un premier temps la chaîne de caractères transmise en paramètre en bytes. Puis dans un second temps, écrire ces données dans notre objet de flux sendStream grâce à la méthode write().

Une fois les données chargées dans notre objet sendStream nous allons envoyer ces données vers l’appareil cible grâce à la fonction flush() de notre objet afin de pousser le contenu du flux.

En cas d’échec, l’application relèvera une erreur évitant ainsi de bloquer l’application.

Fermer une connexion

Pour fermer une connexion établie entre nos deux appareils. Dans la méthode (ci-contre) nous allons appeler la méthode cancel() de l’objet mConnectThread qui va essayer de clore la connexion dans un thread différent.

.

Système

Dans cette partie, nous allons voir comment récupérer les informations réseau propres au terminal. L’accès à ces informations se fait de manière universelle, peu importe la marque du constructeur. Puis en dernier lieu, nous verrons comment passer d’une interface à une autre, en lui transmettant des variables.

Dans un premier temps nous allons réaliser une nouvelle classe CNetwork.java.

Puis nous allons créer un objet wm de la classe WifiManager. Cette classe permet de récupérer les informations liées à la carte radio du terminal.

Nous créons et initialisons une nouvelle Liste par la même occasion afin de stocker les valeurs que nous allons récupérer.

Nous créons notre constructeur qui restera vide.

Puis nous allons rédiger la méthode system() qui prend en argument le contexte de l’application qui l’a appelée. Cette méthode va avoir pour but d’appeler toutes les méthodes qui renseigneront les paramètres attendus. Et retournera les résultats sous forme d’une liste.

Information wifi

Dans le milieu industriel, il est important pour le technicien de la Hotline d’avoir un diagnostic du réseau wifi. Sur quelles bornes le terminal est-il connecté ? La borne est hors service ? Etc.

De ce fait, récupérer l’adresse IP du terminal ainsi que l’adresse MAC et le SSID de la borne sur laquelle le terminal est connecté est d’une grande importance.

Notez que pour pouvoir récupérer les informations radio du terminal il faut déclarer la permission dans le fichier AndroidManifest.xml. Les permissions suivantes sont à ajouter :

Cette méthode permet de récupérer l’adresse IP du terminal. Pour cela nous allons utiliser la classe WifiManager comme vu ci-contre.

Dans un premier temps, nous allons initialiser l’objet wm en lui spécifiant quel service nous ciblons. Ainsi, (WifiManager)context.getSystemService(Context.Wifi_Service) permet de faire le lien entre la couche matérielle et la couche logicielle. C’est avec la méthode getConnectionInfo() de l’objet wm que nous allons extraire les informations. Pour cela, il est nécessaire de créer un objet adIpWifi de la classe WifiInfo.

Pour récupérer l’adresse IP, il suffit juste d’appeler la méthode getIpAddress() de l’objet adIpWifi. Cependant, la valeur retournée est exprimée en hexadécimal. C’est pour cela que nous passons cette méthode comme paramètre de la méthode adressIpWifi() que nous verrons plus bas, et qui permet de convertir l’adresse IP hexadécimale en adresse IP sous forme décimale.

Pour récupérer le SSID (Service Set Identifier) il suffit de récupérer le résultat de la méthode getSSID() de l’objet adIpWifi. Puis nous ajoutons le résultat dans une liste.

La méthode adressIpWifi() permet de convertir une adresse IP en chaîne de caractères.

Pour cela, nous allons utiliser la méthode format() de la classe String, qui permet de définir le format du résultat que nous souhaitons obtenir en précisant les données de chacun de ces formats.

Nous allons donc appliquer un masque (255 0xFF) sur notre variable. L’opération s’effectue via l’opérateur logique &. Puis nous allons décaler de 8 bits vers la droite notre variable en utilisant l’opérateur >> en appliquant de nouveau notre masque. L’opération est la même mais en décalant de 16 bit vers la droite, puis de 24 bits vers la droite.

De cette façon, nous transformons notre adresse IP sous le format X.X.X.X. Il ne nous reste alors plus qu’à retourner notre chaîne de caractères contenant notre adresse IP.

Cette méthode permet de récupérer l’adresse MAC du point d’accès radio. Pour cela nous allons utiliser la classe comme précédemment la classe WifiManager.

La procédure mise en œuvre étant la même que celle de la récupération de l’adresse IP, nous ne verrons que la ligne qui nous intéresse.

Pour récupérer l’adresse MAC de la borne WIFI, il suffit d’appeler la méthode getBSSID() de l’objet adIpWifi. Le résultat retourné par cette méthode est exprimé comme une chaîne de caractères hexadécimale comme nous le souhaitons.

Information terminal

Cette méthode permet de récupérer le numéro de série de l’appareil afin de pouvoir l’identifier.

Notre méthode prend en argument le contexte du layout qui l’a appelé. Pour obtenir le numéro de série de l’appareil, il suffit d’utiliser la fonctionnalité SERIAL de Build. Qui fait partie des couches bas niveau de l’API. Cela nous retournera une chaîne de caractères avec l’identifiant de l’appareil.

Notez que pour pouvoir soutirer les informations du terminal, il est nécessaire de déclarer la permission de lire les données du terminal en ajoutant la permission suivante dans le fichier AndroidManifest.xml :

Voici un aperçu du résultat une fois affiché sur le terminal :

Navigation d’un écran à un autre

Dans un projet complexe, nous possédons dans la plupart du temps plusieurs interfaces. Il est intéressant de voir comment nous pouvons passer d’un écran à un autre en partageant des variables.

Nous allons expliquer le passage de paramètre d’une Activité 1 vers une Activité 2.

Dans l’activité 1 nous allons déclarer un intent en précisant l’activité de base, puis l’activité cible.

Par exemple, nous souhaitons depuis l’écran Principal aller vers l’écran des options (BDD).

Puis afin de passer en paramètre une variable, nous allons instancier un objet objetBundle de la classe Bundle en référençant notre valeur par une clef qui permettra de récupérer les données.

Puis nous ajoutons dans l’intent que nous avons déclaré ci-dessus l’objet objetBundle contenant notre valeur.

En dernier lieu, nous exécutons le changement de layout en utilisant la méthode startActivity() en précisant en paramètre notre intent.

Afin de pouvoir naviguer vers une nouvelle interface, il est nécessaire de déclarer l’existence de l’activité dans notre fichier Manifest.xml.

Nous indiquons l’activité et non pas le layout.

Dans notre seconde activité (Activité 2) nous allons récupérer la valeur que nous avons envoyée depuis l’activité 1.

Pour cela, nous allons écrire les lignes de code ci-contre dans la méthode onCreate() de notre Activity.

Nous allons déclarer un objet recupVal de la classe Bundle afin de pouvoir récupérer le Bundle passé en paramètre, puis récupérer la valeur de la façon suivante :

Là se trouve l’importance de mettre un nom de clé parlant afin de récupérer le bon paramètre. Nous déclarons un objet du même type que le paramètre passé afin de recueillir celui-ci. Pour récupérer la valeur de notre paramètre, il suffit de préciser la clef dans la méthode suivante :

Afin de vérifier que nous avons bien passé notre variable, nous affichons le contenu de celle-ci dans le LogCat. Ci-dessous nous avons le résultat de la variable que nous avons transmise.

Attention : Une erreur récurrente lors d’un changement d’activité est d’oublier de déclarer l’activité dans le fichier AndroidManifest.xml. L’erreur est suggérée dans la plupart du temps dans le LogCat.

Conclusion

Projet

Le projet est fonctionnel dans sa totalité. Naturellement, le code reste à optimiser et à debugger en profondeur.

Le tableau ci-dessous fait le bilan des fonctionnalités demandées par Karelis lors de l’expression du besoin :

TypeFonctionnalitésÉtat
Fichier de configurationÉcriture (XML)VALIDE
Lecture (XML)VALIDE
Base de données (MySQL)Requête via http à un web serviceVALIDE
Requête directement à une BDD (JDBC)VALIDE
Base de données (SQLite)Créer une base de données .dbVALIDE
Effectuer des requêtes (INSERT/UPDATE/SELECT)VALIDE
Synchroniser les données avec BDD MySQLVALIDE
SystèmesRécupération SSID et @MAC point d’accèsVALIDE
Récupération N° de série de l’appareilVALIDE
Récupération de @IP délivré par le point d’accèsVALIDE
BluetoothRécupérer les appareils associésVALIDE
Récupérer les appareils disponiblesVALIDE
Activer/Désactiver la carte BluetoothVALIDE
Imprimer des données envoyéesVALIDE
Établir une connexionVALIDE
Bluetooth existence sur l’équipementVALIDE

L’application Android qui a servi à utiliser toutes ces fonctionnalités n’est cependant pas optionnelle. Ce qui ne pose pas de réel problème sauf de pouvoir observer l’ergonomie, la fluidité qu’offre Android.

Bien que l’application soit encore en cours de développement, nous pouvons nous rendre compte de la différence de dynamisme entre un programme développé sous WinDEV pour Windows Mobile/CE et un programme développé en java natif pour Android.

Pour réaliser une application Android, même si WinDEV permet de créer des projets pour ce type de plateforme, il est préférable d’utiliser une application en java native. Il existe de nombreux problèmes comportementaux d’un projet WinDEV sous Android au niveau de la durée de vie d’une application.

Android a de nombreux atouts. Bien qu’il existe à l’heure actuelle de nombreuses manières de développer une application sous Android, la voie la plus fiable reste le développement en java natif et non pas de type webApps (RhoStudio de Motorola).

De plus, la communauté Android est très importante et active ce qui permet de pouvoir trouver facilement de l’aide sur les forums et de nombreux tutoriels pour apprendre des fonctionnalités non maîtrisées (ce qui n’est pas le cas pour la plateforme RhoStudio).

Cependant, il est important de prendre en compte que le développement sous Android demande beaucoup plus de temps qu’un développement sous WinDEV. Bien que par la suite avec l’usage de classe et de méthode revenant régulièrement dans les projets un gain de temps peut être constaté.

Bilan

Pour ma part, l’entreprise Karelis n’est pas prête à utiliser et à s’investir dans le développement Android à l’heure actuelle. Que ce soit sur le plan matériel, logiciel ou humain.

Sur le plan matériel, Android est parfait pour le monde grand public et pour un public averti et compétent. L’usage d’Android dans le monde professionnel se limite à l’usage d’appareil à l’intention de commerciaux et non pas de technicien sauf exception.

Il est parfaitement envisageable qu’un commercial puisse utiliser comme support un appareil Android pour ses démonstrations et présentations chez un client ce qui sur la durée sera une réalité, car les tablettes jouent et joueront ce rôle.

Mais il est impensable de laisser un terminal laissant autant de liberté dans son utilisation à un technicien. Les règles de restrictions ne sont pas encore (voire même absentes) aussi puissantes que sous des terminaux utilisant Windows CE.

Sur le plan logiciel, l’avantage est qu’il n’y a aucune licence à payer pour développer. Cependant, le développement en Android demande un investissement temporel non négligeable bien plus important que lors d’un développement sous WinDEV.

Sur le plan humain, il est nécessaire de former un technicien et dédier celui-ci entièrement à cette tâche ou d’employer un développeur spécialisé en Android/Java.

Tant qu’Android n’a pas fait sa place dans le secteur industriel de manière officielle, il n’est pas viable d’investir dans cette voie. Mais, ce n’est pas pour autant que cette technologie doive être délaissée et abandonnée bien au contraire. Je me permets de vous conseiller de rester à l’écoute de l’évolution de ce dernier dans le secteur d’activité qui est celui de Karelis.

Cahier 5 : Rapport Technique
<-
Cahier 5 : Mémoire d’un Licence Pro

Sources

Bibliographie

  • Programmer en Java 7 Edition Java 5 et 6 – Claude Delannoy – Edition Eyrolles
  • Programmation Android : De la conception au déploiement, avec le SDK Google Android – Damien Guignard, Julien Chable, Emmanuel Robles, Nicolas Sorel – Edition Eyrolles

Webographie

Bluetooth

Générale

Fichiers

Éléments graphiques

Boutons
ListView
TabHost

JDBC

SQLite

WebService

Wifi

XML-JDOM