Build in different “flavors” for your app

Here’s a short, yet useful, post today. How can you have different “flavors”? For example, how can you release both a free and paid version of your app? It’s actually simple.

 

Add The Base Plugin

In both your project level and app level build.gradle files, add this line:

apply plugin:’base’

This plugin allows gradle to compile two versions of your app.

 

Declare Your Flavors

productFlavors {
free {
applicationId “com.podraza.android.gaogao.gaogao.free”
}
paid {
applicationId “com.podraza.android.gaogao.gaogao.paid”
}
}

Once your flavors are declared you can switch between them by clicking on the Build Variants tab on the left-hand side of Android studio.

 

Create Different Files For Each Flavor

Identify any file that needs to be different. Left click on the app’s base package and create a new version of that file. Now you’ll be able to select the flavor from the source set options.

For example, if I wanted to create a paid version of the MainActivity layout file, I would left click the base package. Then, choose a new android resource file. I would name the file the same name as in the free flavor and choose “paid” from the available source sets.

All done!

 

 

 

Creating a Bar Code Scanning App

Apps that use barcode scanners are really useful. It’s difficult to physically type in all the numbers of a UPC code (inevitably, I miss one).

And, with all the free cloud databases available it’s super easy to pull the info you need after scanning the barcode.

I created a simple app that uses a barcode scanner to grab the EAN of a book, connects with the Google books API, and pulls the data for that book from the API.

Here’s how it works:

First of all, while we could create a barcode scanner from scratch, it’s difficult. Also, pointless, because there are a few good (and free) barcode scanning libraries for Android that we can just include in our app. Why reinvent the wheel?

So, I used zxing.

Here are my app level build.gradle dependencies:

barcode-dependencies.jpg

(At the time of development, 1.8.2 was the latest release. Please review the github account for more recent releases).

Once zxing is declared as a dependency we’ll be able to use the barcode scanner in our app. Zxing provides support for UPC-A, UPC-E, EAN-8 and EAN-13 codes. We will be using EAN-13 codes.

Moving on. Our use case is that our user wants to add a book to their app’s book library by scanning a barcode. Here is the interface design:

Screenshot_20160204-123202.png

Here is the “Add a Book” screen (or activity). Pressing the “SCAN” button launches this screen:

Screenshot_20160204-125109.png

Once the UPC is captured, it is returned to the launching activity:

Screenshot_20160204-125116.png

Let’s walk through the code!

First of all, we have to find the scan button from the layout and assign it some functionality, which is what we are doing here in the onCreateView method of the AddBook activity:

launch_barcode_activity.jpg

(While this works for our purposes a release app should really save a reference to the scan button into an easily accessible data structure rather than access rootView every time onCreateView is called.)

The code is straightforward. We have to check if there is internet to avoid errors and crashing :-(. Then we launch the CameraActivity for a result (which calls back to an onActivityResult method in this class).

Here we are in the CameraActivity:

CameraActivity_onCreate.jpg

The first thing we need to do is implement the ZXingScannerView.ResultHandler interface (Android studio will complain if you make the declaration and don’t write a handleResult method).

Then, we declare a ZXingScannerView, mScannerView, which will allow us to capture the EAN with the camera.

In onCreate we initialize mScannerView by passing in the CameraActivity as the ResultHandler parameter (the “this”). And, we implement the necessary functionality of createViewFinderView by simply returning our own CustomViewFinderView.

Finally, we call setContentView with the mScannerView we just initialized. Now the barcode scanner will be working!

Here is our custom view class:

CustomViewFinderView.jpg

The details aren’t particularly interesting; it draws the view finder on top of the camera view.

Once the mScannerView has captured the EAN, it has to handle the result- hence the reason why we had to implement ResultHandler. Here is the ResultHandler method in our CameraActivity:

handleResult.jpg

We initialize a new intent (finishIntent) and put the resulting EAN into it (the call to putExtra). By calling setResult() and then finish(), we are returning the finishIntent to the calling activity (AddBook). Finally, our scanned EAN will be available to the AddBook activity. But, we’re not done yet!

We need to do something with the returned EAN… If you look at the user interface above, all we need to do is fill the search text box with the EAN. Here’s how we do that back in AddBook:

onActivityResult.jpg

The CameraActivity returns the intent to AddBook. We need to make sure that the data exists, otherwise the app will crash. Then, we pull the EAN from the intent and store it in the variable scannedEan. Once we get the string from the intent, we call setText() on the global variable “ean” (which refers to the search textbox). Finally, we refresh everything.

And there you have it!

You can see all my code at the github repository here.

Creating an Android Watch Face

Picking up from where we left off last week, today I’m going to walk through how I created a watch face to show data from the Sunshine phone app.

So… DataItems are being sent from the phone using the Wearable DataApi. We need to retrieve those items on the watch.

I accomplished this using a service that is woken by the system when it receives a BIND_LISTENER intent.

The wearable service needs to extend the WearableListenerService class.

Here is my listener service:

SunshineListenerService.jpg

(Enclosing brackets are not shown for brevity.)

This class is pretty straightforward. The onDataChanged method receives data events from the system. Then, we compare the path of the data items received to the expected path (in this case “/sunshine”). If the paths are equal (deep equals, of course), we pull out the data items, repackage them into an intent, and send out a broadcast. I used a broadcast because there is both a watch face and a wearable app that expect this data (broadcast receivers would make the data accessible to both with one broadcast from this class). We also need to declare this service in the Android manifest file as well as that it receives BIND_LISTENER intents. Here is the code that does this from the manifest:

<service
    android:name=".SunshineService"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
    </intent-filter>
</service>

The watch face class is really interesting. It doesn’t use xml to define layouts the way a standard Android app does. It draws the elements directly to the screen (this allows for rapid refreshing). A lot of interesting stuff happens in this class, so let’s dive in!

First of all, I used the Android Studio create watch face wizard to create a digital watch face. We are provided with a watch face that, starting off, draws the time to the screen in the onDraw method.

We need this class to:

-register a broadcast receiver to handle the data the service is broadcasting

-draw the data to the screen

-account for both square and round watch faces (I won’t go into detail about this right now).

We only need to create the broadcast receiver once. Therefore, we initialize it in the onCreate method. Here is the code snippet:

initializing_broadcast_receiver.jpg

mMessageReceiver is declared globally and initialized here, as are mHigh, mLow and mWeatherId. The extra parameter in the getDoubleExtra method is a default value in the event the expected data items are null. mReceivedBroadcast tracks whether or not the data has been received. Simple enough!

Now that we have the data we have to draw it to the screen. The aptly named onDraw method is the best place to handle this. Here is the code snippet:

drawdata.jpg

We need to check if a broadcast was received, which we do so using the mReceivedBroadcast boolean initialized earlier. If a broadcast was received then we can draw the data items to the screen. First, we get the picture associated with the mWeatherId (a very straightforward process, not interesting enough to write about here). Then, we can draw that picture to the screen using X and Y values delineating where on the watch face the picture should be located. Next, we draw a very simple string consisting of the high and low temperatures to the screen. Finally, we draw the time.

In the event that mReceivedBroadcast was false we display a simple message saying “No Data”, which prompts the user to connect their watch to their phone.

Here is the final product:

sunshinewatchface.jpg

The layout would need some refining if this were a production quality app. But, the functionality is there!

Here is the github repo.

Let me know if you have any questions!

 

 

Android Wearable Watch Apps and Faces

The Android Wear APIs are pretty damn cool. That said, I’m still struggling with the usefulness of spending money for a watch with less functionality than a phone… When your phone is in your pocket and your watch is on your wrist. What’s the point???

In all seriousness- Google is usually ahead of the curve when it comes to software trends. The coming internet of things revolution is most certainly going to make operating systems on watches, TVs, cars, refrigerators, dogs, cats etc etc ubiquitous. Udacity has an entire course section dedicated to ubiquitous computing (full disclosure: I’m taking the Android nanodegree program). As programmers we need to stay ahead of the waves so our skills remain in demand. Learning how to use the wearable APIs is one example of doing just that.

This post will kick off a series of blog posts demonstrating how to create both a wearable app and a watch face that receive and display data from an app running on your phone. It’s damn cool (even though I’m still questioning the current usefulness).

Let’s get started!

My top-level build.gradle looks like this:

top-level-gradle

I am using an app that I developed previously with the Udacity nanodegree program. Here is the app’s build.gradle:

sunshine-gradle.jpg

Also, here is the github repository for the app (named “Sunshine”):

https://github.com/udacity/Advanced_Android_Development/tree/7.05_Pretty_Wallpaper_Time

What we want to develop is both a watch face and a wearable app that updates with the latest weather info, (highs, lows and a weather dependent image) pulled by the app running on the phone.

In order to do this we need to use the wearable data layer API.

It is simple to set up. Here’s how I did it.

The Sunshine app uses a bunch of advanced back-end android classes to ensure that everything runs smoothly, including loaders, a content provider and a sync adapter. For our purposes I decided to use the sync adapter to shuttle the needed data off to the wearable.

In the onPerformSync method of the SunshineSyncAdapter, I included this code:

initialize-api-client.jpg

This code initializes a class level field with an anonymous callback class. The methods of the callback just log messages so that we can debug any problems.

send-weather-function.jpg

Here is the meat of creating a data object. It’s straightforward (thank you Google). We get an instance of a PutDataMapRequest and give it a path name (“/sunshine”). Each of the necessary data items get “put” into the map. Then, we have to create a request from the map.

We call the Wearable data api with our previously created GoogleApiClient and our newly created request. Usefully, callback methods are provided, but here we’re just logging messages for debug purposes.

Finally, we have to call sendWeatherInfo with our data. This presented an interesting engineering problem because we only want to update the data on the wearable with the current day’s information AND we only want to update when the phone pulls the data. After some thinking I decided the best place to do this was from inside the notifyWeather() function. Notify weather pushes a notification on the phone (so it’s both showing the current day’s weather and only pushing it out once).

So, I call sendWeatherInfo() from inside the notifyWeather() method with the same parameters that notifyWeather() is using to send push notifications. Voila! Our wearable is receiving data.

This is how to implement this functionality on the phone side. I’ll cover implementing on the receiver side in later posts.

Let me know if you have any questions!