Android green figure, next to its original packaging

Android: Determine when App is Opened or Closed

The Problem

Inevitably when developing an Android application there will come a time when you need to detect when it comes into the foreground, and when the user leaves.  Surprisingly, there is no easy way to do this! It isn’t hard to detect when the application is first opened, but its not so simple to determine when it is re-opened or closed.

This post will lay out a technique that can be used to detect when an application has been opened, re-opened, or closed.

Lets Get Started

At the core of determining if an application is opened or closed is if any of its activities are currently being displayed. So lets take a very simple example; an application that has exactly one Activity, and does not support landscape mode. All it would take to determine when the application opened or closed would be the Activity’s onStart and onStop methods.

protected void onStart() {
    // The Application has been opened!

protected void onStop() {
    // The Application has been closed!

The problem is this approach quickly breaks down as soon as you add landscape support.  If we rotate the device then this Activity will be re-created and onStart will run a second time resulting in incorrectly detecting the app was opened a second time.

In order to handle device rotation we need to add a validation step. This validation needs to launch a timer whenever the Activity stops in order to detect if we quickly see another Activity in the app start. If we do not, then the user has really exited the app, if we do then we know that the user is still within the app.

This validation also allows supporting an application with multiple Activities. Since transitioning from one Activity to another is handled by this validation as well.

So using this technique I created a manager class that all Activities report to when they become visible and are no longer visible. This manager class handles the validation step for each Activity to avoid accidental detection. It also utilizes a publisher-subscriber (Observer) pattern to allow any interested parties to be notified when the application opens or closes.

To use this manager there are three steps:

1) Add it to your codebase

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.format.DateUtils;

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.Set;

 * This class is responsible for tracking all currently open activities.
 * By doing so this class can detect when the application is in the foreground
 * and when it is running in the background.
public class AppForegroundStateManager {
    private static final String TAG = AppForegroundStateManager.class.getSimpleName();
    private static final int MESSAGE_NOTIFY_LISTENERS = 1;
    public static final long APP_CLOSED_VALIDATION_TIME_IN_MS = 30 * DateUtils.SECOND_IN_MILLIS; // 30 Seconds
    private Reference<Activity> mForegroundActivity;
    private Set<OnAppForegroundStateChangeListener> mListeners = new HashSet<>();
    private AppForegroundState mAppForegroundState = AppForegroundState.NOT_IN_FOREGROUND;
    private NotifyListenersHandler mHandler;

    // Make this class a thread safe singleton
    private static class SingletonHolder {
        public static final AppForegroundStateManager INSTANCE = new AppForegroundStateManager();

    public static AppForegroundStateManager getInstance() {
        return SingletonHolder.INSTANCE;

    private AppForegroundStateManager() {
        // Create the handler on the main thread
        mHandler = new NotifyListenersHandler(Looper.getMainLooper());

    public enum AppForegroundState {

    public interface OnAppForegroundStateChangeListener {
        /** Called when the foreground state of the app changes */
        public void onAppForegroundStateChange(AppForegroundState newState);

    /** An activity should call this when it becomes visible */
    public void onActivityVisible(Activity activity) {
        if (mForegroundActivity != null) mForegroundActivity.clear();
        mForegroundActivity = new WeakReference<>(activity);

    /** An activity should call this when it is no longer visible */
    public void onActivityNotVisible(Activity activity) {
         * The foreground activity may have been replaced with a new foreground activity in our app.
         * So only clear the foregroundActivity if the new activity matches the foreground activity.
        if (mForegroundActivity != null) {
            Activity ref = mForegroundActivity.get();

            if (activity == ref) {
                // This is the activity that is going away, clear the reference
                mForegroundActivity = null;


    /** Use to determine if this app is in the foreground */
    public Boolean isAppInForeground() {
        return mAppForegroundState == AppForegroundState.IN_FOREGROUND;

     * Call to determine the current state, update the tracking global, and notify subscribers if the state has changed.
    private void determineAppForegroundState() {
        /* Get the current state */
        AppForegroundState oldState = mAppForegroundState;

        /* Determine what the new state should be */
        final boolean isInForeground = mForegroundActivity != null && mForegroundActivity.get() != null;
        mAppForegroundState = isInForeground ? AppForegroundState.IN_FOREGROUND : AppForegroundState.NOT_IN_FOREGROUND;

        /* If the new state is different then the old state the notify subscribers of the state change */
        if (mAppForegroundState != oldState) {

     * Add a listener to be notified of app foreground state change events.
     * @param listener
    public void addListener(@NonNull OnAppForegroundStateChangeListener listener) {

     * Remove a listener from being notified of app foreground state change events.
     * @param listener
    public void removeListener(OnAppForegroundStateChangeListener listener) {

    /** Notify all listeners the app foreground state has changed */
    private void notifyListeners(AppForegroundState newState) {
        android.util.Log.i(TAG, "Notifying subscribers that app just entered state: " + newState);

        for (OnAppForegroundStateChangeListener listener : mListeners) {

     * This method will notify subscribes that the foreground state has changed when and if appropriate.
     * <br><br>
     * We do not want to just notify listeners right away when the app enters of leaves the foreground. When changing orientations or opening and
     * closing the app quickly we briefly pass through a NOT_IN_FOREGROUND state that must be ignored. To accomplish this a delayed message will be
     * Sent when we detect a change. We will not notify that a foreground change happened until the delay time has been reached. If a second
     * foreground change is detected during the delay period then the notification will be canceled.
    private void validateThenNotifyListeners() {
        // If the app has any pending notifications then throw out the event as the state change has failed validation
        if (mHandler.hasMessages(MESSAGE_NOTIFY_LISTENERS)) {
            android.util.Log.v(TAG, "Validation Failed: Throwing out app foreground state change notification");
        } else {
            if (mAppForegroundState == AppForegroundState.IN_FOREGROUND) {
                // If the app entered the foreground then notify listeners right away; there is no validation time for this
            } else {
                // We need to validate that the app entered the background. A delay is used to allow for time when the application went into the
                // background but we do not want to consider the app being backgrounded such as for in app purchasing flow and full screen ads.
                mHandler.sendEmptyMessageDelayed(MESSAGE_NOTIFY_LISTENERS, APP_CLOSED_VALIDATION_TIME_IN_MS);

    private class NotifyListenersHandler extends Handler {
        private NotifyListenersHandler(Looper looper) {

        public void handleMessage(Message inputMessage) {
            switch (inputMessage.what) {
                // The decoding is done
                case MESSAGE_NOTIFY_LISTENERS:
                    /* Notify subscribers of the state change */
                    android.util.Log.v(TAG, "App just changed foreground state to: " + mAppForegroundState);

2) Activities Must Notify of Visibility Changes

Have all of your Activities implement the following code to notify the manager when they become visible and when they are no longer visible. This is best achieved by adding this code to your base Activity class.

protected void onStart() {

protected void onStop() {

3) Subscribe to Be Notified of Foreground Changes

Subscribe to be notified of app foreground state changes from somewhere of interest. The application class onCreate method is a prime placement to ensure that you get notified every time the app enters or leaves the foreground.

public class MyApplication extends Application {
    public void onCreate() {

    public void onAppForegroundStateChange(AppForegroundStateManager.AppForegroundState newState) {
        if (AppForegroundStateManager.AppForegroundState.IN_FOREGROUND == newState) {
            // App just entered the foreground. Do something here!
        } else {
            // App just entered the background. Do something here!

Further thought

There are a few details that need further discussion.  These changes may need to be made in order to calibrate this for your particular application.

Validation Time

How long should this validation timer be that is used to detect that your app has really entered the background? In the code above it set to 30 seconds for a few reasons.

There are third party Activities that can appear full screen when the application is running. A few common examples of these are in Google In App Purchasing or Facebook signup. Both of these essentially send the application into the background since none of you applications Activities are in the foreground when those are displaying. It is not desirable for those to count as the user “leaving the app” since they really haven’t. The 30 second timeout helps to catch this case. For example if a user completes an in app purchase in under 30 seconds, which the vast majority of users will, then they will not be counted accidentally as “leaving the app”.

If this situation doesn’t apply to you, then I recommend setting your validation time to around four seconds. That is enough of a safety margin for slow devices to create the next Activity when rotating.

CPU Sleep

A potential issue is there is no guarantee that the CPU will still be running long enough for the background detection to occur if the user locks their phone quickly after exiting the app (or locks the phone with the app still open).  In order to guarantee this always works as expected you would need to take a wake lock until the app closed event can be validated to prevent the CPU from sleeping. In practice however this did not seem to be a big enough issue to warrant use of a wake lock.

Determining How The App Was Launched

Great so now we know how to detect when the application was opened or closed, but we don’t know how the application was opened. Did the user click on a notification? Did they click on a link? Or did they just launch the app from the icon or recents tray?

Tracking Launch Mechanism

First we need somewhere to track how the application was opened. In this code I have added an enum to the application class to track how the application was opened. This builds upon the last example so we can print a log when the application is opened, along with how the application was opened.

public class MyApplication extends Application {
    public final String TAG = MyApplication.class.getSimpleName();

    public enum LaunchMechanism {

    private LaunchMechanism mLaunchMechanism = LaunchMechanism.DIRECT;

    public void setLaunchMechanism(LaunchMechanism launchMechanism) {
        mLaunchMechanism = launchMechanism;

    public void onCreate() {

    public void onAppForegroundStateChange(AppForegroundStateManager.AppForegroundState newState) {
        if (AppForegroundStateManager.AppForegroundState.IN_FOREGROUND.equals(newState)) {
            // App just entered the foreground.
            Log.i(TAG, "App Just Entered the Foreground with launch mechanism of: " + mLaunchMechanism);
        } else {
            // App just entered the background. Set our launch mode back to the default of direct.
            mLaunchMechanism = LaunchMechanism.DIRECT;

Setting the Launch Mechanism

Great so now we can print off the launch mechanism when the app is opened, but we never actually set it! So the next step is to set it when the user opens the app via a link or a notification. If its not set to one of those two, then the user must have opened the app directly.

Tracking Link Clicks

To track the user clicking a link that caused the app to open find the place in your code where you intercept your links and place the following code to track the launch mechanism. Make sure this is called before your Activity’s onStart(). This could be needed in many places or just one common link intercepter depending on your architecture.


Tracking Notifications

Unfortunately tracking notifications is a bit trickier. Notifications are shown and when clicked a PendingIntent that you previously bound to them is opened. The trick here is to add a flag to all PendingIntents that you make for a notification that indicates that this Intent is an Intent from a Notification. In other words, when the intent eventually opens some Activity, we need to be able to detect that this intent was created from a Notification.

So for example when creating any PendingIntent for a notification add the following to each intent:


// Put an extra so we know when an activity launches if it is a from a notification

Now all we need to do is check for that flag in every single Activity (add to your base Activity class). If we detect the flag then we know this Activity was launched via a notification and we can set the launch mechanism to notification. This must be done in onCreate so that it is set prior to the application coming into the foreground (which will trigger the printing of the launch mechanism).

public void onCreate(Bundle savedInstanceState) {

    Intent intent = getIntent();
    if (intent != null && intent.getExtras() != null) {
        // Detect if the activity was launched by the user clicking on a notification
        if (intent.getExtras().getBoolean(EXTRA_HANDLING_NOTIFICATION, false)) {
            // Notify that the activity was opened by the user clicking on a notification.

And there you have it! You can now detect not only when the app is opened or closed, but how it was opened as well.


Do you find this sort of work interesting? Do you love quaint Bucks County Pennsylvania? Are you an amazing Android Developer? Then we would love to hear from you!

Featured image by Dsimic – license via CC BY-SA 3.0

Best Practices for Consuming APIs On Android

First Some History

Up until fairly recently integrating APIs into your Android application had been the wild west. Each application had their own networking and caching implementations that were generally pretty brittle and didn’t handle non optimal networking conditions terribly well.

Thanks largely to Square Inc, the innovative company bringing credit card processing for businesses to mobile phones, there is now a wealth of high quality open source libraries available that support API integration in your Android applications.

What will we learn how to do?

In this post, we will learn how to use a Retrofit, OkHttp and GSON stack in order to be able to simply and robustly integrate a REST API into your application. Using this stack we will download and parse some data from  Following the steps outlined, you will be able to integrate most REST APIs into your application in just a few minutes, without writing any boilerplate code.

Lets Learn About the Stack


Retrofit makes it incredibly easy to download JSON or XML data from a web API and parse it into a Plain Old Java Object (POJO). For example to download a users repo information from Github all the code you need to write is:

List<Repo> listRepos(@Path("user") String user);

Additionally you would need to create the Repo POJO so that the parser knows what type of data you are expecting from that endpoint.  This code can be auto-generated, more on this later.

Its just as easy to provide query parameters or do POST or HEAD requests. For instructions for how to connect with different types of APIs just see the documentation.

One of the nice features of Retrofit is the ability to add additional logic to all requests and responses. You could for instance add additional data to all request HTTP headers or intercept any unauthorized response error codes and redirect the user to your login screen.


OkHttp is an HTTP client for Android applications. It is efficient by default and includes support for SPDY, connection pooling, GZIP, and a HTTP response cache.

In addition OkHttp handles common networking issues automatically and silently such as retries and SSL handshake issues. Retrofit will use OkHttp automatically as its networking layer if it is present in your application.


GSON is a Java library that is used to parse JSON data into a POJO. It can also be used to convert a POJO into JSON, which in Android can be helpful as a way to store generic objects into shared preferences.

To use GSON you essentially just need to create a representative POJO of the data you wish to parse and run GSON on the data to parse it into an instance of the POJO. Its dead simple and makes parsing a breeze. To learn how to create your POJOs compatible with GSON see the documentation. Retrofit uses GSON in order to do its JSON parsing.

Lets do Some Coding!

Add the libraries to your project

  1. Download the jar files for Retrofit, OkHttp, and GSON.
  2. Drag each of the jar files into your libs folder in your project
  3. If using Android Studio Sync the project with gradle

Find or write an API

You probably already have an API in mind but if you are looking for a directory of APIs I recommend ProgrammableWeb. For the purposes of this tutorial we are going to be parsing a list of streams available from To see the request format see their API documentation. The basic API request to get the list of steams from in JSON format is:

Capture Some Sample Output

In order to proceed we need some sample data that is returned from the API. In this case since it is a GET request we can just run the request in a web browser, and copy out the response such as:

[{“broadcast_part”: 4, “featured”: true, “channel_subscription”: true, “audio_codec”: “uncompressed”, “id”: “6640712464”, “category”: “gaming”, “title”: “Fnatic xPeke, Normals(ranked down) on smurf”, “geo”: “DE”, “video_height”: 1080, “site_count”: 8014, “embed_enabled”: true, “channel”: {“subcategory”: null, “producer”: true, “image_url_huge”: “×600.jpeg”, “timezone”: “Europe/Madrid”, “screen_cap_url_huge”: “http://static

Generate the POJOs for your data

Now for the fun part, using the sample data we just captured we are going to auto generate the POJOs that represent that data. Use jsonschema2pojo and be sure to enter in your desired package name, class name, JSON as the type, and use primitive types. For this example the generator got confused because the root of the JSON is an array and not an object; so I only pasted in the first element of the array. Some fiddling may be necessary.


Integrate the Generated POJOs Into Your Code

With the POJOs generated now we can just paste those generated classes into our project. In my sample project they are in the models package.

Use Retrofit to Download/Parse the API

Create a Rest Adapter

Creating the adapter is as simple as setting the endpoint:

RestAdapter restAdapter = new RestAdapter.Builder()

Define the APIs interfaces

Define the interface for each endpoint you are going to connect with. In this case we are connecting to the steams endpoint with the limit and offset parameters which are used for paging the data. These are specified in the Justin.Tv API documentation.

public interface TwitchTvApiInterface {
    void getStreams(@Query("limit") int limit, @Query("offset") int offset, Callback<List<JustinTvStreamData>> callback);

You will notice we are expecting back a response from the endpoint that is a List of JustinTvStreamData objects, which is the POJO we auto-generated earlier. For more information on how to define this interface see the Retrofit documentation.

Create the Twitch.Tv Service

Now that we have the endpoint established and the interface defined we need to make the Twitch.Tv service that allows making requests.

TwitchTvApiInterface twitchTvService = restAdapter.create(TwitchTvApiInterface.class);

Hit the API

Making the API request is equally simple.  We just need to use the service we just created.

twitchTvService.getStreams(ITEMS_PER_PAGE, pageNumber * ITEMS_PER_PAGE, new Callback<List<JustinTvStreamData>>() {
    public void success(List<JustinTvStreamData> justinTvStreamData, Response response) {

    public void failure(RetrofitError retrofitError) {

What is interesting here in the fact that Retrofit will download and parse the API data on a background thread, and then deliver the results back to the UI thread via the success or failure method. Retrofit also supports just downloading on whatever thread it is called on (not shown here).

Do Something Interesting With the Data

Now that the data is in a POJO do something interesting with it!
For this demo project I display the Twitch.Tv channel image and description and used the Picasso Library to download and cache the images.



Open Source Sample Project


Do you find this sort of work interesting? Do you love quaint Bucks County Pennsylvania? Are you an amazing Android Developer? Then we would love to hear from you!

Android Tricks and Tips: Storing a POJO Into Shared Preferences

Often you will yourself with the need for storing some simple persistent data in your Android application. Maybe you are tracking the last time you showed a user an upsell dialog? Perhaps you want to know if this is the first time onto a screen so you can show some new user experience flow.

Shared Preferences to the rescue! Sweet! All I need to do is store my Plain Old Java Object into a shared preference key and we are all set. So you open up the interface document for the Shared Preference editor class to see which method to call.

SharedPreferences Editor Interface

Wait a minute? I only see interfaces for basic Java types? No support for Parcelable or Serializable? Looks like there is no way to just store a POJO into Shared Preferences. Or is there…

GSON to the rescue! GSON is a beautiful Java utility library that allows converting to and from JSON and POJOs.

Saving to the Shared Preference

  1. Integrate the GSON library into your project. (Just download the jar and drag it into your libs folder)
  2. Create the POJO
  3. Serialize the POJO into a JSON String using GSON
  4. Save the serialized POJO into your shared preference

Restoring from the Shared Preference

  1. Read the shared preference value into a string
  2. Using GSON convert the serialized string back into your POJO

Time for Some Code!

First lets take a look at our class that we want to save and restore from a Shared Preference. What is important to notice is we have encapsulated the serialization and deserialization into the class.

public class MyData {
    private String mString1;

    private Long mLong1;

    private Double mDouble1;

    public MyData(String string1, Long long1, Double double1) {
        mString1 = string1;
        mLong1 = long1;
        mDouble1 = double1;

    public String serialize() {
        // Serialize this class into a JSON string using GSON
        Gson gson = new Gson();
        return gson.toJson(this);

    static public MyData create(String serializedData) {
        // Use GSON to instantiate this class using the JSON representation of the state
        Gson gson = new Gson();
        return gson.fromJson(serializedData, MyData.class);

Now lets take a look at the code to store and retrieve the POJO from the Shared Preference.

String PREFS_NAME = "MyPrefName";
String PREFS_KEY = "MyPrefKey";

// Create our data object
MyData myData = new MyData("thing1", 5L, 2D);

// Serialize the object into a string
String serializedData = myData.serialize();

// Save the serialized data into a shared preference
SharedPreferences preferencesReader = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferencesReader.edit();
editor.putString(PREFS_KEY, serializedData);

// Read the shared preference value
String serializedDataFromPreference = preferencesReader.getString(PREFS_KEY, null);

// Create a new object from the serialized data with the same state
MyData restoredMyData = MyData.create(serializedDataFromPreference);


Do you find this sort of work interesting? Do you love quaint Bucks County Pennsylvania? Are you an amazing Android Developer? Then we would love to hear from you!

A Tale of Migrating From Eclipse to Android Studio

I have recently done the unthinkable and taken the plunge into full time use of Android Studio over Eclipse for my Android development. This was not willingly mind you, but as a necessity since the project I was to work on was using Android Studio along with its Gradle build system.

After several months of using Android Studio as my full time IDE I have just one thing to say:

I will never go back to Eclipse

Through the years Eclipse has treated me fairly well and is a robust IDE that I have become quite expert at, but anyone that has used it for any length of time for Android development is aware of some of its shortcomings:

  • It has a tendency to get slower and crash more often with each successive release
  • In order for it to run for more than a few hours you need to edit the config files to give it massive amounts of RAM
  • It tends to run out of memory and crash when you are trying to export an APK
  • It requires a massive amount of CPU power to use it without getting a please wait beach ball every few seconds. I built a quad core 4.5 GHz machine just to make it usable as my daily driver.
  • Theme support is fairly mediocre, there are plugins to add support however none of them theme anything but the code window.
  • Creating UI for Android is extremely clunky
  • Anytime you touch a file outside of Eclipse you need to tell it to refresh itself. Anyone that works on multiple code branches every day will quickly realize it is very easy to forget to do this.
  • There is a mysterious need to constantly “clean” the project. Changed a file not using the editor? Better refresh then clean. Modified just an XML file but not any code files? Better clean or that XML modification probably won’t make it in the build, or worse yet the string values will all offset by one from what they should be.

Welcome our new robot overlords

Android Studio is a welcome change that addresses many of this laundry list of issues in Eclipse and installation is as simple as downloading and dragging it to your applications folder. The first thing you will notice is you can now theme the entire program and it looks beautiful!

Android Studio

Some key improvements

  • Full theming takes away much of the eye strain I was getting with Eclipse
  • Very stable and does not leak memory forcing constant reboots
  • The UI creation tools are vastly improved
  • No refreshing! The editor automatically updates itself whenever files are changed outside of the editor. No need to refresh every time I change branches.
  • There is no need to constantly clean my projects!
  • Command clicking on Android related items actually works. For instance command click on an android id and it opens the XML file it is defined in.


Android Studio has multiple builds in the wild including canary, dev, and beta. I do not recommend running the canary build as it tends to be quite buggy. I recommend running the dev build. After running the dev builds for over four months now I can say that it is a much more stabile development environment than Eclipse. Performance is good and I have never had to close and reopen the program because it was slowing leaking more and more memory and getting slower and slower.

For the Eclipse Convert

An incredible feature is the ability to set your hotkeys to the same that are used in Eclipse. For myself, the main reason I had held out was an intense fear of having to relearn all of the hotkeys I use daily.

UI Creation is Better

Creating UI in Eclipse is painful; not only do you have to constantly toggle between the XML tab and the rendering tab to check your work, but you have to do it twice every time because of a bug where the first time it doesn’t always render correctly. Android Studio UI In Android Studio you can actually see the UI rendered as you type the XML. Not only that, but you can click on the fields in the rendering and jump right to the XML. Additionally there is support for design time attributes which allows you to add things like text in each of your TextViews to aid in designing your XML. No longer do you have to design everything with canned data so its not invisible only to have to delete it before you actually commit your code.

Gradle Gradle Gradle

The biggest hurdle to overcome with your transition to Android Studio is that is uses a different build environment in Gradle. While there is absolutely a learning curve here most of the common questions have already been answered on StackOverflow. In addition Eclipse has a new option to aid in migrating from Eclipse to Gradle and migration is generally pretty straightforward.

The first time you try to add a library project or jar file you will need to relearn the process, but once you have it really is pretty trivial. One drawback is many open source libraries do not have Gradle support yet so you will need to use Eclipse to export and add Gradle support. While you are at it why not upload them back to the source repo? Its a great way to move things forward and get some easy Github cred.

Gradle has some real advantages over what you are used to in Eclipse:

  • The build process is scripted, meaning you can add useful dynamic features to it
  • Adding a GUI toggle for build variants is pretty easy. Want an internal build and a store build? An Amazon and Google build?
  • You can export APKs with the version number in the filename
  • You can run a script when your APK is created; for instance to automatically upload the APK to TestFlight for internal testing


Do you find this sort of work interesting? Do you love quaint Bucks County Pennsylvania? Are you an amazing Android Developer? Then we would love to hear from you!

An Easy to Use Android App Rating Library

After recently releasing some new Android apps I found myself in that same place again; how can I get people to leave  app reviews? In my experience reviews need to be solicited, as emotions towards your app are not always strong enough for a user to go out of their way to leave a review.

Step number one, lets look for good open source solutions to this problem. In comes an App Rate Library which I have used in the past. App Rate allows your users to rate your application and encapsulates that knowledge into a library for easy use.

Some of its key features are:

  • Configure when to prompt for a rating such as after 5 app launches and 3 days from the first launch of the app
  • Customize all the button and dialog text
  • Attach listeners on all dialog button clicks to allow running code when the user interacts with the dialog




They like us, they really like us!

This is all great, but its missing some key features that I really needed for my project. First, its pretty common now to see an initial popup that asks if you like the app or not; and if you do not then don’t ask the user to rate the app. So I forked the library and added (optional) support for this. If the user likes the app then they are directed to the existing rate the app dialog; if not then they are now prompted to leave feedback for the app.


Drop Us A Line

If the user would like they can now leave us some feedback by sending an email with whats on their mind. This can be helpful both to let users vent without having to do it via our rating, as well as get ideas for ways to make the app better. And of course everything on this dialog and in the email can easily be customized.




Email Screenshot

We Love Developers!

The feedback email that is crafted also adds useful information like OS version, app version and the user’s phone type.







Great so how do I get it?

The fork of the library can be found right here.


Do you find this sort of work interesting? Do you love quaint Bucks County Pennsylvania? Are you an amazing Android Developer? Then we would love to hear from you!