Profile cover photo
Profile photo
Thomas Bruyelle
173 followers
173 followers
About
Thomas's posts

Post has attachment

Post has shared content
The new version of the Android Gradle plugin, released today, can automatically remove unused resources. The big win here is that it removes unused resources not just from your own code, but more importantly from libraries you are using (e.g. where there are resources included to support features that you are not actually using from your app). Please try it on your own application projects to see what the net gain is (and of course, to verify that it works! Please report any bugs you encounter!)

Automatic resource shrinking is off by default; to enable it, add "shrinkResources true" to your build type. Note that this feature relies on code shrinking first, so it requires minifyEnabled to be true as well:

    android {
        buildTypes {
            release {
                minifyEnabled true
                shrinkResources true
            }
        }
    }

Post has shared content

Post has shared content
That's enough socializing for one day
Photo

Post has shared content
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
Animated Photo

Post has shared content
+Ars Technica +Ron Amadeo  #NailedIt  
"Wear is the first OS to fully make use of the the Notification Access APIs introduced in Android 4.3, and as a result, every notification from every app just works. ... No matter what, you get an app icon, the full notification text, and any buttons the notification has. All of this was made without [the third party app] having to do a thing other than having an Android notification."

#AndroidWear   #watch   #android  

Post has attachment

Post has shared content
#pixelpushing

And then there was another crypto #gotofail bug, this time affecting multiple Linux distributions, and programmers everywhere [citation needed] were all like...
Animated Photo

Post has shared content
Managing and manipulating tasks and stacks in #android  may be tricky sometimes. Here are my slides from our last #gdg  meeting covering various launch modes and intent flags. 


#gde   #techtalk  

Post has shared content
http://polymer-project.org just got a brand new look and some new intro docs to boot. Check it out and let us know what you think? :)

Huge thanks to +Eric Bidelman +Rob Dodson +Alex Komoroske and everyone else that made this possible.
Photo
Wait while more posts are being loaded