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

Tagged with:  

New Contactless payment solution

On 23 April, 2013, in android, internet, java, by codlab

I am currently finishing a whole news payment solution for every NFC compatible devices.

Easy to use, easy to implement, the solution is simply based on having connectivity between the seller device (or pc with NFC ready peripheral : acrxxx, etc… ) and the buyer.

The buyer sync with a server, the buyer receive the push from the buyer and sync with the server etc… and tada

The solution currently work with paypal and let you having payment solution better than the one you can see in the apple stores B) hey, it is great to say to a customer “you have nfc on your smartphones? you can buy our product directly with your paypal account”

I am open to implement any other solutions, if you are a company and want it, you can contact me per mail to discuss about the condition and to link your project/solution with it (for instance if you don’t want paypal but your own servers, etc…)

Tagged with:  

You already may have encountered “bug” by using a Viewpager and a SlidingMenu at the same time :

this bug is simply while sliding viewpager… the sliding menu “takes” the event.

 

How to fix it?

In fact, it is very simple. First of all, make an object (your fragment, activity…), create a method which will take one integer (native one, not the Object ;p )

In it, you can simply check if the index is equal to 0 (or the maximum if you were using a right menu >> according to your code, but here, I will only make it compatible with left. Add now a simple if else statement. If the index is 0 then enable the menu, otherwise disable it.

For example:


public class SlidingViewPagerFragmentActivity extends SlidingFragmentActivity{
  public void setViewPagerSelected(int index){
    //in this example, I also check for the screen
    //which is currently selected
    if(index == 0 && this.findViewById(R.id.mobile) != null){
      this.getSlidingMenu().setSlidingEnabled(true);
    }else{
      this.getSlidingMenu().setSlidingEnabled(false);
    }
  }
}

Now that we have a perfectly working checking method, you can now implements a OnPageChangeListener in your activity/fragment/whatever… (from the …view.ViewPager package)

Once done, you will have to override the onPageSelected(int index) method. In this one, call your Object which manage the SlidingMenu (in my own code, I made an object override SherlockFragmentActivity, implements the first method in it and then, my activities simply override my Activity with this method. And to finish (last little thing), register your Object in the :
yourpager.setOnPageChangeListener()
//note that if you use the ViewPagerIndicator, you will have to register your Object
//in the indicator ;)

For instance (in a SherlockFragment):


public class FragmentExample extends SherlockFragment{
  @Override
  public void onPageSelected(int index) {
    if(getSherlockActivity() instanceof SlidingViewPagerFragmentActivity){
      ((SlidingViewPagerFragmentActivity)getSherlockActivity()).setViewPagerSelected(index);
    }
  }
}

And voila ;)

Tagged with:  

pfffioooouuuu posted a (unsigned) long long time ago but there it is : a new post !

Today, i’ll write about the BAUG (yep, in Bordeaux, France), it was the first session about two topics : Android / UI Guidelines and finally, Market Shares / Evolution.

It was really interesting with those two conferences and after, chat with every one in the conference room.

Happy to take part in this adventure =)

Tagged with:  

Androtex server close in few hours

On 28 December, 2012, in Uncategorized, by codlab

Hi everyone,

bad news today, due to recent problem with the server (overload, etc…) I must disable it for days (between 1 and 2 months maximum) you can create your own server without any problem :)

 

Well of course it s ire rewritten from the previous post (here).

Well first, simply create a certificate :
Open the Keychain app from the LaunchPad > Utilities > Keychain Access

From the menus, choose “Certificate Assistant” > create a certificate
From the window, choose Certificate Type => Code Signing
and from the Text Input above, choose a name for our certificate such as JailbreakTests (You need to remember the name ;) )

Now the fun part updated !!
Open a terminal and type (or cmd+c/cmd+v)
cd /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/
now
sudo cp Info.plist ~/Desktop
open ~/Desktop/Info.plist

(it will launch XCode) now replace every XCiPhoneOSCodeSignContext => XCCodeSignContext
sudo cp ~/Desktop/Info.plist Info.plist

Now the third part,
from the current directory change to ./Developer/SDKs/iPhoneOSX.Y.sdk with X.Y egal to 5.1 for example
so

cd Developer/SDKs/iPhoneOS5.1.sdk/
and then :
sudo cp SDKSettings.plist ~/Desktop
open ~/Desktop/SDKSettings.plist

sudo cp ~/Desktop/SDKSettings.plist SDKSettings.plist

and replace every YES from every *_REQUIRED to NO

And finally,
cd /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/PrivatePlugIns
cd iPhoneOS\ Build\ System\ Support.xcplugin/Contents/MacOS/
sudo nano create.sh

and copy/paste this code to this the nano which opened :
dd if=iPhoneOS\ Build\ System\ Support of=working bs=500 count=255
printf “\xc3\x26\x00\x00″ >> working
/bin/mv -n iPhoneOS\ Build\ System\ Support iPhoneOS\ Build\ System\ Support.original
/bin/mv working iPhoneOS\ Build\ System\ Support
chmod a+x iPhoneOS\ Build\ System\ Support

type ctrl+o and ctrl+x

now, type:
sudo chmod +x create.sh
sudo ./create.sh

You will se something like
55+1 … in
55+1 … out
27712 bytes transfered

Restart Xcode if it was open, if not, just launch it !

Open your project and change the build configuration from every Code Signing to “Don’t Code Sign”
This step will make Xcode not code signing the code

Now, we will code sign ourself the code, to enable it we execute this code :

mkdir -p /Developer/iphoneentitlements
cd /Developer/iphoneentitlements
curl -O http://www.alexwhittemore.com/iphone/gen_entitlements.txt
mv gen_entitlements.txt gen_entitlements.py
chmod 777 gen_entitlements.py

and now, in the project, on the target add a new custom build phase to run script:
and copy/paste this code and replace iPhone Developer to the name you choose when you made your certificate:

export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate
if [ "${PLATFORM_NAME}" == "iphoneos" ]; then
/Developer/iphoneentitlements/gen_entitlements.py “my.company.${PROJECT_NAME}” “${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/${PROJECT_NAME}.xcent”;
codesign -f -s “iPhone Developer” –entitlements “${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/${PROJECT_NAME}.xcent” “${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/”
fi

This code will auto sign the application

If your iDevices was not configure to do development, you need to open the Organizer and select your iDevice. Then choose “Use for development”

That’s it, you can now choose the iDevice instead of the emulators

Tagged with:  

Guild Wars 2 Halloween ClockTower jumping puzzle

On 27 October, 2012, in guildwars, by codlab

With Halloween, new achievements and events came.

Here is my walkthrough of the clock tower which can give you reward and a title achievement.

 

Tagged with:  

Here we are! The Galaxy S3 is a great device but … the external sd (up to 64GB) IS NOT used per default to store Android/data when you want to use external storage to store data. It is here that the application I developed can help you!

If your device is rooted, you can now swap the internal and external sdcard forever (in fact at every boot) or until the phone reboot

Does it work with every devices? In fact, it was made to be installed and used on a Galaxy S3 but the trick used in the app can be modify to work with … every devices which embed 2 sdcard (internal & external)

To manage these features :

  1. you can update the configuration list directly from the internet
  2. you can set your own configuration (only 1 at this time)
  3. you do not know what device represent your physical sdcard? no problem, you can directly from the application check every device on the phone/tablet and choose the correct one and it will edit the custom paramter !
  4. you do not know what to do? you can send the list provided, and/or your build.prop (the build.prop will help me to create new configuration for everyone when they download the updated configuration list)

You can download and install directly from this link (the store one will soon arrive)

http://www.codlab.eu/Internal2External.apk

Tagged with:  

What a long title to a simple and really easy system.

But It took me some minutes to find how to manage to open my application activity when a nfc tag is read with a particular url.

Here is the trick :
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<data
android:host="google.com"
android:scheme="http" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

put this between <activity></activity> to tell to the system that the activity can hold the http://*.google.com/* and should start it by default

It will also override the internet browser ;)

Tagged with:  

Men In Black Neuralyzer on Android

On 13 June, 2012, in android, java, by codlab

Just a post about a new application I just released on the Android Market. This time, it is a neuralyzer free to download which can operate as a neuralyzer (erf on/ neuralyser? neuraliser? neuralizer? /erf off)

How it works? It simply use the flash torch mode to start and stop the flash. You can simply use it this way through java code to handle Android’s Camera Flash

Camera cam = Camera.open();
Parameters cam_parameters = cam.getParameters();

cam_parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
cam.setParameters(cam_parameters);
… time
cam_parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
cam.setParameters(cam_parameters);

cam.release()

Tagged with:  

Switch to our mobile site