Profile

Cover photo
Stéphane Guérin
Works at Netco Sports
Attended Ecole Centrale Paris
Lives in Paris
1,078 followers|181,725 views
AboutPostsPhotosYouTubeReviews

Stream

Stéphane Guérin

Shared publicly  - 
 
 
Update on Google I/O Registration Window -- opening next week:

We're still working to make the registration process even easier for you, and it will now be open four days starting next week (opening next Tuesday and closing Friday). After the registration window closes, applicants will randomly be selected and we'll send ticket purchase confirmation emails shortly thereafter. #googleio   #io2014  
1
Add a comment...

Stéphane Guérin

Shared publicly  - 
 
 
Android App Polishing: Adding Subtle Attention Seekers

With the release of Capitaine Train for Android[0], several people recently asked me how we implemented some of the tips & tricks available in the application (some of these tricks are barely visible but remember, I love details :p). In order to showcase some of the most interesting application bits of code, I thought it could be helpful to Android developers to start a small series of posts. Feel free to comment this article if you want me to describe something you found nice in the Capitaine Train application.

During the entire development of the Capitaine Train Android app, we kept one important thing in mind: be subtle but still understandable. Although this rule is easy to understand it is always hard to implement correctly.

Some great examples of adding subtle but yet understandable visual tricks are the search form and the passenger detail screen. Indeed, when launching a new train search with some missing required fields, the field animates to indicate the user something is wrong. An equivalent is the "Add a passenger" ActionBar button than wobble when the user is tapping the empty screen indicating she/he has no registered passengers yet. This wobbling button is like saying "Hey, guy, tap me to create a new passenger!". The gif attached to this post demonstrates the animation but let's be honest I'm not a gif expert :s I highly encourage you to have a look at the Capitaine Train and try it out directly ;).

When used appropriately, attention seekers, are way better than these pretty ugly Toasts displayed right in the middle of the screen. Why? Mostly because they are subtle and require less time to be scanned/parsed than a long and difficult to read text.

But how to implement such an animation? It generally consists on several "back and forth"... We could have obviously implemented this using a sequence of ObjectAnimators or a pretty weird TimeInterpolator but that would have been quite painful. The trick is simply to leverage the animation framework by using the Keyframe[1] & PropertyValuesHolder[2] objects.

A Keyframe is an object that holds a time/value pair describing a particular state in an animation. For instance Keyframe.ofInt(.5f, Color.RED) indicates the color should be Color.RED at 50% of the animation duration.

A PropertyValuesHolder is a class that associates a property to some values. It is particularly useful whenever you want to animate several properties at once with a single ValueAnimator.

When developing the Capitaine Train application we created several attention seekers and tried them all. We finally ended up using only 2 different animations:
  
  • The "nope" animation: used whenever a field is invalid (this is the case when trying to start a search with some missing mandatory fields)
  • The "tada" animation: used to indicate the user the action she/he is looking for is probably a tap-away from this button (this is the case when tapping the empty state with no passenger and/or when tapping the "no cards" cell on the passenger detail screen)


public static ObjectAnimator tada(View view) {
    return tada(view, 1f);
}

public static ObjectAnimator tada(View view, float shakeFactor) {

    PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofKeyframe(View.SCALE_X,
            Keyframe.ofFloat(0f, 1f),
            Keyframe.ofFloat(.1f, .9f),
            Keyframe.ofFloat(.2f, .9f),
            Keyframe.ofFloat(.3f, 1.1f),
            Keyframe.ofFloat(.4f, 1.1f),
            Keyframe.ofFloat(.5f, 1.1f),
            Keyframe.ofFloat(.6f, 1.1f),
            Keyframe.ofFloat(.7f, 1.1f),
            Keyframe.ofFloat(.8f, 1.1f),
            Keyframe.ofFloat(.9f, 1.1f),
            Keyframe.ofFloat(1f, 1f)
    );

    PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofKeyframe(View.SCALE_Y,
            Keyframe.ofFloat(0f, 1f),
            Keyframe.ofFloat(.1f, .9f),
            Keyframe.ofFloat(.2f, .9f),
            Keyframe.ofFloat(.3f, 1.1f),
            Keyframe.ofFloat(.4f, 1.1f),
            Keyframe.ofFloat(.5f, 1.1f),
            Keyframe.ofFloat(.6f, 1.1f),
            Keyframe.ofFloat(.7f, 1.1f),
            Keyframe.ofFloat(.8f, 1.1f),
            Keyframe.ofFloat(.9f, 1.1f),
            Keyframe.ofFloat(1f, 1f)
    );

    PropertyValuesHolder pvhRotate = PropertyValuesHolder.ofKeyframe(View.ROTATION,
            Keyframe.ofFloat(0f, 0f),
            Keyframe.ofFloat(.1f, -3f * shakeFactor),
            Keyframe.ofFloat(.2f, -3f * shakeFactor),
            Keyframe.ofFloat(.3f, 3f * shakeFactor),
            Keyframe.ofFloat(.4f, -3f * shakeFactor),
            Keyframe.ofFloat(.5f, 3f * shakeFactor),
            Keyframe.ofFloat(.6f, -3f * shakeFactor),
            Keyframe.ofFloat(.7f, 3f * shakeFactor),
            Keyframe.ofFloat(.8f, -3f * shakeFactor),
            Keyframe.ofFloat(.9f, 3f * shakeFactor),
            Keyframe.ofFloat(1f, 0)
    );

    return ObjectAnimator.ofPropertyValuesHolder(view, pvhScaleX, pvhScaleY, pvhRotate).
            setDuration(1000);
}

public static ObjectAnimator nope(View view) {
    int delta = view.getResources().getDimensionPixelOffset(R.dimen.spacing_medium);

    PropertyValuesHolder pvhTranslateX = PropertyValuesHolder.ofKeyframe(View.TRANSLATION_X,
            Keyframe.ofFloat(0f, 0),
            Keyframe.ofFloat(.10f, -delta),
            Keyframe.ofFloat(.26f, delta),
            Keyframe.ofFloat(.42f, -delta),
            Keyframe.ofFloat(.58f, delta),
            Keyframe.ofFloat(.74f, -delta),
            Keyframe.ofFloat(.90f, delta),
            Keyframe.ofFloat(1f, 0f)
    );

    return ObjectAnimator.ofPropertyValuesHolder(view, pvhTranslateX).
            setDuration(500);
}

Once again, attention seekers are great but they should be used with parsimony. The less you use them, the greater their influence is.

#gde #android

[0]: https://play.google.com/store/apps/details?id=com.capitainetrain.android
[1]: http://developer.android.com/reference/android/animation/Keyframe.html
[2]: http://developer.android.com/reference/android/animation/PropertyValuesHolder.html
3
Add a comment...
 
 
Today’s #AndroidDev #Protip from +Nick Butcher is about entering email addresses.

Entering data on mobile devices with on screen keyboards can be challenging; typing out email addresses can be particularly fiddly.   Anything you can do to ease this will be appreciated by your users and make them less likely to abandon your app.  While social identity providers (such as Google+ Sign-In [0][1]) can ease the process of signing in, there may be situations where you require direct input.

With the user’s permission [2], you can query the AccountManager [3] for accounts saved on the device.  You can then present these options, for example by using them as suggestions for an AutoCompleteTextView [4]:

final Account[] accounts = AccountManager.get(context).getAccounts();
final Set<String> emailSet = new HashSet<String>();
for (Account account : accounts) {
    if (Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) {
        emailSet.add(account.name);
    }
}
List<String> emails = new ArrayList<String>(emailSet);
mEmailAutoCompleteView.setAdapter(new ArrayAdapter<String>(context, android.R.layout.simple_dropdown_item_1line, emails));

Note that in the above snippet we’ve used a Set to de-duplicate accounts and a regex to only use accounts which are email addresses.

You can also ease entering email addresses not already known to the device by setting an appropriate keyboard layout and providing a meaningful action:

<AutoCompleteTextView
    android:inputType="textEmailAddress"
    android:imeActionLabel="@string/sign_up"
    android:selectAllOnFocus="true"
    … />

Not only will this technique ease data entry, but it will help prevent typos and remove the need to enter an address twice for verification (and double annoyance!)  If you have more tips for easier data entry, let us know in the comments.

[0] https://developers.google.com/+/mobile/android/
[1] Android Design in Action: Onboarding Experience
[2] http://developer.android.com/reference/android/Manifest.permission.html#GET_ACCOUNTS
[3] https://developer.android.com/reference/android/accounts/AccountManager.html
[4] https://developer.android.com/reference/android/widget/AutoCompleteTextView.html
5
Add a comment...
 
 
I just made in Inkscape a svg with a construction Bugdroid and a skyline of Paris.

Hope you wil enjoy it :)
2
1
Frank Harper's profile photoEdouard Marquez's profile photo
2 comments
 
Thanks +Marion Hayoun it's beautiful, and it awakens my latent Parisian nostalgia!
Add a comment...
 
 
The most hotly anticipated mobile game sequel is here!! 
1
Add a comment...
Have him in circles
1,078 people
Didier Tranchier's profile photo

Stéphane Guérin

Shared publicly  - 
 
 
Google is rebooting its TV ambitions
Every so often, some enterprising computer company will claim they’ve finally fixed the TV. They’ll talk about how they’ve turned a dumb terminal into a smart computing platform that extends...
2
Add a comment...
1
1
Ilya Bogdanovski's profile photo
Add a comment...
 
On cherche un développeur Android confirmé pour travailler sur de super projets (vraiment) chez Netco Sports
 ·  Translate
4
2
Edouard Marquez's profile photoJulien Del Rio's profile photoPierre-Olivier Dybman's profile photo
 
Ping +Djavan Bertrand !
Add a comment...

Stéphane Guérin

Shared publicly  - 
 
 
Vous pouvez maintenant soumettre vos présentations pour les prochaines conférences, directement sur notre site :
 ·  Translate
2
1
Antonin Fouques's profile photo
Add a comment...

Stéphane Guérin

Shared publicly  - 
 
 
If the success of Flappy Birds has made you think that Play Games Leaderboards would be a marvelous thing to add into your game, then the GitHub repo of samples is a great resource. I'd love to see more games implementing Play Games Cloud Backup as well.
3
1
Albrecht Noll's profile photo
Add a comment...
People
Have him in circles
1,078 people
Didier Tranchier's profile photo
Work
Occupation
Android Technical Manager
Skills
Android development, Startups
Employment
  • Netco Sports
    Android Technical Director, 2012 - present
  • Paris Android User Group
    President, 2010 - present
  • Appoke
    CEO, 2010 - 2013
Places
Map of the places this user has livedMap of the places this user has livedMap of the places this user has lived
Currently
Paris
Previously
Saint-Etienne - Annonay
Story
Introduction
President of the Paris Android User Group. Android Technical Lead at Netco Sports (Canal Football App, UEFA Euro 2012, CAN, AS Monaco, Vendée Globe,...)
Education
  • Ecole Centrale Paris
    Computer Science, 2005 - 2008
Basic Information
Gender
Male
Un garage capable de te faire payer la réparation d'un pneu endommagé par un de ses mécaniciens... Première et dernière fois que j'y met les pieds.
Public - 2 months ago
reviewed 2 months ago
2 reviews
Map
Map
Map