Monday, 15 June 2015

Android + Gradle: Build different APKs with different dependencies

Introduction
Recently, I switched my projects, to Android Studio.
Two years ago when Google announced the new IDE, I was skeptic: android studio was buggy and gradle a new complicated tool to learn.
Today I'm an happy user of android studio.

In this tutorial, I will talk about my experience with gradle and some useful customization I made on the build process of my app, called Qoffee.

The problem
Qoffee is available on Play Store and Amazon App Store and allows users to find the best coffee in town.
One of the last features I added, it was the support for Android Wear: now it is possible to search coffees from the smartwatch!

With the new features:
- the new apk is passed from 1.2 mb to 3.9 mb
- the new apk contains also the apk to install into the smartwatch
- there is a new Service, precisely a WearableListenerService. This service is the one that talks with the watch.

New classes/features were not useful on the apk for other app store (eg. amazon).
In the new solution, it is now possible to automatically build 2 separate apk:
- one for play store: with all the features (size: 3.9 mb)
- one for other store: without android wear and google play services support (size: 1.2 mb)

Remove unused files: Separate the Code and merge manifests
I searched a way to create 2 different builds for my app, in order to create a custom Manifest and to remove the WearableListenerService from the non-play store apk.
In the src folder of my project on android studio I created 2 new “Java Folder”:
- playstore
- genericstore

Create a new Java Folder


New project tree


The original folder for my project was called “main”.
I created 2 other AndroidManifest.xml files, and placed them in the new folder playstore and genericstore like this:
- AndroidManifest.xml in main folder contains common data for both apk: eg. all the common activities
- AndroidManifest.xml in playstore folder contains only informations specific to the play store apk: eg. reference to the WearableServices class, keys for playstore services
- AndroidManifest.xml in genericstore folder contains information for non-playstore apk: mainly, empty

See the differences in the following image:

Differences between Manifest

After this operation I created two product flavors in the gradle file of my app like this:

android {
     compileSdkVersion 20
     buildToolsVersion '20.0.0'
     productFlavors {
          playstore{
               applicationId "com.andrea.degaetano.coffelover.playstore"
          }
          genericstore{
               applicationId "com.andrea.degaetano.coffelover.genericstore"
          }
     }
… … (other unchanged configurations here..)
}

The new build.gradle file generated 4 new “Build Variants” in Android Studio.
This new menu allows the developer to select which kind of build generate:

All my modules.. and the selected variant
you can change the selected variant on any module

At this point, if you try to export the apks, the genericstore apk fails, because the android wear apk is present in the genericstore apk and the package of the genericstore is different from the one in the android wear apk.
Not only, but the genericstore apk is always 3.9mb.

In order to remove the dependency from android wear in the generic apk, I have changed the dependencies of my application from:

dependencies {
     compile project(':parseLoginUI')
     compile 'com.android.support:support-v4:20.0.0'
     compile 'com.google.android.gms:play-services-wearable:7.5.0'
     compile 'com.android.support:appcompat-v7:20.0.0'
     compile files('libs/android-async-http-1.4.6.jar')
     WearApp project(':qoffeewear')
}

to

dependencies {
     compile project(':parseLoginUI')
     compile 'com.android.support:support-v4:20.0.0'
     playstoreCompile 'com.google.android.gms:play-services-wearable:7.5.0'
     compile 'com.android.support:appcompat-v7:20.0.0'
     compile files('libs/android-async-http-1.4.6.jar')
     playstoreWearApp project(':qoffeewear')
}

Important: The package of the android wear app is the same of the playstore variant: com.andrea.degaetano.coffelover.playstore

Thursday, 28 May 2015

Friday, 15 May 2015

Adding USB to Ethernet to Arietta

Introduction
Arietta is a low cost linux embedded module: http://www.acmesystems.it/arietta I already talked about it, here:
This post talks about adding a usb to ethernet adaptor for arietta.
The adapter is based on asix hardware, you can find it in various shapes:


Modding the Kernel
My build enviroment is based on a debian linux, created with vagrant.
There is this very good tutorial on acmesystem website: http://www.acmesystems.it/compile_linux_3_16 on how to compile a new kernel for the board.
Instead of following the tutorial untill the end, when you reach "make ARCH=arm menuconfig"you have to enable the "Multi-purpose USB Networking Framework" and select the appropriate ethernet adapter:


You can find the section under Device Drivers / Network device support / USB Network Adapters.
After you have rebooted with the new kernel you can plug the adapter and see if the device is recognized typing "dmesg".

My ethernet device is recognized as "eth0", in order to configure it with dhcp you have to edit /etc/network/interfaces on arietta and insert these lines at the end:

auto eth0
iface eth0 inet dhcp
 
Plug the ethernet cable, reboot the board and... done!







Friday, 10 April 2015

Parse and Android: my slide for DroidconIT 2015

Yesterday, I had a talk about Android and Parse, in Turin.
The talk was inside a barcamp session.
The slide are here:



More articles on parse.com and android will be available on the blog in the next months :)

Thursday, 2 April 2015

Number / Money Picker Dialog in Android

I needed to create a money picker dialog for one of my apps called Qoffee.
This money picker is used to signal the price of a coffee in a bar.
Here is the dialog:


To build this dialog I created an AlertDialog with a Custom Layout.
First of all you need to define the layout with a classic xml layout file:


< LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"  >
    < TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:padding="10dp"
        android:textSize="16sp"
        android:text="@string/bar_change_price"/>

    < LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center">
       
    < NumberPicker
        android:id="@+id/euro_picker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />
   
     < TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:padding="5dp"
        android:textSize="20sp"
        android:text="@string/point_symbol"/>
   
    < NumberPicker
        android:id="@+id/cent_picker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />
     < TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:padding="5dp"
        android:textSize="20sp"
        android:text="@string/euro_symbol"/>
   
    </ LinearLayout>
</ LinearLayout>

In my case this is made by:
  • 1 textview for main dialog description
  • 2 number pickers: 1 for euro and 1 for cents
  • other descriptive textview: for euro and point symbols

If you pay attention, you see I didn't defined any buttons.
The bottom buttons are defined as part of the AlertDialog: you don't have to define it in the layout.

The code to show this dialog follows:

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();

View theView = inflater.inflate(R.layout.number_picker_dialog, null);
//I define the dialog and I load the xml layout: number_picker_dialog.xml into the view

final NumberPicker unit_euro = (NumberPicker) theView.findViewById(R.id.euro_picker);
final NumberPicker cent = (NumberPicker) theView.findViewById(R.id.cent_picker);

// I keep a reference to the 2 picker, in order to read their properties for later use
                  
builder.setView(theView)
.setPositiveButton(R.string.accept_price_change,new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
            Log.d("DBG","Price is: "+unit_euro.getValue() + "."+cent.getValue());
    }
}).setNegativeButton(R.string.reject_price_change, new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
                      
    }
});

// I define 2 default buttons, with 2 strings (accept_price_change and reject_price_change) and their behaviours

unit_euro.setMinValue(0);
unit_euro.setMaxValue(3);

// I define the range for the first numberpicker.

String cents[] = new String[20];
for(int i = 0;i < 100; i+=5) {
    if( i < 10 )

       cents[i/5] = "0"+i;
    else
        cents[i/5] = ""+i;
}

cent.setDisplayedValues(cents);
//I create the range of the possible values displayed in the second numberpicker.

cent.setMinValue(0);
cent.setMaxValue(19);
cent.setValue(0);          
   
//I configure the possible values of the second picker

builder.show();

//Finally, the alert is showed!

Wednesday, 25 February 2015

Security Webcam: (Improve) Uploading Photo to Dropbox with a Linux Board


Recently I bought a used webcam Microsoft Lifecam HD3000 on ebay.
I was interested in this device because it is Linux compatible and it can be used with one of my linux boards: Arduino Yun.



I was interested to use the Webcam, the Yun and a Pir Sensor to make a rudimental security camera system for my home.

If you are interested in this type of activity, you can find a lot of material, just "googling" (and of course you can use another linux board, like a raspberry pi):
What I didn't like from these projects is the way they execute actions from the arduino side.

The components of my finished project are very similar to the first link from adafruit.com: a webcam, a pir sensor and the arduino yun.

The events on the Yun, Arduino side
The example that I've found works like this:
  1. wait for move event (eg. from pir sensor)
  2. use Process and call fswebcam to get a photo from the webcam
  3. use Process and call a python script to upload a photo on dropbox
  4. ... do something ...
  5. go back to 1.
Everytime in a yun's sketch you will use Process, you are blocking the execution of the arduino part until the command is completed.
As long as the step 3 is completed, it is impossible to capture another photo.
Some samples use Temboo for dropbox, but I don't like it: it makes the sketch more complicated to mantain and the Dropbox Api is easy to use.
Since I didn't want to wait the 3rd step or use Temboo api on my system, I have wrote some code.

My solution: Arduino part
In my solution the arduino part work like this:
  1. wait for move event (From pir sensor)
  2. use Process and call fswebcam to get a photo from the webcam saving it, in a temporary directory
  3. use Process to move the photo to a destination directory where will be picked by the linux part
  4. go back to 1
The step number 3 is needed to be sure that the photo is totally written before the upload on dropbox.
Now, I have again 2 call to Process... but move a photo of less than 100 kbyte from a directory to another is faster than uploading the same photo to dropbox.
The arduino side, it is indipendent from the dropbox upload: this is a job for the linux side.
(if you want the arduino's sketch, just ask in the comments).

Linino part
I wrote a python script upload_to_dropbox.py in /root, that is able to continually check the photos's destination directory and when it finds one new, it uploads it on my dropbox account and on a succesfull upload, it deletes the local photo from the yun.
For setup of python and dropbox library on arduino yun I have followed this tutorial.
What I have changed from it, it is the sketch and the python script.

The python script is here, just edit it with your generated dropbox key.

 import dropbox  
 import glob   
 import os  
 import json  
 from time import sleep  
 photodir = '/mnt/sda1/arduino/www/';  
 client = dropbox.client.DropboxClient('DropBoxGeneratedKeyGoHere')  
 #starting main loop here  
 while(1):  
      toupload = glob.glob(photodir+'*.jpg');  
      try:  
           for fname in toupload:  
                print "Uploading... " + fname;  
                f = open(fname, 'rb');  
                response = client.put_file(fname[len(photodir):], f);  
                print "uploaded" + fname[len(photodir):];  
                print response['bytes'];  
                if(response.has_key("bytes") and response['bytes'] > 0):  
                     os.remove(fname);   
           sleep(0.3);  
      except:  
           sleep(2);  

In order to start the script automatically on each boot of the Yun, you need to edit /etc/rc.local adding:

export PYTHONPATH=/mnt/sda1/python-packages
python /root/upload_to_dropbox.py &





Sunday, 11 January 2015

Extracting data generated in a Facebook Group

Introduction

I do Parkour since august of 2007 and I have also created with other people in town a Facebook Group.
This facebook group is used by practitioners and beginners in order to find other people to train with, make questions,  post photos and links on parkour but also schedule training appointment.
I was curious to know which was the spot/the place, where practitioners have played most activities in the 2014.



Facebook Data: Graph Api Explorer
To dump all the post of facebook of my parkour group, I started with the documentation at developer.facebook.com.
The API is called Graph Api, the documentation at facebook.com is good enough done: https://developers.facebook.com/docs/graph-api/using-graph-api/v2.2

One of the first tools to use to test the facebook API is Graph Api Explorer https://developers.facebook.com/tools/explorer/145634995501895/

Graph API Explorer (GAE) is useful to test facebook api and to generate a valid token for your tests/scripts, just press "Get Access Token" button on the user interface.

The first step with GAE is to generate a valid token for your logged user with the permissions requested for your queries: in my case user_groups is mandatory.
I've tested then some queries:
  • "me" show data of the current logged user
  • "me/friends" show data about the friends of the logged user
  • "me/groups" show data about the groups of the logged user
Graph Api Explorer, the response (cutted) on a user data
The data is returned in JSON format and every returned object: person, comment,  status, group...etc  have an own id.
The "me/groups" is useful to find the group-id of the group to later analysis.
So, simply putting the group-id and pressing then submit, it will show the information of the group; if you need to fetch all the feeds of the group you need to insert "group-id/feed".

Pagination and period of interest
It is not possible to fetch all the posts of a group with one query: results are divided in pages.
Every succesful json response contains a "paging" section

  "paging": {  
   "previous": "https://graph.facebook.com/v2.2/34343/feed?since=1420799539&limit=25&__paging_token=enc_AexSv5Apv-nbkvNZ",  
   "next": "https://graph.facebook.com/v2.2/23ddsds/feed?limit=25&until=1417117943&__paging_token=enc_AezUcra6A2_dsSv5A"  
  }  

This section contains 2 links one to query the next results and the other to previous results.
Another important parameter to consider is the "until" parameter (or since), it needs to be used to return all the post until a certain period expressed as Epoc Timestamp.
In order to get all the post of a particular year:
  • I fetch the results recorded until 1/1/2015 00:00:00
  • I use the "next" record until I have a first record with created_time  == 2013
  • all the data is saved in a file for later analysis
  • between one fetch and another, it waits 5 seconds, in order to be safe from api rate limit

The script
To use the following script you need a python enviroment with this library installed: https://github.com/pythonforfacebook/facebook-sdk (on a mac, download it, then sudo python setup.py inside the directory)
It follows the script to analyse all the 2014's posts of a particular group; you need to edit:
  • value of the token variable
  • value of the group_id variable
  • change the start_date_time variable
  • change the stopyear variable

 import time  
 import datetime  
 import facebook  
 import cPickle as pickle  
 token = "put your graph api key here you can have one with Graph API Explorer"  
 group_id = 'put your group id here';  
 start_date_time = '01.01.2015 00:00:00';  
 pattern = '%d.%m.%Y %H:%M:%S'; 
 stopyear = '2013';
 epoch = int(time.mktime(time.strptime(start_date_time, pattern)))  
 print epoch  
 #code control from epoch string... -> print (datetime.datetime.fromtimestamp( epoch ).strftime('%Y-%m-%d %H:%M:%S'))  
 action = group_id + "/feed?limit=25&until=" + str(epoch);  
 print action;  
 graph = facebook.GraphAPI(token)  
 urlLen = len("https://graph.facebook.com/vX.Y"); #to remove from every request.  
 goOn = True;  
 allRecords = [];  
 while (goOn):  
      profile = graph.get_object(action)  
      if 'data' in profile:   
           print 'lecit...';  
      else:  
           print 'problems found... rate limit?';  
           print profile;  
           break;  
      allRecords.extend(profile["data"]);  
      if stopyear in profile["data"][0]['created_time']:  
           print "stop";  
           goOn = False;  
      else:  
           print "not ready..Go On."+str(len(allRecords));  
           action = profile["paging"]["next"][urlLen:];  
      time.sleep(5);  
 with open('genovapkdata.fb', 'wb') as fp:  
   pickle.dump(allRecords, fp)  

Conclusions
At the end of the execution I will have a file (genovapkdata.fb) with all the record saved in a format readable by python with another script:

 import cPickle as pickle  
 data = "";  
 with open('genovapkdata.fb', 'rb') as fp:  
   data = pickle.load(fp)  
 print "Records: "+str (len (data));  
 countGovi = 0;  
 ....  
 for onerecord in data:  
      if 'message' in onerecord:  
           msg = onerecord['message'];  
           msg = msg.lower();  
           if 'created_time' in onerecord and '2013' in onerecord['created_time']:  
                print 'record not important';       
           elif 'govi' in msg:  
                countGovi = countGovi + 1;  
 ...  

I discard posts with created_time of 2013 again, because this time I'm analysing 1 post at time, and I'm also counting record with a particular word in it "govi"... of course I did other analysis.

It is possible now do some statistics like:
- know who is the main post-writer in the group
- do a top10 of the place where the people train most
- how many are the generated posts
- how many are the generated comments