UNESCO Hackathon at FOSSASIA Summit in Singapore

Join the UNESCO Open Data Hackathon at the FOSSASIA Summit, create open source apps and games that tackle climate change, environment and sustainable development challenges, and win awesome prizes! The hackathon takes place from Saturday 24 March to Sunday 25 March 2018 at the Lifelong Learning Institute in Singapore.

We are specifically interested in applications and games that set an example for others who could replicate solutions in other countries, and in particular in the Mekong countries, to tackle the sustainable development challenges. It is our goal to engage the developer community to develop innovative applications in open source by leveraging the open data and knowledge available.

We are inviting developers, designers, open source contributors, bloggers, journalists and all FOSSASIA community members to be part of the UNESCO Hackathon. We are especially encouraging applications from the Mekong region to join the contest. The hackathon is open for all and awesome prizes are waiting for you!

For participants from outside of Singapore we have the possibility to host them in a Singapore hostel. Please apply here. The number is limited. UNESCO encourages the application of women and girls.

How do I sign up?

1. Get your ticket to the Event on eventyay.com.

2. Sign up on Devpost.

3. Join the Gitter channel at https://gitter.im/fossasia/hackathon (requires login with Github).

4. Find team members and create your team preferably at least 3 members and maximum 5 contributors. You are also welcome to sign up and then wait until the Presentation of Ideas on Saturday before deciding to join a team, however we’d encourage you to form/join a team in advance if you already have an idea that you’d like to work on.

5. Join the event at the Lifelong Learning Institute on Saturday, March 24 at the opening at 2.00 pm until 10.00 pm and on Sunday, March 25 from 9.00 am until 5.00 pm.

Visit the website at unesco.sciencehack.asia and stay connected, join the event on Facebook and Meetup and follow FOSSASIA on Twitter.

UNESCO Hackathon Schedule

Hackathon Opening: March 24, 2018

12.00 Registration Opens
14:00 Opening
14.10 Intro of Background, Rules and Prizes
14:20 Presentation of Ideas, Teams and Team Building Activities
15:00 Begin of Hacking Activities
19.30 Dinner
22:00 Closing of Space

Hackday: March 25, 2018

08:00 – 09:00 Breakfast
09:00 – 13:00 Hack Activities Continue
13:00 – 13:30 Lunch
13:30 – 15:00 Hacking Continues
14:00 Submission Form Closes
15:15 – 16:00 Presentation of Outcome
16:00 Judges Withdraw for Consultation
16:30 Award Announcement and Ceremony
17:00 Summit Closing

Location/Venue

Lifelong Learning Institute

Address: 11 Eunos Road 8, Singapore 408601

Prizes

Prizes are awarded for three teams, and each team prize with a value of 1000 SGD. Win cool gear, hardware, raspis, Arduinos and more!

Project Submission Requirements

For the expected outcome of the hack, the applications or games shall be open source and use open data to tackle the climate change, environment and sustainable development challenges.

They shall address one or several of the following requirements:

  1. Respond to pressing environmental challenges at local, national or regional levels in Asia

  2. Enable the visualization of data in an innovative and/or easy-to-understand way

  3. Mobilize and create engagement of variety of stakeholders and sectors in society on climate change, environment and sustainable development

  4. Gender-sensitive prototype, recognizing or encouraging women’s participation in sustainable development

Functioning App

An important point is, is the prototype or showcase functioning? We prefer real code and design implementations over mockups.

What to enter

Please submit a link to the app, a Github repo link and a short presentation as a download or on Google drive (ensure it is set to public sharing). You can also share anything else to demonstrate your work and let us test it.

  • Video: The platform accepts links to YouTube, Vimeo or Youku. If you like you can post a short video to demonstrate your work.

  • File Upload: There is also an option to upload a file. The platform allows submitters to upload one file, though they can combine files into a single ZIP file.

  • Other: The platform requires contestants to enter an entry name and description. Please also accept the the conditions of the contest including sharing your work under certified Open Source license.

Platform

Share information about what operating systems or devices can your hack run on.

Ressources

Include information about API, SDK, or data set, that are required to run the app.

New vs. Existing

Any work done need to be new for the competition. Existing apps are not eligible. However the specific details what is acceptable and what is not will be determined by the jury. For example existing apps that have been modified substantially and include entirely new functionality would still be eligible.

Submission Rights & Display

The submissions should be Open Source and licensed under a compliant Open Source/Free Software license. They should be upload to a Github repository.

We also request the right to use the winners’ names and work to promote the competition and hackathons in future.

Links

UNESCO Hackathon: https://unesco.sciencehack.asia

FOSSASIA Summit: https://2018.fossasia.org

Tickets: https://eventyay.com/e/db15e7db/

Project Signup: https://fossasia-unesco.devpost.com

Facebook: https://www.facebook.com/events/139329623548116/

Meetup: https://www.meetup.com/FOSSASIA-Singapore-Open-Technology-Meetup/events/247899257/

FOSSASIA: https://twitter.com/fossasia

List of Open Data Resources in Asia

Data portals across Asia: http://dataportals.org
China: http://opendatachina.com
Singapore http://data.gov.sg
Indonesia: https://petabencana.id/map/jakarta
Cambodia: https://opendevelopmentcambodia.net
Thailand https://data.go.th, http://catalog.opendata.in.th
Vietnam: https://vietnam.opendevelopmentmekong.net/data/
World Bank: https://data.worldbank.org
India http://data.gov.in

Participate in the #OpenTechNights Program today and Win a Free Stay during the FOSSASIA Summit 2018 from the Open Source Initiative and UNESCO

The FOSSASIA Summit 2018 takes place in Singapore from Thursday, March 22 – Sunday, March 25. Open Source contributors can now apply for a free ticket to the event, and accommodation throughout the conference. In addition, you’ll be eligible to participate in: Featured cloud workshops, the UNESCO hackathon, and celebrate the 20th Anniversary of the Open Source Initiative. All you have to do is convince us, that you are an awesome Open Source contributor and book your trip to Singapore!

About #OpenTechNights

Developers from all over the world are joining the FOSSASIA Summit. We want to connect established and new Open Tech contributors alike. With the support of UNESCO, the Open Source Initiative, and other partners, we are inviting Free and Open Source Software contributors to join us. Winners will receive free lodging at a shared accommodation in the centre of Singapore, and a free ticket to the conference.

Winners are expected to join the summit each day, to participate in the workshops, and the Hackathon on Saturday/Sunday, March 24/25. We would also hope you can support the Open Source Initiative at their booth.

How do I sign up?

Step 1: Please fill in our form here before February 28, 2018.

Step 2: We will notify all winners within three days of their submission, however judging will begin immediately, and continue until all open spots are filled, so the earlier you apply, the higher your chances to win. Please note, winners will receive free accommodations in Singapore. Flight and other travel costs are not included and are the responsibility of the attendee.

Step 3: Selected applicants must confirm their itinerary and tickets before March 1st to insure their free stay in Singapore. Earliest check-in possible is Wednesday March 21, latest check-out is Monday, March 26. Please indicate your arrival and departure times in the application form.

Expectations of Participants – Share what you learn

  1. Attendees support volunteers, speakers and participants at the event, and take a shift at the Open Source Initiative’s booth. Let’s bring the spirit of sharing Open Technologies and learning together!
  2. Please confirm your participation at the opening event at 12PM, Thursday, March 22, 2018 and participate in the specially featured cloud workshops on Friday, March 23, 2018 from 9.00 AM – 5.00PM.
  3. Attendees participate in the UNESCO Hackathon on Saturday, March 24 (2.00 PM – 10.00PM) and on Sunday, March 25 (9.00 AM – 5.00PM).
  4. Attendees help reach out to community members who cannot join us at the event, make tweets, share what you learn on social media, publish photos and put up blog post about the summit.

Apply Now

Apply for a free stay with #FOSSASIA #OpenTechNights supported by the Open Source Initiative and the UNESCO and participate in the FOSSASIA Summit 2018 now here!

More Information

More updates, tickets and information on speakers on our website: https://2018.fossasia.org

Links

Open Source Initiative: https://opensource.org

UNESCO: http://unesco.org

Enhancing Rotation in Phimp.me using Horizontal Wheel View

Installation

To implement rotation of an image in Phimp.me,  we have implemented Horizontal Wheel View feature. It is a custom view for user input that models horizontal wheel controller. How did we include this feature using jitpack.io?

Step 1: 

The jitpack.io repository has to be added to the root build.gradle:

allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
}


Then, add the dependency to your module build.gradle:

compile 'com.github.shchurov:horizontalwheelview:0.9.5'


Sync the Gradle files to complete the installation.

Step 2: Setting Up the Layout

Horizontal Wheel View has to be added to the XML layout file as shown below:

<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2">

<com.github.shchurov.horizontalwheelview.HorizontalWheelView
android:id="@+id/horizontalWheelView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toStartOf="@+id/rotate_apply"
android:padding="5dp"
app:activeColor="@color/accent_green"
app:normalColor="@color/black" />

</FrameLayout>


It has to be wrapped inside a Frame Layout to give weight to the view.
To display the angle by which the image has been rotated, a simple text view has to be added just above it.

<TextView
android:id="@+id/tvAngle"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:textColor="@color/black"
android:textSize="14sp" />

Step 3: Updating the UI

First, declare and initialise objects of HorizontalWheelView and TextView.

HorizontalWheelView horizontalWheelView = (HorizontalWheelView) findViewById(R.id.horizontalWheelView);
TextView tvAngle= (TextView) findViewById(R.id.tvAngle);

 

Second, set up listener on the HorizontalWheelView and update the UI accordingly.

horizontalWheelView.setListener(new HorizontalWheelView.Listener() {
@Override
public void onRotationChanged(double radians) {
updateText();
updateImage();
}
});


updateText()
updates the angle and updateImage() updates the image to be rotated. The following functions have been defined below:

private void updateText() {
String text = String.format(Locale.US, "%.0f°", horizontalWheelView.getDegreesAngle());
tvAngle.setText(text);
}

private void updateImage() {
int angle = (int) horizontalWheelView.getDegreesAngle();
//Code to rotate the image using the variable 'angle'
rotatePanel.rotateImage(angle);
}


rotateImage()
is a method of ‘rotatePanel’ which is an object of RotateImageView, a custom view to rotate the image.

Let us have a look at some part of the code inside RotateImageView.

private int rotateAngle;


‘rotateAngle’ is a global variable to hold the angle by which image has to be rotated.

public void rotateImage(int angle) {
rotateAngle = angle;
this.invalidate();
}


The method invalidate() is used to trigger UI refresh and every time UI is refreshed, the draw() method is called.
We have to override the draw() method and write the main code to rotate the image in it.

The draw() method is defined below:

@Override
public void draw(Canvas canvas) {
super.draw(canvas);
if (bitmap == null)
return;
maxRect.set(0, 0, getWidth(), getHeight());// The maximum bounding rectangle

calculateWrapBox();
scale = 1;
if (wrapRect.width() > getWidth()) {
scale = getWidth() / wrapRect.width();
}

canvas.save();
canvas.scale(scale, scale, canvas.getWidth() >> 1,
canvas.getHeight() >> 1);
canvas.drawRect(wrapRect, bottomPaint);
canvas.rotate(rotateAngle, canvas.getWidth() >> 1,
canvas.getHeight() >> 1);
canvas.drawBitmap(bitmap, srcRect, dstRect, null);
canvas.restore();
}

private void calculateWrapBox() {
wrapRect.set(dstRect);
matrix.reset(); // Reset matrix is ​​a unit matrix
int centerX = getWidth() >> 1;
int centerY = getHeight() >> 1;
matrix.postRotate(rotateAngle, centerX, centerY); // After the rotation angle
matrix.mapRect(wrapRect);
}

 

And here you go:

Resources

Refer to Github- Horizontal Wheel View for more functions and for a sample application.

How to use Realm in SUSI Android to Save Data

Sometimes we need to store information on the device locally so that we can use information offline and also query data faster. Initially, SQLite was only option to store information on the device. But working with SQLite is difficult sometimes and also it makes code difficult to understand. Also, SQL queries take a long time. But now we have realm a better alternative of SQLite. The Realm is a lightweight mobile database and better substitute of SQLite. The Realm has own C++ core and store data in a universal, table-based format by a C++ core. This allows Realm to allow data access from multiple languages as well as a range of queries. In this blog post, I will show you why we used Realm and how we save data in SUSI Android using Realm.

“How about performance? Well, we’re glad you asked 🙂 For all the API goodness & development productivity we give you, we’re still up to 100x faster than some SQLite ORMs and on average ~10x faster than raw SQLite and common ORMs for typical operations.” (compare: https://blog.realm.io/realm-for-android/)

Advantages of Realm over SQLite are following:

  • It is faster than SQLite as explained on the Realm blog. One of the reasons realm is faster than SQLite is, the traditional SQLite + ORM abstraction is leaky because ORM simply converts  Objects and their methods into SQL statements. Realm, on the other hand, is an object database, meaning your objects directly reflect your database.
  • It is easier to use as it uses objects for storing data. When we use SQLite we need boilerplate code to convert values to and from the database, setting up mappings between classes and tables, fields and columns, foreign keys, etc. Whereas in Realm data is directly exposed as objects and can be queried without any conversion.

Prerequisites

To include this library in your project you need

  • Android studio version 1.5.1 or higher.
  • JDK version 7.0 or higher.
  • Android API level 9 or higher.

How to use realm in Android

To use Realm in your project we must add the dependency of the library in build.gradle(project) file 

 dependencies {
       classpath “io.realm:realm-gradle-plugin:3.3.1”
   }

and build.gradle(module) file.

apply plugin: realm-android
dependencies {
compile io.realm:android-adapters:1.3.0
}

Now you have to instantiate Realm in your application class. Setting a default configuration in your Application class, will ensure that it is available in the rest of your code.

RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(this)
                                                              .deleteRealmIfMigrationNeeded().build();
Realm.setDefaultConfiguration(realmConfiguration);

Now we need to create a model class. A model class is use to save data in Realm and retrieve saved data and it must extend RealmObject class. For eg.

public class Person extends RealmObject {
   private String name;
   public String getName() {
       return name;
   }
   public void setName(String name) {
       this.name = name;
   }
}

Field in the model class uses to define columns. For eg. ‘name’ is a column name. Method like setName() use to save data  and getName() use to retrieve saved data.

Now create an instance of the Realm in the activity where you want to use it. It will be used to read data from the Realm and write data to the Realm.

Realm realm = Realm.getInstance(this);

Before you start a new transaction you must call beginTransaction(). It will open database.

realm.beginTransaction();

To write data to the Realm you need to create an instance of the model class. createObject used to create an instance of RealmObject class. Our model class is RealmObject type so we use createObject() to create an instance of the model class.

Person person = realm.createObject(Person.class);

Write data to realm.

person.setName(“MSDHONI”);

And after it you must call commitTransaction(). commitTransaction() use to end transaction.

realm.commitTransaction();

Reading data from Realm is easier than writing data to it. You need to create an instance of the Realm.

Realm realm = Realm.getInstance(this);

To create query use where the method and pass the class of object you want to query. After creating query you can fetch all data using findAll() method.

realm.where(Person.class).findAll();

Reference

Using Universal Image Loader to Display Image on Phimpme Android Application

In Phimpme Android application we needed to load image on the sharing Activity fast so that there won’t be any delay that is visible by a user in the loading of any activity. We used Universal Image Loader to load the image on the sharing Activity to load Image faster.

Getting Universal Image Loader

To get Universal Image Loader in your application go to Gradle(app)-> and then add the following line of code inside dependencies:

dependencies{

compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.4'

}

Initialising Universal Image Loader and Displaying Image

To display image on using Universal Image Loader we need to convert the image into a URI from a file path:

saveFilePath = getIntent().getStringExtra(EXTRA_OUTPUT);
Uri uri = Uri.fromFile(new File(saveFilePath));

How an image should be displayed

We need to display the image in such a way that it covers the whole image view in the sharing Activity. The image should be zoomed out. The quality of the image should not be distorted or reduced. The image should look as it is. The image should be zoomable so that the user can pinch to zoom in and zoom out. For the image to adjust the whole Image View we set ImageScaleType.EXACTLY_STRETCHED. We will also set cacheInMemory to true and cacheOnDisc to true.  

private void initView() {
   saveFilePath = getIntent().getStringExtra(EXTRA_OUTPUT);
   Uri uri = Uri.fromFile(new File(saveFilePath));
   ImageLoader imageLoader = ((MyApplication)getApplicationContext()).getImageLoader();
   DisplayImageOptions options = new DisplayImageOptions.Builder()
           .cacheOnDisc(true)
           .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
           .cacheInMemory(true)
           .bitmapConfig(Bitmap.Config.RGB_565)
           .build();
   imageLoader.displayImage(uri.toString(), shareImage, options);
}

Image Loader function in MyApplication class:

private void initImageLoader() {
   File cacheDir = com.nostra13.universalimageloader.utils.StorageUtils.getCacheDirectory(this);
   int MAXMEMONRY = (int) (Runtime.getRuntime().maxMemory());
   // System.out.println("dsa-->"+MAXMEMONRY+"   "+(MAXMEMONRY/5));//.memoryCache(new
   // LruMemoryCache(50 * 1024 * 1024))
   DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
           .cacheInMemory(true)
           .cacheOnDisk(true)
           .build();

   ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
           this).memoryCacheExtraOptions(480, 800).defaultDisplayImageOptions(defaultOptions)
           .diskCacheExtraOptions(480, 800, null).threadPoolSize(3)
           .threadPriority(Thread.NORM_PRIORITY - 2)
           .tasksProcessingOrder(QueueProcessingType.FIFO)
           .denyCacheImageMultipleSizesInMemory()
           .memoryCache(new LruMemoryCache(MAXMEMONRY / 5))
           .diskCache(new UnlimitedDiskCache(cacheDir))
           .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default
           .imageDownloader(new BaseImageDownloader(this)) // default
           .imageDecoder(new BaseImageDecoder(false)) // default
           .defaultDisplayImageOptions(DisplayImageOptions.createSimple()).build();

   this.imageLoader = ImageLoader.getInstance();
   imageLoader.init(config);
}

Image View in Sharing Activity XML file:

In the Sharing Activity Xml resource, we need to specify the width of the image view and the height of the image view. In Phimpme Android application we are using ImageViewTouch so that we have features like touch to zoom in zoom out. The scale type of the imageView is centerCrop so that image which is loaded is zoomed out and focus is in the center of the image.  

<org.fossasia.phimpme.editor.view.imagezoom.ImageViewTouch
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:id="@+id/share_image"
   android:layout_below="@+id/toolbar"
   android:layout_weight="10"
   android:layout_alignParentStart="true"
   android:scaleType="centerCrop"/>

Conclusion

To load image faster on any ImageView we should use Universal Image Loader. It helps load the activity faster and allows many features as discussed in the blog.

 

Github

Resources

Implementation of Set Different Language for Query in SUSI Android

SUSI.AI has many skills. Some of which are displaying web search of a certain query, provide a list of relevant information of a topic, displaying a map of the certain position and simple text message of any query. Previously SUSI.AI reply all query in English language but now one important feature is added in SUSI.AI and that feature is, reply query of the user in the language that user wants. But to get the reply in different language user has to send language code of that language along with query to SUSI Server. In this blog post, I will show you how it is implemented in SUSI Android app.

Different language supported in SUSI Android

Currently, different languages added in option in SUSI Android and their language code are:

Language Language Code
English en
German de
Spanish es
French fr
Italian it
Default Default language of the device.

Layout design

I added an option for choosing the different language in settings. When the user clicks on Language option a dialog box pops up. I used listpreference to show the list of different languages.

<ListPreference

  android:title=“@string/Language”

  android:key=“Lang_Select”

  android:entries=“@array/languagentries”

  android:entryValues=“@array/languagentry”>

</ListPreference>

“title” is used to show the title of setting, “entries” is used to show the list of entry to the user and “entryValue” is the value corresponding to each entry. I used listpreference because it has own UI so we don‘t have to develop our own UI for it and also it stores the string into the SharedPreferences so we don’t need to manage the values in SharedPreference. SharedPreference needed to set value in Language in settings so that once user close app and again open it setting will show same value otherwise it will show default value. We used an array of string to show the list of languages.

<string-array name=“languagentries”>

  <item>Default</item>

  <item>English</item>

  <item>German</item>

  <item>Spanish</item>

  <item>French</item>

  <item>Italian</item>

</string-array>

SetLanguage implementation

To set language user must choose Language option in setting.

On clicking Language option a dialog box pop up with the list of different languages. When the user chooses a language then we save corresponding language code in preference with key “prefLanguage” so that we can use it later to send it to the server along with the query. It also uses to send language to the server to store user language on the server, so that user can use the same language in the different client.

querylanguage.setOnPreferenceChangeListener { _, newValue ->

  PrefManager.putString(Constant.LANGUAGE, newValue.toString())

  if(!settingsPresenter.getAnonymity()) {

      settingsPresenter.sendSetting(Constant.LANGUAGE, newValue.toString(), 1)

  }

}

newValue.toString() is the value i.e language code of corresponding language.

Now when we query anything from SUSI.AI we send language code along with query to the server. Default language is default language of the device. Before sending language to the server we check language is default language or any specific language.

val language = if (PrefManager.getString(Constant.LANGUAGE, Constant.DEFAULT).equals(Constant.DEFAULT))

Locale.getDefault().language

else PrefManager.getString(Constant.LANGUAGE, Constant.DEFAULT)

And after that, we send the corresponding language along with query to the server.

clientBuilder.susiApi.getSusiResponse(timezoneOffset, longitude, latitude, source, language, query)

Reference

Making SUSI Alexa skill as an express app

Previously SUSI Alexa skill was deployed using AWS Lambda service (Refer to this blog). Each SUSI.AI Bot should be deployed on Google cloud using Kubernetes. To accomplish that, we need to remove the dependency of the SUSI Alexa skill from AWS Lambda service. We need to make it an express app, to be able to deploy it to Google cloud. Let’s start with on how to achieve it:

SUSI Alexa skill:

We require three files to make the skill as an express app. The main entry point for the skill would be server.js file, which will serve the incoming request using two helper files alexa.js and handlers.js.

Server.js:

This file acts as the main entry point for the incoming request. We handle two type of requests using it, that are:

  1. Launch request
  2. Intent request

Launch request is triggered when a person utters “Alexa, open susi chat” , “Alexa, start susi chat”, “Alexa, launch susi chat” etc. This request is responded with an introductory phrase about SUSI.AI. To catch this request:

if (type === "LaunchRequest") {
        var endpoint = "http://api.susi.ai/susi/chat.json?q="+"Welcome"; // ENDPOINT GOES HERE
        
        http.get(endpoint, (response1) => {
            var body = "";
            response1.on("data", (chunk) => { body += chunk; });
            response1.on("end", () => {
                var viewCount;
                viewCount = JSON.parse(body).answers[0].actions[0].expression;
                endpoint = "http://api.susi.ai/susi/chat.json?q="+"Get+started"; // ENDPOINT GOES HERE
                body = "";
                http.get(endpoint, (response2) => {
                    response2.on("data", (chunk) => { body += chunk; });
                    response2.on("end", () => {
                        viewCount += JSON.parse(body);.answers[0].actions[0].expression;
                        response.say(viewCount,false);
                    });
                });
            });
        });
    }

Intent request gets triggered, when any other phrase is uttered by the user except Launch related phrases. We check if the intent triggered has a corresponding handler to handle the request. If the handler is found in handlers.js file, we call it passing the required arguments to the handler function. Let’s see how handlers make this step possible.

Handler.js:

This file decides on what function to run when a particular type of intent is triggered. As we have just one intent for our SUSI Alexa skill i.e. callSusiApi, we have just one function in our handlers.js file. During its execution, the first step we do is extract the query value:

let query = slots.query.value;

Depending upon the query value, we run its corresponding code. For example, in case of a generic query (i.e. any query except stop, cancel and help):

var endpoint = "http://api.susi.ai/susi/chat.json?q="+query; // ENDPOINT GOES HERE

http.get(endpoint, (response1) => {
    var body = "";
    response1.on("data", (chunk) => { body += chunk; });
    response1.on("end", () => {
        var data = JSON.parse(body);
        if(data.answers[0].actions[1]){
            // handle rss and table type results
        }
        else
        {
            viewCount = data.answers[0].actions[0].expression;
        }
        response.say(viewCount,true);
    });
});

At the end of the function we respond to the user with an answer to his/her query using:

response.say(viewCount,true);

Alexa.js:

When we get a request from the user, we pass that request and response object to this file. This file helps us wrap the required request properties into an object and return that back to the server file, which was the entry point for the request. Now, we can easily extract the properties in server file and work with those:

We extract the properties like this:

let session = req.body.session,
        intent,
        slots;
session.attributes = session.attributes || {};

if (req.body.request.intent) {
    intent = req.body.request.intent.name;
    slots = req.body.request.intent.slots;
}

Then we return the object back at the end:

return {
        type: req.body.request.type,
        intent: intent,
        slots: slots,
        session: session,
        response: {
            say: (text, shouldEndSession) => say(text, shouldEndSession),
            ask: (text, shouldEndSession) => say(text, shouldEndSession)
        }
    };

Great, we have made the SUSI Alexa skill as an express app. The next step is to do some changes in the configuration tab of our skill:

  1. Instead of Amazon resource number, we fill our webhook address here: 

  2. A new property shows up that is SSL certificate. As we are using Heroku for webhook services, we select the second option as shown below: 

  3. It’s time to test the skill: 

    This repository by Salesforce helped me a lot in making the SUSI skill as an express app.

    Resources:

    1. Developing Alexa Skills Locally with Node.js by Josh Skeen from Bignerdranch.
    2. Amazon Alexa Skills: Create a Custom Skill by Simon Coope from SJCNET.

How to Parse HTML Tags and Anchor Clickable Links in SUSI Android App

Html tags are used to define how contents of a webpage should be formatted and displayed. Sometimes the SUSI answer type response contains some html tags but showing these html tags without parsing would distort the normal text flow in SUSI Android.

For the query ‘Ask me something’ SUSI’s reply is

“data”: [
     {
      “question”: “Which soccer team won the Copa Am&eacute;rica 2015 Championship ? “,                                          
     }]

In SUSI Android this message looks like

As you can see that showing html tags without parsing distort the normal text flow. So we need to parse html tags properly. We use Html class for this purpose. Html class is present in android.text package and you can import it in the class where you want to use it.

import android.text.Html

fromHtml method of Html class is used to parse html tags. But for API level less than 24 and equal to or greater than 24 we use different parameters in fromHtml method.

For API level less than 24 we used

Html.fromHtml(model.getContent())

But for API level equal to or greater than 24 we have to use

Html.fromHtml(model.getContent(), Html.FROM_HTML_MODE_COMPACT)

Here the second parameter is legacy flags which decides how text inside a tag will be shown after parsing.

In case of Html.fromHtml(String string) legacy flag is by default FROM_HTML_MODE_LEGACY. It indicates that separate block-level elements with blank lines.

So after parsing html tags using fromHtml

But return type of fromHtml method is Spanned so if you need String then you have to convert it into string using toString() method.

Anchor action type in susi response contains link and text.

       “link”: “https://www.openstreetmap.org/#map=13/1.2896698812440377/103.85006683126556”,
       “text”: “Link to Openstreetmap: Singapore”

Here the text is the text we show in textview and link is used to show web content in the browser when user click on text. So first link and text are attached together like

“<a href=\”” +susiResponse.getAnswers().get(0).getActions().get(i).getAnchorLink() + “\”>”
+ susiResponse.getAnswers().get(0).getActions().get(1).getAnchorText() + “</a>”

Here text between the tag is description of link and after parsing we show this text in textview. It can be parsed using fromHtml method of Html class and textview is made clickable by

chatTextView.setMovementMethod(LinkMovementMethod.getInstance());

Resources

Reset Password Option in SUSI Android App

Login and signup are an important feature for some android apps like chat apps because the user will want to save and secure personal messages from others. In SUSI Android app we provide a token to a logged-in user for a limit period of time so that once the user logs in and someone else gets access to the device, then he/she can’t use the user account for a long period of time. It is a security provided from our side but the user also has to maintain some security. Cyber security risks have increased and hacking technologies have improved a lot in the past 10 years. So, using the same password for a long period of time absolutely puts your account security at risk. So to keep your account secure you should change/reset your password regularly. In this blog post, I will show you how reset password option is implemented in SUSI Android app.

Layout design for reset password

Reset password option is added in the setting. When the user clicks on reset password option a dialog box pops up. There are three textinputlayout boxes – each for the current password, new password and confirm password. I have used textinputlayout instead of simple edittext box because it helps user to show first “hint” and when user taps on, hint will come up with text over it as floating label so that the user can understand what to add in that box and also in case of error we can show that error to user.

Reset Password implementation

On clicking reset password option a dialog box appears in which user inserts the current password, new password and confirm password to confirm the new password. Before sending new password to the server we perform two checks

  1. New password should not be empty and length of new password should be at least six.
  2. New password and confirm password must be same.
if (!CredentialHelper.isPasswordValid(newPassword)) {

settingView?.passwordInvalid(Constant.NEW_PASSWORD)

return

}

if (newPassword != conPassword) {

settingView?.invalidCredentials(false, Constant.NEW_PASSWORD)

return

}

And when these two checks are passed we send “new password” to server.

Endpoint use to reset password is

http://api.susi.ai/aaa/changepassword.json?changepassword=your mail id&password=current password&newpassword=newpassword

As you can see it needed three parameters

  • changepassword: Your email id
  • password : Your current password
  • newpassword: Your new password

When user logs in, we save user’s email id so that the user doesn’t have to provide it again and again when the user wants to change the password.

utilModel.saveEmail(email)

The user provides current password and new password through dialog box. We used resetPassword method to reset the password. We send these three parameters to the server using resetPassword method and if the password changed successfully then server sends a message.

override fun resetPassword(password: String, newPassword: String, listener: ISettingModel.onSettingFinishListener) {

  val email = PrefManager.getString(Constant.SAVE_EMAIL, null)

  resetPasswordResponseCall = ClientBuilder().susiApi

          .resetPasswordResponse(email,password,newPassword)

  resetPasswordResponseCall.enqueue(object : Callback<ResetPasswordResponse> {

  } )

}

We used retrofit library for network call and resetPasswordResponse is a model class using which we are retrieving server response.

Reference

Using Firebase Test Lab for Testing test cases of Phimpme Android

As now we started writing some test cases for Phimpme Android. While running my instrumentation test case, I saw a tab of Cloud Testing in Android Studio. This is for Firebase Test Lab. Firebase Test Lab provides cloud-based infrastructure for testing Android apps. Everyone doesn’t have every devices of all the android versions. But testing on all of them is equally important.

How I used test lab in Phimpme

  • Run your first test on Firebase

Select Test Lab in your project on the left nav on the Firebase console, and then click Run a Robo test. The Robo test automatically explores your app on wide array of devices to find defects and report any crashes that occur. It doesn’t require you to write test cases. All you need is the app’s APK. Nothing else is needed to use Robo test.

Upload your Application’s APK (app-debug-unaligned.apk) in the next screen and click Continue

Configure the device selection, a wide range of devices and all API levels are present there. You can save the template for future use.

Click on start test to start testing. It will start the tests and show the real time progress as well.

  • Using Firebase Test Lab from Android Studio

It required Android Studio 2.0+. You needs to edit the configuration of Android Instrumentation test.

Select the Firebase Test Lab Device Matrix under the Target. You can configure Matrix, matrix is actually on what virtual and physical devices do you want to run your test. See the below screenshot for details.

Note: You need to enable the firebase in your project

So using test lab on firebase we can easily test the test cases on multiple devices and make our app more scalable.

Resources: