Build It Bigger - 2/2

Add free and paid product flavors (commit)

Create two productFlavors:

app/build.gradle

Ads are only for the free version. Replace this:

app/build.gradle

by this:

app/build.gradle

Create a specific AndroidManifest for free productFlavor. Copy-Paste:

Source: app/src/main/AndroidManifest.xml

Target: app/src/free/AndroidManifest.xml


Create a specific MainActivityFragment.java for free productFlavor. Move:

From: app/src/main/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

To: app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java


Create a specific fragment_main.xml for free productFlavor. Move:

From: app/src/main/res/layout/fragment_main.xml

To: app/src/free/res/layout/fragment_main.xml


The paid productFlavor don’t have AndroidManifest. In this case, it will inherit the main AndroidManifest. We need to remove ads elements on the main AndroidManifest.

Delete this:

app/src/main/AndroidManifest.xml

And delete this:

app/src/main/AndroidManifest.xml

Create a specific MainActivityFragment.java for paid productFlavor:

app/src/paid/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

Create a specific fragment_main.xml for paid productFlavor without Ads:

app/src/paid/res/layout/fragment_main.xml

Fix bug “Not enough space to show ad” (commit)

This bug (“Not enough space to show ad”)[http://stackoverflow.com/questions/21848532/not-enough-space-to-show-ad-admob] is caused by the left and right padding of RelativeLayout, which is consuming space required by the AdView.

We add one more relative layout, and we move in padding constraints to allow the display of ads:

app/src/free/res/layout/fragment_main.xml

Refactoring and add a callback for EndpointsAsyncTask (commit)

Now, we meet the minimal requirements of Udacity project. Does that mean we stop here? Continue with optional features.

At this point, I commit some fix after a lint check. Nothing special to say. To see the (commit).

For the next steps, we need to control what is happening before and after the call to the EndpointAsyncTask. To do this refactorization, we need to put all the logic in MainActivityFragment:

  • OnClickListener for the button, to add some steps before the call to the EndpointAsyncTask
  • OnTaskCompleted interface to have a callback when the joke is loaded, to add some steps before display the joke

Delete the part of launching joke in the main activity:

app/src/main/java/com/udacity/gradle/builditbigger/MainActivity.java

Add an id in fragment.xml for free and paid flavors:

app/src/free/res/layout/fragment_main.xml
app/src/paid/res/layout/fragment_main.xml

And delete the call of launching joke method for free and paid flavors:

app/src/free/res/layout/fragment_main.xml
app/src/paid/res/layout/fragment_main.xml

Create an interface:

app/src/main/java/com/udacity/gradle/builditbigger/OnTaskCompleted.java

Implement this interface in MainActivityFragment for free and paid flavors:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java
app/src/paid/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

Add the listener for the button for free and paid flavors:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java
app/src/paid/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

And the method who call EndpointAsyncTask for free and paid flavors:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java
app/src/paid/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

Modify the constructor of EndpointAsyncTask:

app/src/main/java/com/udacity/gradle/builditbigger/EndpointsAsyncTask.java

And modify the onPostExcute:

app/src/main/java/com/udacity/gradle/builditbigger/EndpointsAsyncTask.java

And finally add the callback method in MainActivityFragment for free and paid flavors:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java
app/src/paid/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

After that, the execution is the same for the user. But now it’s easier to implement next features!

Add Interstitial Ad for free product flavor (commit)

In this step, we request an interstitial ad for free product flavor. When the user click on the button:

  • if the interstitial ad is loaded, then it is displayed
  • else the EndpointsAsyncTask is called

When the interstitial ad is closed, the EndpointsAsyncTask is called.


Instantiate and create a listener:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

Request new interstitial in on create view activity method:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

And the associated method:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

Display the interstitial ad:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

Set AdListener:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

Add a loading indicator while the joke is being retrieved (commit)

When the user click on the button, the EndpointsAsyncTask is called. But the data is not available immediately! We want to display a loading indicator while waiting for the callback of EndpointsAsyncTask.


Define ProgressBar in xml:

app/src/free/res/layout/fragment_main.xml
app/src/paid/res/layout/fragment_main.xml

Initialize the ProgressBar:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java
app/src/paid/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

Set the visibility of ProgressBar visible when calling to EndpointsAsyncTask:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java
app/src/paid/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

Set the visibility of ProgressBar gone when EndpointsAsyncTask call back:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java
app/src/paid/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

Load joke during interstitial ads displaying (commit)

Features are ok, but I’m a little bit frustrated! I click, I see an interstitial Ad, I close it and I need to wait to see the joke. Why the joke is not loaded during the Ad visualization?

We add two variable:

  • mAdsOnScreen is a boolean, to know if interstitial ad is actually displayed on screen
  • mResult is a string, that contains the joke. Null if the joke isn’t loaded

In addition to the method loadData, the method launchActivity is called when:

  • the user click
  • the data is loaded
  • the ads is closed

If the ad is not currently displayed, depending on the load of the joke, we display the progressbar or the joke.


When the Ad is closed, affect a value to mAdsOnScreen and call launchActivity:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

When the button is clicked, affect a value to mAdsOnScreen and call launchActivity:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

When the EndpointsAsyncTask is called, affect a value to mResult:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

When the EndpointsAsyncTask call back, affect a value to mResult and call launchActivity:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

The global logic with the method launchActivity:

app/src/free/java/com/udacity/gradle/builditbigger/MainActivityFragment.java

Gradle test task: launch GCE local dev server, run all tests, shutdown server (commit)

This gradle in a nutshell:

  • runAppEngineAndTest call startAppEngineAndTest, and after execute the task :backend:appengineStop
  • startAppEngineAndTest call :backend:appengineRun, and run backend:appengineRun task in daemon mode, execute the task :app:connectedAndroidTest

If we replace the tasks in the execution order, it gives:

  • :backend:appengineStop: starts the GCE local developer server
  • backend.extensions.appengine.daemon = true: run appengine in daemon mode
  • :app:connectedAndroidTest: run on-device Android tests
  • :backend:appengineStop: stop the GCE local developer server
build.gradle