Profile

Cover photo
Cyril Mottier
Works at Capitaine Train
Attended INSA de Rennes
Lives in Lyon, France
7,602 followers|4,444,231 views
AboutPostsPhotosYouTube

Stream

 
Android App Polishing: Leveraging Reselect Taps

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.

In a previous post of mine[1], I explained how much attention we put to the Capitaine Train Android app search form. Indeed, the search form is probably the most important screen in the application. This is where all train trips begin after all!

Prior publicly releasing the application, we spent quite some time doing some user-testing. While most people were satisfied with the current implementation of the Search form, some other users were frustrated by the "OK" button on the upper-left corner of the screen when selecting an outward and/or inward date/time. It finally appears these users were all Android active/power users!

The "OK" button was originally placed here because it felt logical to us to put it here:

  • It is consistent with some other Android apps (GMail, Gallery, etc.)
  • It matches the "ActionBar" contextual mode pattern
  • It indicates you're in an edit mode rather than in the normal user-flow
  • It doesn't take space on an already charged screen

The unique complain about the "OK" button being here was it was not "easily accessible". Indeed, the scanning process in all search form edit modes is to go from the top to the bottom of the screen. As a consequence, it was pretty annoying to power-users to go back to the top of the screen to validate the selected date/time (especially for users using their device with one hand).

Hence, we were faced with an serious issue: break everything just to satisfy power users or keep the form "as-it" ... We finally came out with a simple but yet-extremely useful idea: leverage the "reselect to validate" gesture. Because normal/regular doesn't care about "quick" edit mode validation we simply decided to validate the selected date/time once the date or time is reselected.

Android doesn't really put the "reselect to do smth" pattern in front of the scene. This is mainly because it is up to the application to decide which UI element can be "reselected". There are still references to this pattern in the framework's ActionBar TabListener. The onTabReselected(ActionBar.Tab, FragmentTransaction), for instance, can be used to scroll a scrollable container to the top.

This pattern is obviously not visible and that's actually how power-user gestures should be: available but visually hidden and used sparingly. Just be adding this power-user gesture we kept a visually simple UI for most users while still satisfying power-users. When developing an Android application always concentrates on creating a UI dedicated to general users. Start thinking for power-users only if they really complain about your UI!

[O]: https://play.google.com/store/apps/details?id=com.capitainetrain.android
[1]: https://plus.google.com/118417777153109946393/posts/UoM8g1BbzAp
[2]: http://developer.android.com/reference/android/app/ActionBar.TabListener.html#onTabReselected(android.app.ActionBar.Tab, android.app.FragmentTransaction)
92
44
Simone Leoni's profile photoRoy Sun's profile photoAtaul Munim's profile photoYao-Te Tsai's profile photo
13 comments
 
+Steren Giannini I agree, I was not entirely satisfied with the solution at first but user-testing validated my choice. As +Ataul Munim said, validation on Android is kind of a mess :(

+Ataul Munim I had no new messages from power-users after the gesture was included so I guess they are OK with that…

+Frank Harper We couldn't go for the big "DISCARD/DONE" solution in this case for several reasons (we did we some other screens in the app). The DISCARD/DONE button would have prevented us to change the title indicating what the user is currently editing. Moreover, it wouldn't have been possible to add some extra actions (like adding a new passenger in the current version of the app).

+Stan KOCKEN Your designer is right :) I also hate to put several buttons that does the same thing on screen. However in this case I don't think it's an issue as it doesn't impact the visual hierarchy of the screen (nothing indicates the gesture is available)

+Patrick Fuentes +Martin Rajniak I'll try to write a complete post to explain how I made the search form transitions. Just have to find some free time...
Add a comment...
 
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
401
189
Roland Yeghiazaryan's profile photoJiří Hromádka's profile photoShuhrat Dehkanov's profile photoBenjamin Weiss's profile photo
44 comments
 
+Cyril Mottier do you use custom items in action bar? For example, "Add a passanger" item. Is this custom view? When i call getActionView() from standart menuItem it returns null and I can't animate it, however when i set imageview in action bar, animation works.
Add a comment...
 
For the past few months, +Mathieu Calba and I have been working really hard on the Capitaine Train #Android app, the best train ticket booking engine in France and nearby countries. We are really proud to finally see it live on the Play Store[0]. Go get it now!

[0]: https://play.google.com/store/apps/details?id=com.capitainetrain.android
147
21
Henri Dominique Rapin's profile photoJosé M. Pereira's profile photoKarthik Subramaniam's profile photoPieter-Jan Vandormael's profile photo
23 comments
 
+Cyril Mottier really very well done! Animations are really subtle and slick. Especially new activity animations with zoom in/out.

Congrats!

+Roman Nurik nomination for your show :) 
Add a comment...
 
Smoothly animating TextView's text color

Starting Android 3.0 (Honeycomb), the framework provides developers with a bunch of utilities to animate View properties such as their x/y position, background color, alpha, etc. Animating objects is a vast and subtle topic in mobile development. Animations are an excellent way to indicate users how a UI "transformed" itself from one state to the other but performing to many animations at the same time may also completely waste the user experience.

In this article, I want to show you how to animate the text color of a TextView. Although this may seem easy at first sight, it requires some little workarounds if you want the animation to perform correctly. In order to demonstrate the code, we will use a simple example that perform a smooth text color transition from black to red.

Attempt #1

Let's begin with the simpliest code ever that you can use to animate a value. It consists on getting a reference on the TextView, creating an ObjectAnimator on the "textColor" property and starting it:

final TextView textView = (TextView) findViewById(R.id.text);
textView.setTextColor(Color.BLACK);

final ObjectAnimator animator = ObjectAnimator.ofInt(textView, "textColor", Color.RED);
animator.setDuration(333L);
animator.setEvaluator(new ArgbEvaluator());
animator.setInterpolator(new DecelerateInterpolator(2));
animator.start();

This code runs perfectly and, as, expected, it animates the text color. But it animates the text color from transparent to red although I've explicitly set the text color to black prior starting the ObjectAnimator. Because we don't want to deep dive into the code (at least for now), let's workaround this issue by using a different implementation.

Attempt #2

Android introduced a new way to encapsulate a property in API 14: Property[0]. This class is extremely handy and lets you create a new instance just by calling the "of(Class<T>, Class<V>, String)" static factory method:

final TextView textView = (TextView) findViewById(R.id.text);
textView.setTextColor(Color.BLACK);

final Property<TextView, Integer> property = Property.of(TextView.class, int.class, "textColor");
final ObjectAnimator animator = ObjectAnimator.ofInt(textView, property, Color.RED);
animator.setDuration(333L);
animator.setEvaluator(new ArgbEvaluator());
animator.setInterpolator(new DecelerateInterpolator(2));
animator.start();

If you run this code, you will end up with an annoying but understandable Exception:

android.util.NoSuchPropertyException: No accessor method or field found for property with name textColor

To sum up, this Exception informs us TextView has no "int getTextColor()". Indeed, looking at the TextView's API, we can notice it has a "ColorStateList getTextColors()" method but no "int getTextColor()". Fortunately, that doesn't mean we're stuck : "int getCurrentTextColor()" is here to the rescue.

Attempt #3 ... the finale one

Because TextView has no "int getTextColor()" method, we need to create a completely custom Property that will forward the set/get method to the appropriate TextView methods:

final TextView textView = (TextView) findViewById(R.id.text);
textView.setTextColor(Color.BLACK);

final Property<TextView, Integer> property = new Property<TextView, Integer>(int.class, "textColor") {
   @Override
    public Integer get(TextView object) {
        return object.getCurrentTextColor();
    }

   @Override
    public void set(TextView object, Integer value) {
        object.setTextColor(value);
    }
};

final ObjectAnimator animator = ObjectAnimator.ofInt(textView, property, Color.RED);
animator.setDuration(333L);
animator.setEvaluator(new ArgbEvaluator());
animator.setInterpolator(new DecelerateInterpolator(2));
animator.start();

Running the code above, we finally have a smooth animation from black to red. 

Conclusion

Although, the solution we endup is based on Property - a Android 4.0+ API - it doesn't mean you can't animate TextView's text color pre-API 14. The solution pre-API 14 is a little bit trickier though and consists on manually listening to "animation ticks" and changing the text color manually.

The Property-based solution didn't explain us why the first attempt was animating from transparent to red rather than black to red. Put simply, ObjectAnimators based on property names use a completely different algorithm to determine the getters and setters. When using property names the code accepts non-existing setters/getters[3] while Property-based ObjectAnimators are more strict and require the setter and getter to exist[4]. Because of this, we were actually animating from an unknown color of value 0x0 (i.e. Color.TRANSPARENT) to the final red color.

In a nutshell, I strongly encourage you to use Property when animating values. You can seriously consider the old property name-based APIs as deprecated. This is also a great opportunity for you to set the min SDK of your application to 14!.

[0]: http://developer.android.com/reference/android/util/Property.html
[1]: http://developer.android.com/reference/android/widget/TextView.html#getTextColors()
[3]: https://github.com/android/platform_frameworks_base/blob/master/core/java/android/animation/PropertyValuesHolder.java#L378-L422
[4]: https://github.com/android/platform_frameworks_base/blob/master/core/java/android/util/ReflectiveProperty.java#L45-L88

#gde   #android   #blogpost
115
59
Thuy Trinh's profile photoRobin Chutaux's profile photoSebastiano Poggi's profile photoJoe Scott's profile photo
13 comments
Jay Ray
 
For Attempt #1, i suggest the following: "final ObjectAnimator animator = ObjectAnimator.ofInt(tv, "textColor", Color.TRANSPARENT, Color.WHITE);" as example
Add a comment...

Cyril Mottier

Shared publicly  - 
 
A nice introduction to Espresso presented by +Stephan Linzner 
 
Here are my slides for the Espresso Introduction i presented at +GDG Düsseldorf  Christmas Meetup. 

Big thanks to the organizers +Randy Gupta and +Resul Kocyigit which again did an awesome job!

#androidtesting   #espresso  
78
40
Béla Gubics's profile photoVitalik Zasadnyy's profile photo
Add a comment...
Have him in circles
7,602 people
Chansuk Yang's profile photo
 
Android App Polishing: Show UI State Through Icons

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.

As some of you may have noticed, we put a lot of attention to the search form in the Capitaine Train Android app. As I explained in my previous article[1], I'm not a huge fan of long texts. While often offering a great explanation, text requires a lot of parsing time. Icons are often a great alternative to text because they allow user to understand what's going on more rapidly.

When creating the search form, we thought about leveraging icons to help user better understand the current "form state". As a consequence, the form heavily relies on icons:

  • The "To" icon changes whether the search is round trip or not
  • Mandatory fields (i.e "From", "To" and "Passengers") icons turn red when missing
  • A red icon turns grey in edit mode while animating back to red if the field is not set when exiting the edit mode
  • The "Passengers" icon changes depending on the current number of selected passengers (see screencast)

As you can see in the screencast, the change is done as smoothly as possible simply fading between the different states. This can be done fairly easily thanks to a LevelListDrawable[2]. Here is the XML we use in Capitaine Train Android for the "Passengers" icon.

<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- The error icon -->
    <item
        android:drawable="@drawable/ic_search_passengers_0"
        android:maxLevel="0"
        />

    <item
        android:drawable="@drawable/ic_search_passengers_1"
        android:maxLevel="1"
        />

    <item
        android:drawable="@drawable/ic_search_passengers_2"
        android:maxLevel="2"
        />

    <item
        android:drawable="@drawable/ic_search_passengers_several"
        android:maxLevel="10000"
        />

</level-list>

Starting API 11, you can animate changes in a LevelListDrawable or more globally in any DrawableContainer. Unfortunately, the framework only exposes the XML attributes in <selector /> (I really don't know why it has not being exposed to all DrawableContainer :s). Fortunately for us, you can tweak the fading duration values in your Java code with the set[Enter|Exit]FadeDuration(int) methods (yep I also don't know why the duration is an 'int' rather than a 'long').

In our code, we simply update the icon whenever there is an impacting change (an error occurred, the number of selected passenger changed, etc.). Here are some notes about the following snippet of code:

  • mFieldErrorState is a bit mask gathering all of the fields that are currently in error
  • mEditMode contains the current "edit mode" ("Passengers", "From", "To", etc.).
  • LEVEL_ERROR is 0 & LEVEL_NORMAL is 1

private void updateIcons(boolean animated) {
    final int animationDuration = (int) ANIMATION_DURATION;

    // Update the "From" icon...

    // Update the "To" icon...

    final Drawable passengersIcon = mPassengersView.getCompoundDrawables()[TextViewAdditions.INDEX_LEFT];
    if (passengersIcon != null) {
        if (passengersIcon instanceof LevelListDrawable) {
            ((LevelListDrawable) passengersIcon).setEnterFadeDuration(animationDuration);
            ((LevelListDrawable) passengersIcon).setExitFadeDuration(animationDuration);
        }
        int level = LEVEL_ERROR;
        if ((mFieldErrorState & ERROR_PASSENGERS) == 0 || mEditMode == EDIT_MODE_PASSENGERS) {
            level = Math.max(LEVEL_NORMAL, mPassengerIds.size());
        }
        passengersIcon.setLevel(level);
        if (!animated) {
            passengersIcon.jumpToCurrentState();
        }
    }
}

[0]: https://play.google.com/store/apps/details?id=com.capitainetrain.android
[1]: https://plus.google.com/118417777153109946393/posts/FABaJhRMCuy
[2]: http://developer.android.com/reference/android/graphics/drawable/LevelListDrawable.html
273
119
Sinan KOZAK's profile photoJ.L H's profile photojeckziel cortes's profile photoAlexander Lent's profile photo
7 comments
 
good sharing. thanks Cyril.
Add a comment...

Cyril Mottier

Shared publicly  - 
 
Android App Polishing: Customizing Soft Keyboard Action Button

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. 

A long long time ago, Android 1.6 introduced soft input methods. Soft input methods has many advantages over traditional hardware keyboards. It obviously requires less hardware and may help to build lighter devices. It also allow content-dependent keyboards. For instance, a keyboard may be different when typing a person name, an email address or a pin code.

By default, the Android framework bundles several constants you may use to control the keyboard that will appear. From the code perspective, this can be controlled with the android:inputType[1] XML attributes on TextView. You can also change the "Enter" button to display a text that better match its purpose. This can be done thanks to the android:imeOptions attribute (see [2] for an exhaustive list of all the possible values):

<EditText
    android:id="@+id/password"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:imeOptions="actionDone"
    android:inputType="textPassword" />

While a "Done" button can fit almost all purposes (log in form, sign up form, etc.) it is quite ambiguous and not really satisfying to my mind. At Capitaine Train we wanted the action button to better reflect the actual action it performs. As a consequence, when signing in, we wanted the button to display "Sign in" rather that "Done". Because that's what it does after all!

Android lets you customize the action button thanks to the android:imeActionLabel[3] and android:imeActionId[4] attributes (or their TextView#setActionLabelId(CharSequence, int)[5] Java equivalent). Using these methods basically consists on setting a label to the done button and a unique id used to identify the action. Here is what your XML layout should be look like:

<EditText
    android:id="@+id/password"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:imeActionId="@+id/action_sign_in"
    android:imeActionLabel="@string/sign_in_short"
    android:inputType="textPassword" />

The second part consists on catch all taps on the soft input keyboard action button made with the appropriate action id:

mEditText = (EditText) view.findViewById(R.id.password);
mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
   @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (actionId == R.id.action_sign_in) {
            // Do sign in
            return true;
        }
        return false;
    }
});

#gde   #android  

[0]: https://play.google.com/store/apps/details?id=com.capitainetrain.android
[1]: http://developer.android.com/reference/android/widget/TextView.html#attr_android:inputType
[2]: http://developer.android.com/reference/android/widget/TextView.html#attr_android:imeOptions
[3]: http://developer.android.com/reference/android/widget/TextView.html#attr_android:imeActionLabel
[4]: http://developer.android.com/reference/android/widget/TextView.html#attr_android:imeActionId
[5]: http://developer.android.com/reference/android/widget/TextView.html#setImeActionLabel(java.lang.CharSequence,%20int)
210
106
Ted Chien's profile photoShuhrat Dehkanov's profile photoAmmar Lanui's profile photoBenjamin Weiss's profile photo
30 comments
 
+Andy Barber  also only got it working with the int tweak, else the actionId is always 0.
+Cyril Mottier  any idea?
Add a comment...
 
Browsing the Android source code from Android Studio: an update

A while ago I posted a G+ article about how to browse the Android framework source code directly from Android Studio[0]. With the releases of Android Studio the original post has became a little bit outdated so here is an update. This post has been written based on Android Studio 0.4.5

The SDK Manager lets you download the entire source repository of a particular Android release. While this is extremely useful to browse the source code locally, it can be quite painful to link your code to the Android code.

Thanks to Android Studio, you can bind some source code to a given SDK. In order to do that, simply go to File > Other Settings > Default Project Structure... In the popup, simply go to the SDK section and choose the Android version you want to attach sources to. Go to the "Sourcepath" tab and press the "+" button at the bottom.

You can find the source code in your SDK ("/Application/Android\ Studio.app/sdk/sources" on Mac OS X).

After applying the change you can now simply [Cmd]+click a method, field, etc. to go to the Android source code definition.

[0]: https://plus.google.com/+CyrilMottier/posts/GNcGL6xVth1
132
62
Philip Schiffer's profile photoQuang-Hai PHAN's profile photoFarrukh Najmi's profile photoMartin Sloup's profile photo
21 comments
 
Why my "project structure" popup window has no "SDK" sections? There is only "SDK Location" section. Thanks!
Add a comment...

Cyril Mottier

Shared publicly  - 
 
+Flavien Laurent's deep dive into Spans. Spans have always been there in the framework but only a few developers know how to use them and how great they are. This article is clearly a must read if you don't know Spans or simply want to understand how they work.
 
A new blog post on how to push Spans to the next level.

http://flavienlaurent.com/blog/2014/01/31/spans/

Hope you enjoy this article and my new blog theme (a lot more pleasant to read)

#androiddev  
42
20
Brian Wenger's profile photoSalvador Gómez's profile photo
Add a comment...
 
Using the new Gradle-based Android build system: a new example

A while ago I wrote a long post about the way I was using Gradle to build AVélib[0] & AVélov[1], some personal projects of mine. If you don't remember this post and are interested in the new Gradle-based Android build system, I highly encourage you to have a look at it here: https://plus.google.com/+CyrilMottier/posts/Dk65EACXqsh.

The main purpose of this post at that time has a) to show you the new build system was ready to be used in production in some cases and b) to give you some tips and tricks to overcome some of the issues related to ContentProvider authorities and/or Google Maps API keys when having several flavors/build types.

With the release of the new Gradle plugin 0.7, I've updated my applications and I'd like to show you some of the improvements you can use to make the configuration cleaner and simpler to write. For example, I've finally been able to switch to flavors and I've removed most constants duplication between the Java code, the XML files and the Gradle configuration file.

You can obviously have a look at the new file hierarchy as well as the Gist I've made with all of the relevant parts.

https://gist.github.com/cyrilmottier/8234960

[0]: https://play.google.com/store/apps/details?id=com.cyrilmottier.android.avelib
[1]: https://play.google.com/store/apps/details?id=com.cyrilmottier.android.avelov
107
53
Laurent Michenaud's profile photoWei Xie's profile photoAleksandr Beshkenadze's profile photoQuang-Hai PHAN's profile photo
19 comments
 
Hi +Cyril Mottier, excellent reference, these days I'm using on my projects (java only).
On the other hand, what do you think would be the strategy to follow when you're with hybrid / native projects? Where the parameterization of the application is in the HTML part
Add a comment...
People
Have him in circles
7,602 people
Chansuk Yang's profile photo
Work
Employment
  • Capitaine Train
    Mobile Software Engineer, 2013 - present
  • Prixing
    Lead Mobile Software Engineer, 2012 - 2013
  • Greencopper
    Mobile Software Engineer/Technology Manager, 2010 - 2012
Places
Map of the places this user has livedMap of the places this user has livedMap of the places this user has lived
Currently
Lyon, France
Previously
Paris, France - Vannes, France - Rennes, France - Helsinki, Finland
Story
Tagline
A curious guy always looking for new challenges.
Education
  • INSA de Rennes
    Computer Science, 2006 - 2009
Basic Information
Gender
Male