Tag Archives: java

Android : Widgets et Services, un zouli mélange

Maintenant que vous savez que vous devez rester dans les clous avec les widgets, on va commencer à pouvoir y aller à la pelle et voir qu’on peut quand même faire du bon gros quick’n’dirty ; bon ok… on va pas aller jusque là mais vous saurez que vous pouvez faire plus que ce qui vous pensiez pouvoir faire depuis le précédent article. héhé

 

Rien de miraculeux, il faut garder à l’esprit toutes les différentes remarques pour cet article qui se propose de mettre les mains dans le code au travers d’un exemple simple et de faire découvrir un aspect des widgets et du développement sous android.

Commençons

Pour cet exemple, créons un simple projet. Chargez votre IDE favori et créez le projet. Peu importe le package de base que vous utiliserez, souvenez-vous simplement que des éléments du Manifest et des déclarations de xml auront besoin du package exact de vos classes pour instanciations/permissions.

 

Classes de base

Faisons simple. Si vous avez lu l’article précédent, vous aurez besoin d’un AppWidgetProvider pour le widget, et d’un Service.

Nous les appellerons simplement MyAppWidgetProvider et MyService (pourquoi faire compliqué). Dans la classe MyAppWidgetProvider, nous allons surcharger la méthode onUpdate puis dans Service, la méthode onStartCommand (pour l’exemple)

public class MyAppWidgetProvider extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int []appWidgetId) {
}
}
public class InspectService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int e){
return START_STICKY;
}
}

La base est donnée, nous pouvons continuer. Nous allons créer un simple layout affichant du texte. Créez donc un nouveau layout dans le dossier res/layout en lui donnant un nom que vous souhaitez puis ajoutez dedans :

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal|center_vertical"
android:orientation="vertical" >

<TextView

android:id="@+widget/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="@string/start" />
</LinearLayout>

Ajoutons maintenant deux valeurs strings dans les ressources

<string android:name="start">Start the service</string>
<string android:name="stop">Stop the service</string>

Qui servirons à lancer/stopper le service exemple

 

Manifestons !

Maintenant que la vue pour le widget existe, que les classes sont déclarées, modifions le manifest.

Ouvrez le manifest et au sein de la balise application, indiquez que l’application utilisera un service et un receiver avec un intent-filter

<service android:name="your.package.is.here.MyService" />

<receiver
android:name="your.package.here.MyAppWidgetProvider">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>

<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_service" />
</receiver>

Vous avez vu le meta-data? Au niveau de android:resource? Nous allons voir dans l’étape suivante quoi faire

Au bout du tunnel… du widget

Bon ok, on va voir quoi faire mais attention, il faudra un autre article pour vous montrer dans le détail toutes les possibilités qui vous sont offertes !

Donc créez un simple fichier xml dans res/xml. D’après l’étape précédente, j’appelle donc le mien widget_service.xml. Ouvrez le et mettez :

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="40dip"
android:minHeight="40dip"
android:minResizeWidth="40dip"
android:minResizeHeight="40dip"
android:updatePeriodMillis="0"
android:previewImage="@drawable/uneresourcegraphiqueexemple"
android:initialLayout="@layout/lelayoutcreeavant"
/>

Ce qu’il faut remarquer ici (outre les informations de taille, que vous pouvez changer…) : vous pouvez gérer une image de présentation qui apparaitra dans la liste des Widgets. et un layout par défaut, celui qui est chargé par le widget, dont le nom est à changer en fonction du layout que avez créé précédemment. Dernière petite info, en mettant 0 dans updatePeriodMillis, on indique que le widget sera mis à jour “manuellement” par l’application et non par le système qui aurait pu le faire à intervalle régulier.

 

Récapitulons rapidement, nous avons :

  1. une classe de widget et un service,
  2. déclaré un layout pour le widget
  3. déclaré un xml de déclaration d’informations sur le widget
  4. modifié le manifest pour décrire l’utilisation du service et du widget

Agrémentons tous cela maintenant.

 

Du Widget au Service

Rajoutons de l’activité dans le Widget. Ouvrez votre classe du widget, et mettez ce code dans la méthode onUpdate:

// Preparation des vues
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_service);

//petite disjonction sur l'état d'activité du service, que nous implémenterons après

//change le texte en fonction de l'état
if(MyService.getState() == MyService.RUNNING){
views.setTextViewText(R.widget.text, context.getString(R.string.stop));
}else{
views.setTextViewText(R.widget.text, context.getString(R.string.start));
}

// préparation d'un intent à déclencher au clic sur le widget
Intent serviceIntent = new Intent(context, MyService.class);
serviceIntent.putExtra("state", 2);

PendingIntent pendingIntent = PendingIntent.getService(context, 1, serviceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.widget.text, pendingIntent);

//on envoie sur toutes les instances du widget présentes sur le launcher
for(int i=0;appWidgetId != null && i<appWidgetId.length;i++)
appWidgetManager.updateAppWidget(appWidgetId[i], views);

Cela aura pour effet d’instancier le widget et de le préparer pour l’espace utilisateur. N’oubliez pas qu’il faille en faire un minimum pour permettre de ne pas dépasser le temps critique autorisé et éviter des ANR potentielles (d’après certains tests, 5sec entrainent des messages de warning dans les logs selon les versions du système)

… et du Service, chargeons le Widget

Dernière étape ! Mais pas la plus dure, vous allez voir.

Tout à l’heure, j’ai utilisé une méthode static getState() dans onUpdate. Nous créons donc cela dans le service :

public final static int RUNNING = 1;
public final static int STOPPED = 2;
private static int _state;

public static int getState(){
return _state;
}

Nous avançons ; mettons en place la mise à jour simple des widgets dans une méthode updateWidgets()

private void updateWidgets(){

//récupération du manager général
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this.getApplicationContext());

//récupération d'un ComponentName de notre provider
ComponentName widgetComponentName = new ComponentName(getApplicationContext(), MyAppWidgetProvider.class);

//récupération des widgets possible de l'application
int[] widgetIds = appWidgetManager.getAppWidgetIds(widgetComponentName);

for (int widgetId : widgetIds) {

//pour chaque type, récupération des vues "distantes" (nous sortons de l'application, d'où notamment les restrictions sur les variables vues dans le précédent article)
RemoteViews remoteViews = new RemoteViews(this
.getApplicationContext().getPackageName(),
R.layout.widget_service);

//changeons le texte en fonction de l'état
if(getState() == RUNNING){
remoteViews.setTextViewText(R.widget.text,getString(R.string.stop));

}else{
remoteViews.setTextViewText(R.widget.text,getString(R.string.start));
}

//et on envoie la mise à jour - ici on peut dépasser les 5sec etc... mais attention, en parallèle d'interfactions utilisateurs !
appWidgetManager.updateAppWidget(widgetId, remoteViews);

}
}

 

Et la gestion du cycle du service dans tout cela? Elle vient juste après ; nous avons donc besoin de pouvoir savoir quand le service démarre, “gère” et quitte :

@Override public void onCreate() {
super.onCreate();

updateWidgets();

}

@Override
public int onStartCommand(Intent intent, int flags, int e){
if(intent != null && intent.hasExtra("state")){
int state = intent.getIntExtra("state", 0);
if(state == 2){
_state = (this.getState() == RUNNING) ? STOPPED : RUNNING;
}

if(_state == STOPPED){
stopSelf();
}else if(_state == RUNNING){
}
updateWidgets();
}
return START_STICKY;
}

@Override
public void onDestroy() {
super.onDestroy();

_state = STOPPED;

updateWidgets();
}

Vous voyez ce que cela fait? Au démarrage du service, les widgets sont mis à jour pour indiquer qu’il est possible de quitter le service. Puis à l’extinction du service, ils le sont en leur indiquant que le service peut être lancé

 

Conclusion

Voilà, vous avez pu voir la création d’un très très simple widget qu’on aurait pu appeller le tout-pas-beau ainsi qu’un moyen de les mettre à jour par l’utilisation d’un service. Vous pouvez bien évidemment aussi utiliser les receiver pour récupérer des états bien spécifiques, des url, des tags NFC (quoique je n’ai pas essayé celui-là). A vous donc de gravir le reste de la montagne mais n’oubliez pas : le launcher, ce n’est pas un emplacement sur lequel utiliser tout l’espace, il faut penser à l’expérience utilisateur avant tout

Pokémon Rumble Java :: avancement

Le portage du jeu Pokémon Rumble en java avance bien. Actuellement, l’arène est fonctionnel et les Pokémon peuvent se déplacer dessus, chaque Pokémon à la possibilité d’attaquer mais, uniquement l’attaque éclair de Pikachu est disponible (je prévois 1 attaque/type et par Pokémon).
 
Voici quelques images du jeu, le Pikachu est le Pokémon du joueur humain.
 
rumble1
rumble2
rumble3

Pokemon rumble java @ pc … @ téléphones portables

J’ai dégoté Pokémon Rumble pour la wii et franchement, le prix en points est assez élevé quand on voit ce qu’ils ont fait >< > rien de réellement cool étant donné que les Pokémon ne changent pas de formes par rapport à My Pokémon Ranch, qu’à part l’aspect ring, rien de super ou hyper détonnant.
> pas de connectivité vers la ds ou de déblocage sur My Pokémon Ranch, un peu dommage, pas de Pokémon Event à la Pokémon Battle Révolution

donc pourquoi ne pas s’amuser à faire un truc analogue, bon ok, je ne ferais pas aussi bien graphiquement que ce que nous a pondu BigN mais bon, toujours fun, quand on a pas la Wii devant soi, de ce dire, “tient je vais me faire une tite partie de Bataille Royale” (le seul mode réellement sympa :p ).

Je posterais les versiosn au fur et à mesure que le développement avancera, pour le moment je prévois de pouvoir choisir on pomon et de pouvoir bouger sur le ring, et c’est tout…. :0)

Démineur java pour téléphone mobile

Dans le cadre d’un devoir pour un cours, j’ai choisi un projet personnel a faire pour le mois de janvier, mais bon, avec le temps que j’avais a rester cloitré au lit a cause de maladie, j’en ai profité pour l’avancer… et au final le finir (mais bon, des améliorations à prévoir :) ).

Pour pouvoir le télécharger, vous pouvez vous rendre directement via votre téléphone mobile sur http://codlab.1allo.com/m.html puis télécharger le .jar ou bien le charger depuis votre pc et le transférer sur le téléphone.

A noter que cette version nécessite un téléphone de dernière génération ayant un écran tactile, une trackball etc… (compatible pda), l’écran doi au moins être de 225*247 ***

***il marche très bien sur mon ku990i

Aquarium en Java : version 5

Voici la version 5 de l’Aquarium en java, cette version offre de nouvelle option dont l’ajout via des boutons de sharpedo / requins ou de Poissoroy|Poissirenes / sardines directement dans l’Aquarium ou bien même,au clic, de bouger n’importe quel élément. La vitesse de rafraichissement a été diminuée de 2 (400ms entre deux frames maintenant).

Le jar que je vous propose propose aussi la javadoc complète ainsi que les sources du projet (hum je rajoute la classe bombeA ? bon y a deja les images mais pas le plus fun ^^ )

Aquarium//aqua.jar

http://pokemon-france.fr.nf :: xss inside

Hum, pour ceux qui jouent à pomon et qui ne connaitraient pas ce site amateur (qui au passage propose des téléchargements illégaux… pourquoi est-ce que je précise >< >> le téléchargement illégal), ils proposent un service d’adoption (en bêta encore heureux vu le soucis qui suit – si ce n’est que ca :p )

Bien quand vous vous inscrivez sur le service d’élevage – omg pas lié avec celui du fofo 😡 >> usine à gaz inside²- vous choisissez un Pokémon de départ et il se trouve en première position.

Puis vous pouvez choisir 5 pokémon ensuite (6 pokémon sur soi en fait) par mi une liste….

….

Le hic? et bien le code de cet élevage n’est absolument pas un exemple de choses à faire :s

Pourquoi?
Et bien, tout d’abord, les values du select sont en fait une partie contenant image/{Pokemon}.png, bref vous l’aurez compris, directement le code html pour un (au moins), ce qui laisse supposer que le système est assez lourd pour la base de données : champ varchar(n) de x octets alors qu’un int serait bien plus lèger – ensuite potentiellement (et c’est le cas), hum code de ce type, html dans le values et bien pourquoi ne pas tester voir s’il y a du xss?

Qu’à cela ne tienne, en avant

Après quelques lignes de codes, des modifications pour la publication, voila un code java permettant de créer un compte, et d’y ajouter des Pokémon

(ceci marchera jusqu’à ce que le créateur corrige cela, sinon juste pour vous, des morceaux de la conversation (vous l’aurez compris, binboum est l’auteur :) :

» ME!! – 22-10-13:40 — y a pas grand chose de mal, surtout qu’il est simple de corriger ces failles, d’effacer les comptes (assez lolant certains d’ailleurs mais je m’égare) et ^^’ – il vaut mieux que ce soit moi que potentiellement d’autres qui plus est. M’enfin… lorsque binboum jugera qu’il a besoin de certains conseils ou qu’il applique au moins la limite ca sera un grand pas vers un truc plus sécurisé mais pas plus performant
» ME!! – 22-10-13:33 — Mais pourquoi t’a fais ça,pokasmax ?
» ME!! – 22-10-13:32 — c’est en gros, des tits soucis bénins (mais pouvant être problématiques dans certains cas) au niveau de la gestion du service côté serveur (un peu l’organisation aussi mais secondaire)
» mewtwo45 – 22-10-13:23 — Je ne compriens rien,mais ABSOLUMENT rien à ce que vous dites,pour moi,c’est du chinois^^
» ME!! – 22-10-13:20 — (si tu veux le code que j’ai utilisé, je le mets sur mon site – java inside par contre)
» ME!! – 22-10-13:17 — sinon (encore une fois) tu montres que tu refuses les remarques mêmes si elles sont constructives (du jamais vu, mais bon fallait bien que je tombe sur une personne comme ca dans ma vie 😡 ) après ban ip si tu veux, tu loupes pas mal de choses que j’aurais pu te montrer si tu le voulais
» ME!! – 22-10-13:13 — ba j’ai indiqué qu’il y avait la faille, un strip tag (ou un simple htmlentities) suffit largement ensuite des values d’option de ce type hum pas terrible, lourd pour la bdd ensuite (pourquoi gérer des varchar – alors que des références vers une table contenant les listings permis suffit? si tu veux que je t’explique tout ca pas de soucis
» binboum – 22-10-13:10 — carmais je sens que son ip va bizntot être bannie si il continue
» binboum – 22-10-13:10 — enfaitre y c’est servi des get pour faire des injection
» binboum – 22-10-13:09 — xss c’est une faille ^^

(au passage, quelqu’un pour lui expliquer que bloquer une ip ne suffit pas? si vous avez suivi d’autres de mes articles vous comprendrez de quoi je parle (au moins sur un côté) )

Trêves de mots, le code? unexecutable? ici


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;

public class Test {
/**
* Constructeur paramétré - simple
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
// Construct data
String data = null;
URL url = null;
boolean sortie = false;
System.out.println(args.length);
if (args.length == 5 && args[0].contains("-inscription")) {
data = URLEncoder.encode("pseudo", "UTF-8") + "="
+ URLEncoder.encode(args[1], "UTF-8");
data += "&" + URLEncoder.encode("motdepasse", "UTF-8") + "="
+ URLEncoder.encode(args[2], "UTF-8");
data += "&" + URLEncoder.encode("courriel", "UTF-8") + "="
+ URLEncoder.encode(args[3], "UTF-8");
// exemple pour args[4] : "images/Dracaufeu.png"
// en sachant qu'il est possible de mettre du html - attention
// il utilise un varchar limité, donc pas de trop trop longs
// codes ^^
// exemple de code possible si vous injectez du code (vilains
// rho :p )
// args[4] =
// "images/Dracaufeu.png\" />" width="80" etc...
// et maintenant on a
// bref le code est bien
// fermé
data += "&" + URLEncoder.encode("imgpoke", "UTF-8") + "="
+ URLEncoder.encode(args[4], "UTF-8");
url = new URL(
"http://pokemon-france.fr.nf/visite/inscription2.php");
} else if (args.length == 2) {
data = "&" + URLEncoder.encode("place", "UTF-8") + "="
+ URLEncoder.encode(args[0], "UTF-8");
data += "&" + URLEncoder.encode("imgpoke", "UTF-8") + "="
+ URLEncoder.encode(args[1], "UTF-8");
url = new URL("http://pokemon-france.fr.nf/visite/adopter2.php");
} else
sortie = true;

if (!sortie) {
System.out.println("Et hop chargement....");
// on envoie les données
URLConnection conn = url.openConnection();
/* on initiliase les cookies
* pour plsu d'infos mozilla > options et allez récupérez l'ensemble de
* vos cookies du site http://pokemon-france.fr.nf
*/
conn.setRequestProperty("Cookie",
"sid=---;mybbuser=---;loginattempts=1;mybb[lastactive]=---;mybb[lastvisit]=---;PHPSESSID=---;");
conn.setDoOutput(true);
OutputStreamWriter wr = new OutputStreamWriter(conn
.getOutputStream());
wr.write(data);
wr.flush();

// on obtient la réponse
BufferedReader rd = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
// pour le fun on affiche
System.out.println(line);
}
wr.close();
rd.close();
}
} catch (Exception e) {
}

}

}

Maintenant passons à une partie plus technique que du code, c’est-à-dire comment aider notre programmeur a corriger.

Des idées? effectivement, empêcher le code html d’être directement injecté… Oui, pourquoi pas protèger aussi pour avoir uniquement les images voulues…. et effectivement, certainement revoir un peu la partie base de données.

Donc voici quelques “tips” (mais la doc php est là 😉 )
Empêcher du html : on a le strip tags, et htmlentities
Utiliser uniquement les images voulues? pourquoi pas un array d’image et les values des select auraient les id – ca permettrait comme ca que chaque pages permettant d’avoir un pomon seraient “unique”, ainsi les starters qu’au début et les autres là ou on veut les avoir ou non.

côté bdd?
Vu le code, on peut supposer qu’il utilise (extrapolation):
Membre(id_membre,pseudo,mdp,mail,…)
Pokemon(id_pokemon,image_pokemon,…id_membre)
– et ce dans le cas où le système est moyennement bien codé –
dans le pire des cas, notre webaster aura utilisé une seule table avec au moins 6*X champs tel que X est le nombre de champs pour un pokémon.

Une utilisation un peu plus propre?
Membre(id_membre,pseudo,mdp,mail,…)
Pokemon(id_pokemon,image_pokemon,…)
Liaison(id_membre,id_pokemon,{infos du pokemon du membre})

Ainsi les infos d’un pokémon d’un dresseur seraient stockées dans liaison et plus pokémon, et pokémon ne serait que le squelette du comportement global d’un pokémon défini.

*Les champs soulignés sont les clés des tables

plus d’infos? vous pouvez me mailer ou poser des commentaires.

Projet tuteuré java & Pokémon

Et oui, on peut faire un mixe entre études et Pokémon (lol?)

Nous devons faire un projet en java (un super aquarium kikoo ><), j’ai bien avancé le projet (@mal codé :p ). Et juste pour le fun, j’ai mis des poissons s’affichant avec des poissoroy et les requins avec des sharpeo %)

Pour télécharger le jar exécutable (contenant aussi la doc, et les sources), c’est ici