Deploying BadgeYaY with Docker on Docker Cloud

We already have a Dockerfile present in the repository but  there is problem in many lines of code.I studied about Docker and learned how It is deployed and I am now going to explain how I deployed BadgeYaY on Docker Cloud.

To make deploying of Badgeyay easier we are now supporting Docker based installation.

Before we start to deploy, let’s have a quick brief about what is docker and how it works ?

What is Docker ?

Docker is an open-source technology that allows you create, deploy, and run applications using containers. Docker allows you deploy technologies with many underlying components that must be installed and configured in a single, containerized instance.Docker makes it easier to create and deploy applications in an isolated environment.

Now, let’s start with how to deploy on docker cloud:

Step 1 – Installing Docker

Get the latest version of docker. See the offical site for installation info for your platform.

Step 2 – Create Dockerfile

With Docker, we can just grab a portable Python runtime as an image, no installation necessary. Then, our build can include the base Python image right alongside our app code, ensuring that our app, its dependencies, and the runtime, all travel together.

These portable images are defined by something called a Dockerfile.

In DockerFile, there are all the commands a user could call on the command line to assemble an image. Here’s is the Dockerfile of BadgeYaY.

# The FROM instruction initializes a new build stage and sets the Base Image for subsequent instructions.
FROM python:3.6

# We copy just the requirements.txt first to leverage Docker cache
COPY ./app/requirements.txt /app/


# The WORKDIR instruction sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile.
WORKDIR /app


# The RUN instruction will execute any commands in a new layer on top of the current image and commit the results.
RUN pip install -r requirements.txt


# The COPY instruction copies new files.
COPY . /app


# An ENTRYPOINT allows you to configure a container that will run as an executable.
ENTRYPOINT [ "python" ]

# The main purpose of a CMD is to provide defaults for an executing container.
CMD [ "main.py" ]

 

Step 3 – Build New Docker Image

sudo docker build -t badgeyay:latest .

 

When the command completed successfully, we can check the new image with the docker command below:

     sudo docker images

 

Step 4 – Run the app

Let’s run the app in the background, in detached mode:

 sudo docker run -d -p 5000:5000 badgeyay

 

We get the long container ID for our app and then are kicked back to our terminal.Our container is running in the background.Now use docker container stop to end the process, using the CONTAINER ID, like so :

 

docker container stop 1fa4ab2cf395

 

Step 5 – Publish the app.

Log in to the Docker public registry on your local machine.

docker login

 

Upload your tagged image to the repository:

docker push username/repository:tag

 

From now on, we can use docker run and run our app on any machine. No matter where docker run executes, it pulls your image, along with Python and all the dependencies from requirements.txt, and runs your code. It all travels together in a neat little package, and the host machine doesn’t have to install anything but Docker to run it.

Docker Cloud

Docker Cloud provides a hosted registry service with build and testing facilities for Dockerized application images; tools to help you set up and manage host infrastructure; and application lifecycle features to automate deploying (and redeploying) services created from images.

In BadgeYaY, we  also have a Deploy button button which directly deploys on Docker cloud with a single click .

The related PR of this work is https://github.com/fossasia/badgeyay/pull/401 .

Resources :

  • Docker documentation: Link
  • Get Started With Docker: Link
Continue ReadingDeploying BadgeYaY with Docker on Docker Cloud

Setting up Codecov in Badgeyay

 

BadgeYaY already has Travis CI and Codacy to test code quality and Pull Request but there was no support for testing Code Coverage in repository against every Pull Request. So I decided to go with setting up Codecov to test the code coverage.

In this blog post, I’ll be discussing how I have set up codecov in BadgeYaY in my Pull Request.

First, let’s understand what is codecov and why do we need it. For that we have to first understand what is code coverage then we will move on to how to add Codecov with help of Travis CI .

Let’s get started and understand it step by step.

What is Code Coverage ?

Code coverage is a measurement used to express which lines of code were executed by a test suite. We use three primary terms to describe each lines executed.

  • hit indicates that the source code was executed by the test suite.
  • partial indicates that the source code was not fully executed by the test suite; there are remaining branches that were not executed.
  • miss indicates that the source code was not executed by the test suite.

Coverage is the ratio of hits / (hit + partial + miss). A code base that has 5 lines executed by tests out of 12 total lines will receive a coverage ratio of 41% . In BadgeYaY , Code Coverage is 100%.

How CodeCov helps in Code Coverage ?

Codecov focuses on integration and promoting healthy pull requests. Codecov delivers <<<or “injects”>>> coverage metrics directly into the modern workflow to promote more code coverage, especially in pull requests where new features and bug fixes commonly occur.

I am listing down top 5 Codecov Features:

We can change the configuration of how Codecov processes reports and expresses coverage information. Let’s see how we configure it according to BadgeYaY by integrating it with Travis CI.

Now generally, the codecov works better with Travis CI. With the one line

 bash <(curl -s https://codecov.io/bash)

 

the code coverage can now be easily reported.

Add a script for testing:

"scripts": {
   - nosetests app/tests/test.py -v --with-coverage
}

Here is a particular example of travis.yml from the project repository of BadgeYaY:

Script:
- python app/main.py >> log.txt 2>&1  &
- nosetts app/tests/test.py -v --with-coverage
- python3 -m pyflakes

after_success:
- bash <(curl -s https://codecov.io/bash)

 

Let’s have a look at Codecov.yml to check exact configuration that I have used for BadgeYaY.

Codecov:
  # yes: will delay sending notifications until all ci is finished
  notify:
    require_ci_to_pass: yes

coverage:
  # how many decimal places to display in the UI: 0 <= value <= 4
  precision: 2
  # how coverage is rounded: down/up/nearest
  round: down 
  # custom range of coverage colors from red -> yellow -> green 
  range: "70...100"

  status:
     # measuring the overall project coverage
    project: yes
     # pull requests only: this commit status will measure the
       entire pull requests Coverage Diff. Checking if the lines
       adjusted are covered at least X%.
    patch: yes
     # if there are any unexpected changes in coverage
    changes: no

Comment:

  layout: "reach, diff, flags, files, footer"
  behavior: default
  require_changes: no

 

Now when anyone makes a Pull Request to BadgeYaY, Codecov will analyze the Pull Request according to above configuration and generate a Report showing the code coverage of that Pull Request.

 

Below is the screenshot of all test passing in BadgeYaY repository

This is how we setup codecov in BadgeYaY repository. And like this way, it can be set up in other repositories as well.

The related PR of this work is https://github.com/fossasia/badgeyay/pull/400

Resources :

  • CodeCov Documentation – Link
Continue ReadingSetting up Codecov in Badgeyay

FOSSASIA Summit 2018 Highlights

The schedule for the FOSSASIA Summit is out. Our four-day open tech event starts on Thursday, March 22 with a grand opening of the exhibition at 12:00 PM and the conference at 1:00 PM in the Lifelong Learning Institute.

Developers, engineers and business representatives from FOSS projects and companies are joining the event. Thank you to Google Cloud, Daimler, Indeed, Microsoft, JPMorgan and the many partners and supporters for helping us to make the summit possible!

As a reader of FOSSASIA news you get a 15% discount on your ticket if you book before March 14 (after that 10%) with this link.

Here are some highlights of the event and a glance at participating FOSS projects, organizations and companies.

Highlights of the FOSSASIA Summit 2018

  • 200+ Tech Speakers in 12 Tracks are confirmed. Learn about latest technologies and Open Source business models in the Blockchain track, find out how to analyze data more efficiently in the Artificial Intelligence track or see how to deploy solutions with Kubernetes in the Cloud from engineers at leading cloud providers.
  • Executive Keynotes about “Daimler’s Open Source Strategy”, and “Machine Learning with TensorFlow and Cloud ML”
  • Leadership Panels about “AI, Machine Learning, Cloud, and the Conversational Web: Where is it all going?”, “Making Money with FOSS” and “Open Source Education”
  • The Exhibition and Career Fair runs from Thursday (March 22) till Saturday (March 24) with more than 50 company and project booths, where you can learn about technologies, job opportunities and participate in hands-on labs. Free hall passes are available until March 14.
  • The UNESCO Open Science and Open Data Hackathon takes place on Saturday and Sunday (March 24/25). Tickets and registration are free. Awesome prizes are waiting for the winners.
  • We put together a Cloud Training Day for Business Professionals in cooperation with Google. Apply for your spot here.
  • At the Young Developers Day on Saturday (March 24) there are many hands-on workshops in the exhibition hall, where participants of any age can build their own hardware and experiment with our Pocket Science Lab.
  • Vast variety of Deep Tech Sessions in tracks such as Artificial Intelligence,  Cloud, Container, DevOps, Blockchain, Cybersecurity, Web and Mobile, Open Design, IoT, Hardware, Imaging, Kernel & Platform,  Science Tech and Education and more.

FOSS Organizations at the FOSSASIA Summit

Speakers at the event come from amazing Free/Open Source organizations and projects like Debian, CentOS, FreeBSD, Videolan/VLC, Linux Foundation, Open Source Initiative, Python Software Foundation, Wikimedia, KDE, Apache Software Foundation, Open Source Design, Drupal, OpenTech, Ethical Hacking Club, Pocket Science Lab, Oman FOSS Initiative, LikeCoin Foundation and many more.

Companies at the FOSSASIA Summit

Tech Companies present at the event are Daimler/Mercedes, Google, Microsoft, Samsung, Singapore Press Holding, J.P. Morgan, Indeed, UNESCO, Oracle/MySQL, Gandi.net, Lazada, Viseo, Grab, SUSI.AI, BareOS, Platform.sh, Ulicious, SAP, Thoughtworks, Autodesk, KPMG, VMWare, Lionsforge, Fujitsu, Zendesk, McKinsey, Iomedia, IBM, Collabora, Manulife, Tata Consultancy Services and many startups like KyberNetwork, DataKind, Ethereum, Kamailio, Go-Jek, Canaan, StopStalk, ConsenSys, Chibitronics, Status.im, Attores and many others.

Continue ReadingFOSSASIA Summit 2018 Highlights

Option to exclude albums in Phimpme Android Application

In the Phimpme Android Application, users can perform various operations on the albums available such as move, creating a .zip file of the album, rename an album, delete the album and much more. However one another important functionality that has been implemented in the application is the option to exclude album/albums. In this post we will be discussing how we achieved the functionality to exclude albums in Phimpme Android Application.

Step 1

First we need to keep track of the albums selected by the user to exclude. This can be done by storing the selected albums in an Arraylist<Album> which can be referred later when required for the process of exclusion. The storing of the albums can be done with the help of following lines of code.

private int toggleSelectAlbum(int index) {
if (dispAlbums.get(index) != null) {
  dispAlbums.get(index).setSelected(!dispAlbums.get(index).isSelected());
  if (dispAlbums.get(index).isSelected()) selectedAlbums.add(dispAlbums.get(index));
  else selectedAlbums.remove(dispAlbums.get(index));
}
return index;
}

Step 2

After the selected albums are stored in an Arraylist<Album>, a function call of excludeSelectedAlbums() of HandlingAlbums class is done passing in Context as the parameter. In the method excludeSelectedAlbums() the selected albums are retrieved from the Arraylist one by one and another method excludeAlbum() is called with the album, context being passed as the parameters. The code snippet performing the above operation is provided below.

public void excludeSelectedAlbums(Context context) {
for (Album selectedAlbum : selectedAlbums)
  excludeAlbum(context, selectedAlbum);
clearSelectedAlbums();
}

Step 3

Thereafter an instance of class CustomsAlbumHelper is created and excludeAlbum() method is called with path of the album passed as parameter, and the selected album is removed from the list containing the currently displayed albums. Code snippets for the above operations are provided below.

private void excludeAlbum(Context context, Album a) {
CustomAlbumsHelper h = CustomAlbumsHelper.getInstance(context);
h.excludeAlbum(a.getPath());
dispAlbums.remove(a);
}

Step 4

Now in the excludeAlbum() method of CustomsAlbumHelper class a writable instance of albums_settings sqlite database is obtained. A check is performed if the current album is present in the albums table or not, if not then a row representing the current album is created. Thereafter the excluded value for the current album in the table is updated to integer 1 denoting that the album is excluded. The code snippet required for the above mentioned operations are provided below.

public void excludeAlbum(String path) {
  SQLiteDatabase db = this.getWritableDatabase();
  checkAndCreateAlbum(db, path);
  ContentValues values = new ContentValues();
  values.put(ALBUM_EXCLUDED, 1);
  db.update(TABLE_ALBUMS, values, ALBUM_PATH+“=?”, new String[]{    path});
  db.close();
}

This is how we have achieved the functionality of excluding albums in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android GitHub repository listed in the resources section below.

The screenshot for the display of the excluded albums is provided below.

Resources

  1. Android Developer Guide –https://developer.android.com/training/data-storage/sqlite.html
  1. Github-Phimpme Android Repository –https://github.com/fossasia/phimpme-android/
  1. Sqlite Operations Tutorial – https://www.androidhive.info/2011/11/android-sqlite-database-tutorial/
Continue ReadingOption to exclude albums in Phimpme Android Application

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

Continue ReadingUNESCO Hackathon at FOSSASIA Summit in Singapore

Option to hide albums in Phimpme Android Application

In Phimpme Android Application, users can perform various operations on the albums available such as move, creating a .zip file for the album, delete the album, exclude an album, rename an album, pin an album to the top and more. However one another important functionality that has been added in the application is the option to hide  album/albums. So in this post I will be discussing how we achieved the functionality to hide albums in Phimpme Android Application.

Step 1

First we need to get the albums which are selected to be hidden. This can be done by storing the selected items in an Arraylist<Album> which will keep track of the users choice to hide albums. This can be achieved with the following lines of code.

private int toggleSelectAlbum(int index) {
if (dispAlbums.get(index) != null) {
  dispAlbums.get(index).setSelected(!dispAlbums.get(index).isSelected());
  if (dispAlbums.get(index).isSelected()) selectedAlbums.add(dispAlbums.get(index));
  else selectedAlbums.remove(dispAlbums.get(index));
}
return index;
}

Step 2

After storing of the albums to be hidden a function hideSelectedAlbums() is called with Context being passed as the parameter. Now inside this function we retrieve the albums looping through the Arraylist that stores the albums to be hidden and call another function hideAlbum() passing in the album and context as the parameters. The code snippet representing the above operation is given below.

public void hideSelectedAlbums(Context context) {
for (Album selectedAlbum : selectedAlbums)
  hideAlbum(selectedAlbum, context);
clearSelectedAlbums();
}

Step 3.

Now a .nomedia file is added to the directories/albums which are to be hidden and the android Media Scanner System service is triggered thereafter. As a result of the presence of the .nomedia file inside the directory the Media Scanner service won’t scan the particular directory/album thereby the album will not be picked up at the time of displaying the albums. The code snippet to perform the mentioned operation is provided below.

File dirName = new File(path);
File file = new File(dirName, “.nomedia”);
if (!file.exists()) {
try {
  FileOutputStream out = new FileOutputStream(file);
  out.flush();
  out.close();
  scanFile(context, new String[]{ file.getAbsolutePath() });
} catch (Exception e) {
  e.printStackTrace();
}
}

The screenshot for the display of hidden folders is provided below.

This is how we have achieved the functionality of hiding albums in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android GitHub repository listed in the resources section below.

Resources

  1. Android Developer Guide – https://developer.android.com/reference/android/media/MediaScannerConnection.html
  2. Github-Phimpme Android Repository –https://github.com/fossasia/phimpme-android/
  3. Hiding directories using .nomedia file – http://www.easycodeway.com/2016/08/hide-files-in-android-using-nomedia-file.html
Continue ReadingOption to hide albums in Phimpme Android Application

Maintaining Extension State in SUSI.AI Chrome Bot Using Chrome Storage API

SUSI Chrome Bot is a browser action chrome extension which is used to communicate with SUSI AI.The browser action extension in chrome is like any other web app that you visit. It will store all your preferences like theme settings and speech synthesis settings and data till you are interacting with it, but once you close it, it forgets all of your data unless you are saving it in some database or you are using cookies for the session. We want to be able to save the chats and other preferences like theme settings the user makes when interacting with SUSI AI through Susi Chrome Bot. In this blog, we’ll explore Chrome’s chrome.storage API for storing data.

What options do we have for storing data offline?

IndexedDB: IndexedDB is a low-level API for client-side storage of data. IndexedDB allows us to store a large amount of data and works like RDBMS but IndexedDB is javascript based Object-oriented database.

localStorage API: localStorage allows us to store data in key/value pairs which is much more effective than storing data in cookies. localStorage data persists even if the user closes and reopens the browser.

Chrome.storage: Chrome provides us with chrome.storage. It provides the same storage capabilities as localStorage API with some advantages.

For susi_chromebot we will use chrome.storage because of the following advantages it has over the localstorage API:

  1. User data can be automatically synced with Chrome sync if the user is logged in.
  2. The extension’s content scripts can directly access user data without the need for a background page.
  3. A user’s extension settings can be persisted even when using incognito mode.
  4. It’s asynchronous so bulk read and write operations are faster than the serial and blocking localStorage API.
  5. User data can be stored as objects whereas the localStorage API stores data in strings.

Integrating chrome.storage to susi_chromebot for storing chat data

To use chrome.storage we first need to declare the necessary permission in the extension’s manifest file. Add “storage” in the permissions key inside the manifest file.

"permissions": [
         "storage"
       ]

 

We want to store the chat user has made with SUSI. We will use a Javascript object to store the chat data.

var storageObj = {
senderClass: "",
content: ""
};

The storageObj object has two keys namely senderClass and content. The senderClass key represents the sender of the message(user or susi) whereas the content key holds the actual content of the message.

We will use chrome.storage.get and chrome.storage.set methods to store and retrieve data.

var susimessage = newDiv.innerHTML;
storageObj.content = susimessage;
storageObj.senderClass = "susinewmessage";
chrome.storage.sync.get("message",(items) => {
if(items.message){
storageArr = items.message;
}
storageArr.push(storageObj);
chrome.storage.sync.set({"message":storageArr},() => {
console.log("saved");
});
});

 

In the above code snippet, susimessage contains the actual message content sent by the SUSI server. We then set the correct properties of the storageObj object that we declared earlier. Now we can use chrome.storage.set to save the storageObj object but that would overwrite the current data that we have inside chrome’s StorageArea. To prevent the old message data from getting overwritten, we’ll first get all the message content in our storage using chrome.storage.sync.get. Notice how we are passing the “message” string as the first perimeter to the function. This is done because we only want our message content which was saved in the StorageArea. If we pass null instead, it will return all the content inside storageArea. Once we have our messages (which will be an array of objects that we store as storageObj), we will store that into a new array storageArr. We will then push our new storageObj that contains the message and the sender into the array. Finally, we use chrome.storage.sync.set to save the message content in chrome’s StorageArea which can later be retrieved using the “message” key.

storageArr.push(storageObj);
chrome.storage.sync.set({"message":storageArr},() => {
console.log("saved");
});

We use the same procedure to save messages sent by the user.

Note: chrome.storage is not very large, so we need to be careful about what we store or we may run out of storage space. Also, we should not store confidential data in storage since the storage area is not encrypted.

Resources:

Tags:

  • FOSSASIA, codeheat, Chrome extensions, Javascript, Chrome Storage, Chrome Sync, Susi Chrome Bot, SUSI AI, Bot Development
Continue ReadingMaintaining Extension State in SUSI.AI Chrome Bot Using Chrome Storage API

Displaying Image location Address In Phimpme Android Application

In Phimpme Android application one of the features available is to view the details of any image. The details consists of attributes including Date and time at which the image was captured, size of the image, title, path, EXIF data, description added to the image, location etc. However in the location attribute the location coordinates of the image as well as the location address can be displayed depending on the user’s preference. The process of obtaining the coordinates from address is called as Geocoding and obtaining string address from coordinates is called reverse Geocoding. So in this post I will be explaining how to implement set of strings denoting the address from the available coordinates.

Step 1

First we need to create an instance of the class Geocoder passing context and function Locale.getDefault() as the parameters.  The function of the attribute Locale.getdefault is provided below.

Locale.getDefault() – It returns the current value of the default locale for the current instance of the Java Virtual Machine. The Java Virtual Machine sets the default locale during startup based on the host environment.The code snippet to perform the above mentioned operation is given below.

Geocoder geocoder = new Geocoder(context, Locale.getDefault());

Step 2

Now a function call of getFromLocation() of the Geocoder class is done where we need to pass the Lattitude and Longitude values of the Location object as parameters. The lattitude and longitudes values can be obtained by the use of the Location object functions getLatitude() and getLongitude() respectively. The function getFromLocation() will return a list of Address objects which will contain the extracted addresses from the passed latitude and longitude values. We also need to pass a third parameter an integer value which will determine the maximum no of addresses to be returned. Here we have requested for a maximum of one address. The following code snippet is used to perform the desired function call.

try {
 List<Address> addressList = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
} catch (IOException e) {
  e.printStackTrace();
}

Step 3

After obtaining the list of Address objects returned from the function call of getFromLocation() we will extract the first address from the list since we want a maximum of 1 address. The Address object will contain information like the address name, country, state, postal code etc. Now the set of strings describing the location can be retrieved with the help of the function getMaxAddressLineIndex() of Address class. The code snippets to perform the above mentioned operations is provided below.

ArrayList<String> addresslines = new ArrayList<String>();
Address address = addressList.get(0);
for(int i = 0; i <= address.getMaxAddressLineIndex(); i++) {
  addresslines.add(address.getAddressLine(i));
}
details.put(context.getString(R.string.location), TextUtils.join(System.getProperty(“line.separator”),
      addresslines));

The screenshot displaying the location address is provided below.

This is how we have achieved the functionality of displaying location address in a set of strings from available coordinates in the Phimpme Android application. To get the full source code, please refer to the Phimpme Android GitHub repository listed in the resources section below.

Resources

1.Android Developer Guide – https://developer.android.com/training/location/display-address.html

2.Github-Phimpme Android Repository – https://github.com/fossasia/phimpme-android/

3.Address Class Guide- https://developer.android.com/reference/android/location/Address.html

 

Continue ReadingDisplaying Image location Address In Phimpme Android Application

Leak Canary in Phimpme Android

Leak Canary is a memory detection library for Android and Java. A memory leak occurs when you hold an object for too long after its purpose has been served. If some object is holding another object then the Garbage collector will not be able to collect and this is known as Memory Leak. These memory leaks can be minor (in KB’s) or can lead to an app in ANR state with OutOfMemoryError.Hence to recover and capture this memory leak, Leak Canary is used for Android and Java.

For every functioning done in android, the system needs resource such as memory. Hence in Java the Garbage Collector(GC) plays a major role in deallocating the memory. The GC is mainly used to reclaim memory. Now the question arises, why do we need a memory leak detection library when GC is already present. The answer is sometimes the developers makes programming mistakes and that leads to inhibit the GC to collect the objects that are of no use and mark them as useful objects.

The GC starts from one point(root) and marks active to all the objects that holds references from GC root and the objects which are not marked are wiped out of memory.Hence when some unuseful objects is marked active, memory leak occurs.Hence to eliminate these problems  of memory leaks, we have employed the use of Leak Canary in our project.

The Phimpme project and every related project has possible memory leaks, like for instance we have used fragments in settings activity and to catch that memory leak we have added the refwatcher instance. Hence if any memory leaks occur we get the error such as ‘org.fossasia.phimpme’  leaked 40kb.This can also be checked by Leaks App in the android phone, which has features of showing and sharing the heap dump and info.

To add the Leak Canary in your android app, follow these steps:

  • Add the dependencies in build.gradle(app level)

    dependencies {
       debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
       releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
     }
  • Add the following code to your Application class

    public class MyApplication extends Application{
    @Override
    public void onCreate() {
       if (LeakCanary.isInAnalyzerProcess(this)) {
           // This process is dedicated to LeakCanary for heap analysis.
           // You should not init your app in this process.
           return;
       }
       LeakCanary.install(this);
    }
    
  • Leak canary now will automatically detect the memory leaks  from all activities.

For fragment a refwatcher is needed, hence

public class MYFragment extends Fragment {
    ...

    @Override
    public void onDestroy() {
        super.onDestroy();
        MainApplication.getRefWatcher(getActivity()).watch(this);
    }
}

Hence LeakCanary is setup finally, and now the memory leaks will be detected.

Resources

 

Continue ReadingLeak Canary in Phimpme Android

Adding Map Type Response to SUSI.AI Chromebot

SUSI.AI Chromebot has almost all sorts of reply that SUSI.AI Server can generate. But it still missed the Map Type response that was generated by the SUSI.AI Server.

This blog explains how the map type response was added to the chromebot.

Brief Introduction

The original issue was planned by Manish Devgan and Mohit Sharma as an advanced task for Google Code-In 2017. The link to which can be found here: #157

For a long time the issue remained untouched and after GCI got over I assigned the issue to myself as it was a priority issue since MAP type was a major response from the SUSI.AI Server.

How was Map Type response added?

There were a lot of things to be taken in mind before starting working on this issue.

  • Changing code scheme during GCI and other PRs
  • API Response from the SUSI.AI Server
  • Understanding the new codebase that got altered during GCI-17
  • Doing it quick

I will go through all the steps in detail

Changing Code Scheme

The code was altered numerous times with the addition of a number of pull requests during GCI-17 and there were no docstrings for any functions and methods. So I had to figure them out in order to start working on the map type response.

API Response from the SUSI.AI Server

To understand the JSON that server sent, I went to SUSI.AI API and did a simple search for

“Where is Berlin?” and the response generated is given below.

( Since the JSON is very big I am only posting the relevant data for this issue )

 

    "actions": [
      {
        "type": "answer",
        "language": "en",
        "expression": "Berlin (, German: [bɛɐ̯ˈliːn] ( listen)) is the capital and the largest city of Germany as well as one of its 16 constituent states."
      },
      {
        "type": "anchor",
        "link": "https://www.openstreetmap.org/#map=13/52.52436820069531/13.41053001275776",
        "text": "Here is a map",
        "language": "en"
      },
      {
        "type": "map",
        "latitude": "52.52436820069531",
        "longitude": "13.41053001275776",
        "zoom": "13",
        "language": "en"
      }
    ]

 

Here we see and understand that “actions” is an Array of JSONs and the third part has “type” as “map”. This is the relevant information that we require for generating the map-type response.

The important variables in this context are: “latitude” and “longitude”.

Understanding the Codebase

Now I had to figure out the new pattern of adding response types to the SUSI.AI Chromebot.

After having a talk with @ms10398 I figured out the route map.

The above image shows the correct flow of Javascript Code that generated the response. After this, I was good to go and start my work.

Adding the Map-Type Response

To start with I chose “LEAFLET.JS” as the Javascript Library that will be used to create maps.

  • So I added the LEAFLET.JS to the JS folder.
  • Now changes were made to the “index.html” file

 

<link rel=”stylesheet” href=”https://unpkg.com/leaflet@1.3.1/dist/leaflet.css” />

http://”js/leaflet.js”

 

Appropriate CSS was added along with a link to leaflet.js was added.

  • Adding CSS to the “mapClass
.mapClass{

    height : 200px;

    width : 200px;

}

 

  • Generating Maps with dynamic IDs

This part was where I applied brain, as to add the map to any div we required the div to have a proper and unique ID and so a way to generate unique IDs for div without using any external source was to be thought of.

I came with idea of using timestamp, as it will always be unique.

var timeStamp = new Date.now().toString();

 

Then I created the “composeMapReply()” function.

function composeReplyMap(response, action){

    var newDiv = messages.childNodes[messages.childElementCount];

    var mapDiv = document.createElement(“div”);

    var mapDivId = Date.now().toString();

    mapDiv.setAttribute(“id”, mapDivId);

    mapDiv.setAttribute(“class”, “mapClass”);

    newDiv.appendChild(mapDiv);

    messages.appendChild(newDiv);

    var newMap = L.map(mapDivId).setView([Number(action.latitude), Number(action.longitude)], 13);

 L.tileLayer(“https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}”,{

    /*

        This part contains the data for api call.

    */

}).addTo(newMap);

response.isMap = true;

response.newMap = mapDiv;

return response

    

}

 

The complete code can be found: here

At last after adding so many snippets of code we were able to generate the Map-Type response for SUSI.AI Chromebot

GIF

A gif showing the Map-Type response in action.

 

Resources

 

Continue ReadingAdding Map Type Response to SUSI.AI Chromebot