Adding Build Type option in the Apk Generator of the Open Event Android App

The apk-generator provided ability to the event organiser to build an apk from a single click by providing the necessary json/binary files. However it gave only one type of apk where on the other hand the Open Event Android was available with apk of different build versions.

Recently the functionality of the apk generator of the Open Event Android App was enhanced where the user is asked to select an option for build type either Google Play or FDroid which generates the apk according to that selected type.

The main difference in the googleplay apk and fdroid apk is the inclusion of googleplay libraries which aren’t included in the app/build.gradle file in case of fdroid build.

To include support for build type the following files for the apk-generator had to be changed:

  1. app/views/__init__.py
  2. app/tasks/__init__.py
  3. app/static/js/main.js
  4. app/generator/generator.py
  5. scripts/build.sh
  6. app/templates/index.html

Changes to the files

  • app/templates/index.html

This file was where the changes to the UI of the apk-generator showing build type option to the user were made. With this the user was presented with an option to choose build type among googleplay and fdroid apart from the rest of the essential information.

  • scripts/build.sh

The android app supported two different flavours one for google play and the other for fdroid. This required the build script to be modified according to the build type selected by the user during the filling of form.

If user selected “Google Play” or “Fdroid”, the script would look something like this:

#!/bin/bash
./gradlew assemblegoogleplayRelease --info
echo "signing"
jarsigner -keystore ${KEYSTORE_PATH} -storepass ${KEYSTORE_PASSWORD} app/build/outputs/apk/app-googleplay-release-unsigned.apk ${KEY_ALIAS}
echo "zipaligning"
${1}/zipalign -v 4 app/build/outputs/apk/app-$2-release-unsigned.apk release.apk
echo "done"

Where $2 is googleplay or fdroid depending on what build type the user has selected while building the apk from the apk generator.

  • app/views/__init__.py and app/tasks/__init__.py

These files were modified by adding another parameter for supporting the two build type options in the desired functions.

  • app/static/js/main.js

This is where the option selected by the user was taken and accordingly the apk corresponding to the build type option selected was made available to the user. The code for it was shown as follows:

$buildTypeRadio.change(
   function () {
       if (this.checked) {
           enableGenerateButton(true);
           buildType = $(this).val();
       }
  }
);

This was how the option to display build type option to the user was incorporated. This gave the user the ability to install different build versions of an apk, thus making it more useful from the user point of view.

Related Links:

Generating the Mozilla All Hands Open Event Android App

The main aim of FOSSASIA Open Event Android App is to give an event organiser the ability to generate the app through a single click by providing the necessary json and binary files. The app was tested on the Mozilla All Hands 2017 event which is an annual conference held for Mozilla employees to showcase their experience and also interact with each other.  The sample files for the event can be found here. (https://github.com/fossasia/open-event/tree/master/sample/MozillaAllHands17). The data for the event was taken from here. (https://sanfranciscoallhandsjune2017.sched.com/).

What was required for building the sample for Mozilla All Hands 2017 event?

  • images folder containing the necessary images of speaker having support for local images too, the logo of the event, the background image of the event.
  • event json file which has all the event specific information like the name of the event, the schedule of the event, the description of the event etc.
  • forms json file having session and speaker form data.
  • meta json file having the root url of the event.
  • microlocations json file having all the locations where the sessions are going to happen.
  • session_types json file consisting data of all the type of session which will occur in the event (the length of session, the name of type and the id).
  • sessions json file consisting session specific data like the title of the session, start time and end time of session, which track that session belongs to etc.
  • speakers json file consisting of speaker specific data like the name of the speaker, image of the speaker, social links of the speaker etc.
  • sponsors json file consisting list of all sponsors of the event.
  • tracks json file consisting of tracks specific data.
  • config.json file which consists of the api url, app name.

After generating the required zip containing the above json files, the zip is uploaded to this site (http://droidgen.eventyay.com/) and we get an apk after filling the required information. This means all the event organiser is able to generate the sample app by providing the necessary information about the event.

The sample can be found here:

Folder Link: https://github.com/fossasia/open-event/tree/master/sample/MozillaAllHands17

Zip Link: https://github.com/fossasia/open-event/tree/master/sample/MozillaAllHands17.zip

How did the Mozilla All Hands 2017 sample app look like?

The screenshots of the sample apk can be seen below:

 

 

What were the issues found in the sample app?

As compared to the previous sample apk like Google IO Open Event Android App some issues like support for local speaker images, background issue of the logo were solved. However there were certain issues which we observed on testing the app with the Mozilla All Hands 2017 event:

  1. The theme of the app remains the same no matter which event it is. It is important to give the event organiser the ability to customise the theme of the app.
  2. Certain information in the app like the event information is hard-coded and needs to be taken from the assets folder instead of strings.xml.

Related Links

Using Jackson Library in Open Event Android App for JSON Parsing

Jackson library is a popular library to map Java objects to JSON and vice-versa and has a better parsing speed as compared to other popular parsing libraries like GSON, JSONP etc. This blog post gives a basic explanation on how we utilised the Jackson library in the Open Event Android App.

To use the Jackson library we need to add the dependency for it in the app/build.gradle file.

compile 'com.squareup.retrofit2:converter-jackson:2.2.0'

After updating the app/build.gradle file with the code above we were able to use Jackson library in our project.

Example of Jackson Library JSON Parsing

To explain how the mapping is done let us take an example. The file given below is the sponsors.json file from the android app.

[
    “description”: “”,
    “id”: 1,
    “level”: 3,
    “name”:  KI Group,
    “type”: Gold,
    “url: “”,
    “logo-url”: “” 
]

The sponsors.json consists of mainly 7 attributes namely description, id, level, name, type, url and logo url for describing one sponsor of the event. The Sponsors.java file for converting the json response to Java POJO objects was done as follows utilizing the Jackson library:

public class Sponsors extends RealmObject {
    @JsonProperty(“id”)
    private int id;

    @JsonProperty(“type”)
    private String type;

    @JsonProperty(“description”)
    private String description;

    @JsonProperty(“level”)
    private String level;

    @JsonProperty(“name”)
    private String name;

    @JsonProperty(“url”)
    private String url;

    @JsonProperty(“logo-url”)
    private String logoUrl;
}

As we can see from the above code snippet, the JSON response is converted to Java POJO objects simply by using the annotation “@JsonProperty(“”)” which does the work for us.

Another example which makes this library amazing are the setter and getter annotations which help us use a single variable for two different json attributes if need be. We faced this situation when we were moving from the old api to the new json api. In that case we wanted support for both, old and new json attributes. In that case we simply used the following code snippet which made our transition to new api easier.

public class Sponsors extends RealmObject {
    private int id;
    private String type;
    private String description;
    private String level;
    private String name;
    private String url;
    private String logoUrl;

    @JsonSetter(“logo”)
    public void setLogo(String logoUrl) {
        this.logoUrl = logoUrl;
    }

    @JsonSetter(“logo-url”)
    public void setLogo(String logoUrl) {
        this.logoUrl = logoUrl;
    }
}

As we can see the setter annotations allow easy naming of variable to multiple attributes if need be thus making the code easily adaptable with less overload.

Related Links:

Using Flask SocketIO Library in the Apk Generator of the Open Event Android App

Recently Flask SocketIO library was used in the apk generator of the Open Event Android App as it gave access to the low latency bi-directional communications between the client and the server side. The client side of the apk generator was written in Javascript which helped us to use a SocketIO official client library to establish a permanent connection to the server.

The main purpose of using the library was to display logs to the user when the app generation process goes on. This gives the user an additional help to check what is the mistake in the file uploaded by them in case an error occurs. Here the library established a connection between the server and the client so that during the app generation process the server would send real time logs to the client so that they can be viewed by the user displayed in the frontend.

To use this library we first need to download it using pip command:

pip install flask-socketio

This library depends on the asynchronous services which can be selected amongst the following listed below:

  1. Eventlet
  2. Gevent
  3. Flask development server based on Werkzeug

Amongst the three listed, eventlet is the best performant option as it has support for long polling and WebSocket transports.

The next thing was importing this library in the flask application i.e the apk generator of the app as follows:

from flask_socketio import SocketIO

current_app = create_app()
socketio = SocketIO(current_app)

if __name__ == '__main__':
    socketio.run(current_app)

The main use of the above statement (socket.run(current_app)) is that with this the startup of the web server is encapsulated. When the application is run in debug mode it is preferred to use the Werkzeug development server. However in production mode the use of eventlet web server or gevent web server is recommended.

We wanted to show the status messages currently shown to the user in the form of logs. For this firstly the generator.py file was looked upon which had the status messages and these were sent to the client side of the generator by establishing a connection between them using this library. The code written on the server side to send messages to the client side was as follows:

def handle_message(message):
    if message not None:
        namespace = “/” + self.identifier;
        send(message, namespace = namespace)

As we can see from the above code the message had to be sent to that particular namespace. The main idea of using namespace was that if there were more than one users using the generator at the same time, it would mean the send() method would send the messages to all the clients connected which would lead to the mixing up of status messages and hence it was important to use namespace so that a message was sent to that particular client.

Once the server sent the messages to the client we needed to add functionality to the our client side to receive the messages from them and also update the logs area with suitable content received. For that first the socket connection was established once the generate button was clicked which generated the identifier for us which had to be used as the namespace for that process.

socket = io.connect(location.protocol + "//" + location.host + "/" + identifier, {reconnection: false});

This piece of code established the connection of the socket and helps the client side to receive and send messages from and to the server end.

Next thing was receiving messages from the server. For this the following code snippet was added:

socket.on('message', function(message) {
    $buildLog.append(message);
});

This piece of code receives the messages from the server for unnamed events. Once the connection is established and the messages are received, the logs are updated with each message being appended so as to show the user the real time information about their build status of their app.

This was how the idea of logs being shown in the apk generator was incorporated by making the required changes in the server and client side code using the Flask SocketIO library.

Related Links:

Writing Tests for ISO8601Date.java class of the Open Event Android App

ISO8601Date.java class of Open Event Android App was a util class written to perform the date manipulation functions and ensure the code base got more simpler and deterministic. However it was equally important to test the result from this util class so as to ensure the result returned by it was what we wanted. A test class named “DateTest.java” was written to ensure all the edge cases of conversion of the dates string from one timezone to another timezone were handled properly.

For writing unit tests, first we needed to add these libraries as dependencies in the app’s top level build.gradle file as shown below:

dependencies {
  testCompile 'junit:junit:4.12'
}

Then a JUnit 4 Test class, which was a Java class containing the required test methods was created. The structure of the class looked like this:

public class DateTest {
   @Test
   public void methodName() {
   }
}

Next step was including all the required methods which ensured the util class returned the correct results according to our needs. Various edge cases were taken into account by including functions like converting of date string from local time zone to specified timezone, from international timezone to local timezone, from local timezone to international timezone and many more. Some of the methods which were added in the class are shown below:

  • Test of conversion from local timezone to specified timezone:

This function aimed at ensuring the util class worked well with date conversion from local time zone to a specified timezone. An example as shown below was taken where the conversion of the date string was tested from UTC timezone to Singapore timezone.

@Test
public void shouldConvertLocalTimeZoneDateStringToSpecifiedTimeZoneDateString() {
    ISO8601Date.setTimeZone("UTC");
    ISO8601Date.setEventTimeZone("Asia/Singapore");

    String dateString1 = "2017-06-02T07:59:10Z";
    String actualString = ISO8601Date.getTimeZoneDateStringFromString(dateString1);
    String expectedString = "Thu, 01 Jun 2017, 23:59, UTC";
    Assert.assertEquals(expectedString, actualString);
}
  • Test of conversion from local timezone to international timezone:

This function aimed at ensuring the util class worked well with the date conversion from local timezone to international timezone. An example as shown below was taken where the conversion of the date string was tested from Amsterdam timezone to Singapore timezone.

@Test
public void shouldConvertLocalTimeZoneDateStringToInternationalTimeZoneDateString() {
    ISO8601Date.setTimeZone("Europe/Amsterdam");
    ISO8601Date.setEventTimeZone("Asia/Singapore");

    String dateString = "2017-06-02T02:29:10Z";
    String actualString = ISO8601Date.getTimeZoneDateStringFromString(dateString);
    String expectedString = "Thu, 01 Jun 2017, 20:29, GMT+02:00";
    Assert.assertEquals(expectedString, actualString);
}


Above were some functions added to ensure the conversion of a date string from one timezone to another was correct and thus ensured the util class was working properly and returned the results as required.

The last thing left was running the test to check the results the util class returned. For this we had to do two things:

  1. Sync the project with Gradle.
  2. Run the test by right clicking on the class and selecting “Run” option.

Through this we were able to run the test and check the output of the util class on different cases through the results which could be seen on the Android Monitor in the Android Studio.

Related Links:

  1. This link is about building effective unit tests in android. (https://developer.android.com/training/testing/unit-testing/index.html)
  2. This link is about the unit testing on date processing. (https://stackoverflow.com/questions/565289/unit-testing-code-that-does-date-processing-based-on-todays-date)

Enabling Live Streaming of Sessions in the Open Event Android App

The Open Event Android App had no option for viewing session videos if the links for them were provided by the event organiser. This post walks through how viewing of session videos was made possible through use of implicit intents which launched the Youtube app if the video link was a Youtube link and what all possible cases were taken into account so as to provide the user to view the video of a session as described below:

What is the current status of the app?

The current SessionDetailActivity.java containing the detail of the sessions of the event looks like this:

Adding Live Streaming option in the app

A live streaming feature is added in the app which enables the user to view the session. Now there were certain edge cases which needed to be handled:

  • No video links provided in the sessions json file

In that case the SessionDetailActivity.java looked the way it looks above as there is no way we can enable the live streaming option as the live video links aren’t provided by the event organiser.

  • The video links are provided but are not Youtube links

In that case the SessionDetailActivity.java looks like this, where the card view has a grey background showing that the user will be directed to the required link on a click.

  • The video links are Youtube links

In that case the Youtube thumbnail is fetched through Picasso and is made as the card view background. The SessionDetailActivity.java looks like this in such a case:

First the link is checked whether it is a Youtube link or not as illustrated in the code snippet below:

if(!Utils.isEmpty(video_link)) {
    playButton.setVisibility(View.VISIBLE);

    if(video_link.contains(ConstantStrings.YOUTUBE)) {

        Picasso.with(this)
               .load(youtubeLink)
               .into(youtubeThumbnail);
    
        youtubeThumbnail.setVisibility(View.VISIBLE);
    }

}

After the link is guaranteed as a Youtube link the play icon click is handled. On clicking the play icon, the user is directed to a Youtube app for the viewing of a session through an implicit intent using this piece of code:

playButton.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {

        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(video_link)));

    }

});

Thus the user is given an option to view the live streaming of a session, if the video links are provided by the event organiser.

Related Links:

Adding a Two Pane Layout to the Open Event Android App

Android gadgets are found in various screen sizes and densities. It is here where fragments make planning the layouts for phones and tablets simple.  We can progressively include and expel sections from an activity which makes it conceivable to plan adaptable UIs.

Generally a single pane design is favored for telephones and multi-pane formats are utilized for tablets with a specific end goal to use the additional space which is found in tablets. The Open Event Android App on tablet view appeared to be identical for a versatile client and accordingly it had a considerable measure of free space which could be used for effective UI for tablet clients. A two-pane design is utilized for the application where the navigation view is on the left side while the item clicked on the navigation view is on the right side.

  1. Steps involved for incorporating a two-pane layout

The steps that need to be followed for the app to support a two-pane layout are as follows:

  1. Create a layout-sw600dp (for small tablet users) or layout-sw720dp (for large tablet users) in the res directory.
  2. The name of files should be same for those within layout/ and layout-sw600dp/ to provide a support for a two-pane layout.

The layout/activity_main.xml structure of the app looks like this:

The layout-sw600dp/activity_main.xml structure of the app looks like this:

  1. Now in the MainActivity.java file of the app we took a boolean variable mTwoPane which was true if during runtime findViewById(R.id.drawer) didn’t exist as a drawerlayout is used as a root view for the activity_main.xml in layout/ folder but not in layout-sw600dp folder.
  2. All the parts of the MainActivity.java which had a drawerlayout variable were now put in an “if” condition checking if the mTwoPane boolean value is false then execute the statement otherwise set the drawerlayout to lock mode.

This helped us accomplishing a two-pane layout in the tablet layout of the app thus helping in using the extra space in a more efficient manner.

Related Links:

Formatting of ISO8601Date.java class in Open Event Android App

ISO8601Date.java is an util class in Open Event Android App which comprises of all the required date manipulation functionalities required by the application to parse the dates from the api given in ISO8601 format. Previous implementation of the class consisted of functions which needed multiple lines of function call in the main code. Due to this reason the util class was formatted in a way so that the function call can be simplified and improve the quality of our codebase.

1. Previous Implementation of ISO8601Date.java class

The previous implementation of the ISO8601Date.java class had a number of functions needed for date manipulations in it. However when we used to call them in the code they used to take up several lines which demonstrated that we didn’t use the possibility of an util class to the best of our utilization.

An example illustrating this fact is given below:

Example 1: (In SessionListAdapter.java)

String date = ISO8601Date.getTimeZoneDateString(ISO8601Date.getDateObject(session.getStartTime())).split(",")[0] + "," +ISO8601Date.getTimeZoneDateString(ISO8601Date.getDateObject(session.getStartTime())).split(",")[1];

The principal case is from SessionListAdapter.java class where we are utilizing the ISO8601Date.java util class for finding the start time. It can be perceived how various lines including the split functions are utilized for the date manipulation.

2. Current Implementation of ISO8601Date.java class

The factors taken into account for the current implementation of the util class were:

  1. To ensure we write generic functions which can be used in multiple places in the app.
  2. The calling of the function is enough to do what is required.

These factors were the key points for rewriting the util class and ensuring the class is easy to use with enough commenting to explain what was going on in each function.  The idea was to write all the complex function calling code within the function itself.

With the present execution of the class the codebase got more basic as for each situation a straightforward one line call was sufficient to give the output we needed as demonstrated below:

Example 1: (In SessionListAdapter.java)

String date = ISO8601Date.getDateFromStartDateString(session.getStartTime());

Example 2: (In SessionDetailActivity.java)

String startTime = ISO8601Date.getTimeFromStartDateString(session.getStartTime());

The advantage now is, whenever we have to use a new function related to date manipulation we simply have to create one in the util class and provide a simple one line way of calling it in our main code to make the codebase look straightforward. The examples shown above are the same ones which were illustrated before. The multiple lines which they took for calling of a function didn’t make the util class to the best of our use. As we can see with current examples, the new class ensured the function handled the complex stuff within itself without delegating it to the main code.

Related Links

Generating the Google IO Open Event Android App

The main aim of FOSSASIA Open Event Android App is to give an event organiser the ability to generate the app through a single click by providing the necessary json and binary files. As of late the Android application was tested on Google IO 2017 event. The sample files can be seen here. The data with respect to the event was taken from this site (https://events.google.com/io/). What was astonishing about this application is the simplicity with which we can make an event specific application by giving the vital assets required (json and binary files).

What was needed for generating the Google IO 2017 app?

For generating the app we had to provide the following files:

  1. images folder containing the necessary images of speaker, the logo of the event etc.
  2. event json file which has all the event specific information like the name of the event, the schedule of the event, the description of the event etc.
  3. forms json file having session and speaker form data.
  4. meta json file having the root url of the event.
  5. microlocations json file having all the locations where the events are going to happen.
  6. session_types json file consisting data of all the type of session which will occur in the vent.
  7. sessions json file consisting session specific data like the title of the session, start time and end time of session, which track that session belongs to etc.
  8. speakers json file consisting of speaker specific data like the name of the speaker, image of the speaker, social links of the speaker etc.
  9. sponsers json file consisting list of all sponsers of the event.
  10. tracks json file consisting of tracks specific data.
  11. config.json file which consists of the api url, app name.

After providing the required information we go to this site (http://droidgen.eventyay.com/) and the first thing this site asks us is the email id. Then we upload the required files mentioned above in a zip folder and we have a apk which we can test it out on our Android phone.

How did the Google IO sample app look like?

The files for the sample event can be found over here:

Folder Link:

https://github.com/fossasia/open-event/tree/master/sample/GoogleIO17

Zip File Link:

https://github.com/fossasia/open-event/blob/master/sample/GoogleIO17.zip

What were the issues found in the sample app?

There were certain issues which we observed on testing the app with the Google IO event:

  1. The theme of the app remains the same no matter which event it is. It is important to give the event organiser the ability to customise the theme of the app.
  2. The support for local speaker images needs to be provided as we want to give the event organiser an option to include the images locally or not.
  3. The background of the logo needs to be changed because in certain logos, the dark background causes visibility problems.
  4. Certain information in the app like the event information is hard-coded and needs to be taken from the assets folder instead of strings.xml.

Resources