Integrating Stripe OAuth in Open Event Frontend

Why is Stripe Oauth needed in frontend? Open event allows organizers to add tickets and accepts payments for tickets through various modes for example, Credit card, Debit card, Netbanking and offline payments. Stripe allows users to accept payments into their linked accounts on various online platforms after they provide client secret and publishable key. So to enable online payments in open event, organizers were required to authenticate their stripe account. This is done through Stripe OAuth.

Flow of OAuth

To allow organizers to link their stripe account admin has to enable stripe under payment gateway in admin settings. Admin provides his client ID and secret key. Admin also sets the redirect URL for his app on the stripe dashboard. After enabling these settings organizer will see an option to link their stripe account to open event when they are creating an event with paid tickets.

Here is what open event frontend does when we click connect to stripe button:

  1. Opens a popup to allow organizer to fill his stripe credentials and authorize open event app to access their secret and publishable key.
  2. Once the organizer fills his credentials and authorizes open event app, open event frontend fetches organizers auth code and saves it to server.
  3. Server on receiving auth code from frontend makes a request to stripe using the auth code to retrieve the publishable key and secret key.
  4. Once these are fetched server saves this information against the event so that all payments for that event can go to the linked stripe account.

Implementing the Frontend portion:

  • Choosing the library:

After looking at various libraries that support OAuth for Ember applications we decided to use Torii. Torii is the library that allows the addition of OAuth for various social apps such as Facebook, Google and Stripe too. It allows writing a custom provider for OAuth in case we do not want to use clients for which torii provides supports by default.

  • Implementing Stripe Provider:

Default provider for stripe given by torii fetched the client ID and redirect URL from environment.js file. But since in open event we have already saved client id of admin in our database so we will extend default stripe provider and modify its client Id so that it fetches client id from server. Code for extending default provider is given here:

import stripeConnect from 'torii/providers/stripe-connect';
import { alias } from '@ember/object/computed';
import { inject } from '@ember/service';
import { configurable } from 'torii/configuration';

function currentUrl() {
 let url = [window.location.protocol,
   '//',
   window.location.host].join('');
 if (url.substr(-1) !== '/') {
   url += '/';
 }
 return url;
}

export default stripeConnect.extend({

 settings: inject(),

 clientId: alias('settings.stripeClientId'),

 redirectUri: configurable('redirectUri', function() {
   return `${currentUrl()}torii/redirect.html`;
 })

});

 

We have fetched clientId from our settings service as alias(‘settings.stripeClientId’).

We have already defined settings in our services so we just need to inject the service here to be able to use it.

By default torii provides redirect url as {currentUrl}/torii/redirect.html. But in open event frontend we allow organizers to edit information on two routes and torii suggests in its docs to use {baseUrl}/torii/redirect.html as the redirect url to avoid potential vulnerability. So we also modified the default redirect url building method.

Saving information to server

Once we get the authorization token from stripe we send it to the server and save it to stripe-authorization model. The logic for the same is given below:

connectStripe() {
     this.get('data.event.stripeAuthorization.content') ? '' : this.set('data.event.stripeAuthorization', this.store.createRecord('stripe-authorization'));
     this.get('torii').open('stripe')
       .then(authorization => {
         this.set('data.event.stripeAuthorization.stripeAuthCode', authorization.authorizationCode);
       })
       .catch(error => {
         this.get('notify').error(this.get('l10n').t(`${error.message}. Please try again`));
       });
   },

 

This action gets called when we click on connect to stripe button. This action calls the stripe provider and opens a popup to enable the organizer to authenticate his stripe account.
Full code for this can be seen here.

In this way we connect the stripe service to open event to allow the organizer to receive payments for his events.

Resources
  • Stripe : Documentation on Stripe-Connect : Link
  • Torii: Library to implement Oauth. : Link
  • Implementation: Link to PR showing its implementation : Link
Continue ReadingIntegrating Stripe OAuth in Open Event Frontend

Chrome Custom Tabs Integration – SUSI.AI Android App

Earlier, we have seen the apps having external links that opens and navigates the user to the phone browser when clicked, then we came up with something called WebView for Android, but nowadays we have shifted to something called In-App browsers. The main drawback of the system/ phone browsers are they caused heavy transition. To overcome this drawback “Chrome Custom Tabs” were invented which allowed users to walk through the web content seamlessly.

SUSI.AI Android App earlier used the system browser to open any link present in the app.

This can be implemented easily by

Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(browserIntent);

This lead to a huge transition between the context of the app and the web browser.

Then, to reduce all the clutter Chrome Custom tabs by Google was evolved which drastically increased the loading speed and the heavy context switch was also not taking place due to the integration and adaptability of custom tabs within the app.

Chrome custom tabs also are very secured like Chrome Browser and uses the same feature and give developers a more control on the custom actions, user interface within the app.

                                comparing the load time of the above mentioned techniques

Ref : Android Dev – Chrome Custom Tabs

Integration of Chrome Custom Tabs

  • Adding the dependency in build.gradle(app-level) in the project
dependencies {
    //Other dependencies 
    compile 'com.android.support:customtabs:23.4.0'
}
  • Now instantiating a CustomTabsIntent Builder

    String url = “https://www.fossasia.org” // can be any link
    
    CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); //custom tabs intent builder
    
    CustomTabsIntent customTabsIntent = builder.build();
  • We can also add animation or customize the color of the toolbar or add action buttons.

    builder.setColor(Color.RED) //for setting the color of the toolbar 
    builder.setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left); //for start animation
    builder.setExitAnimations(this, R.anim.slide_in_left, R.anim.slide_out_right); //for exit animation
  • Finally, we have have achieved everything with a little code. Final launch the web page

    Uri webpage = Uri.parse(url); //We have to pass an URI
    
    customTabsIntent.launchUrl(context, webpage); //launching through custom tabs

Benefits of Chrome Custom Tabs

  1. UI Customization are easily available and can be implemented with very few lines of code. 
  2. Faster page loading and in-app access of the external link 
  3. Animations for start/exit  
  4. Has security and uses the same permission model as in chrome browser.

Resources

  1. Chrome Custom Tabs:  https://developer.chrome.com/multidevice/android/customtabs
  2. Chrome Custom Tabs Github Repo: GitHub – GoogleChrome/custom-tabs-client: Chrome custom tabs
  3. Android Blog: Android Developers Blog: Chrome custom tabs smooth the transition
  4. Video: Chrome Custom Tabs: Displaying 3rd party content in your Android

 

Continue ReadingChrome Custom Tabs Integration – SUSI.AI Android App

Building PSLab Android app with Fdroid

Fdroid is a place for open source enthusiasts and developers to host their Free and Open Source Software (FOSS) for free and get more people onboard into their community. Hosting an app in Fdroid is not a fairly easy process just like hosting one in Google Play. We need to perform a set of build checks prior to making a merge request (which is similar to pull request in GitHub) in the fdroid-data GitLab repository. PSLab Android app by FOSSASIA has undergone through all these checks and tests and now ready to be published.

Setting up the fdroid-server and fdroid-data repositories is one thing. Building our app using the tools provided by fdroid is another thing. It will involve quite a few steps to get started. Fdroid requires all the apps need to be built using:

$ fdroid build -v -l org.fossasia.pslab

 

This will output a set of logs which tell us what went wrong in the builds. The usual one in a first time app is obviously the build is not taking place at all. The reason is our metadata file needs to be changed to initiate a build.

Build:<versioncode>,<versionname>
    commit=<commit which has the build mentioned in versioncode>
    subdir=app
    gradle=yes

 

When a metadata file is initially created, this build is disabled by default and commit is set to “?”. We need to fill in those blanks. Once completed, it will look like the snippet above. There can be many blocks of “Build” can be added to the end of metadata file as we are advancing and upgrading through the app. As an example, the latest PSLab Android app has the following metadata “Build” block:

Build:1.1.5,7
    commit=0a50834ccf9264615d275a26feaf555db42eb4eb
    subdir=app
    gradle=yes

 

In case of an update, add another “Build” block and mention the version you want to appear on the Fdroid repository as follows:

Auto Update Mode:Version v%v
Update Check Mode:Tags
Current Version:1.1.5
Current Version Code:7

 

Once it is all filled, run the build command once again. If you have properly set the environment in your local PC, build will end successfully assuming there were no Java or any other language syntax errors.

It is worth to mention few other facts which are common to Android software projects. Usually the source code is packed in a folder named “app” inside the repository and this is the common scenario if Android Studio builds up the project from scratch. If this “app” folder is one level below the root, that is “android/app”, the build instructions shown above will throw an error as it cannot find the project files.

The reason behind this is we have mentioned “subdir=app” in the metadata file. Change this to “subdir=android/app” and run the build again. The idea is to direct the build to find where the project files are.

Apart from that, the commit can be represented by a tag instead of a long commit hash. As an example, if we had merge commits in PSLab labeled as “v.<versioncode>”, we can simply use “commit=v.1.1.5” instead of the hash code. It is just a matter of readability.

Happy Coding!

Reference:

  1. Metadata : https://f-droid.org/docs/Build_Metadata_Reference/#Build
  2. PSLab Android app Fdroid : https://gitlab.com/fdroid/fdroiddata/merge_requests/3271/diffs
Continue ReadingBuilding PSLab Android app with Fdroid

Making a SUSI Skill to get details about bank from IFSC

We are going to make a SUSI skill that fetches information about a bank when the IFSC (Indian Financial System Code) is known. Here is a detailed explanation of how we going about doing this.

Getting started with the skill creation

API endpoint that returns the bank details

Before going to the skill development, we need to find an API that would return the bank details from the IFSC, On browsing through various open source projects. I found an apt endpoint by Razorpay. Razorpay is a payment gateway for India which allows businesses to accept, process and disburse payments with ease. The Github link  to the repository is https://github.com/razorpay/ifsc.

API endpoint –  https://ifsc.razorpay.com/<:ifsc>
Request type –  GET
Response type –  JSON

Now, head over to the SUSI Etherpad, which is the current SUSI Skill Development Environment and create a new Pad. 

Here, we need to define the skill in the Etherpad. We will now write rules/intents for the skill. An intent represents an action that fulfills a user’s spoken request.

Intents consist of 2 parts –

  • User query – It contains different patterns of query that user can ask.
  • Answer – It contains the possible answer to the user query.

The main intent that our skill focuses on is, returning the bank name and address from the IFSC code. Here is how it looks –

Name of bank with IFSC code * | Bank's name with IFSC code *
!example:Name of bank with IFSC code SBIN0007245
!expect: The name of bank is State Bank of India
!console:The name of bank with IFSC code $1$ is $object$
{
"url":"https://ifsc.razorpay.com/$1$",
"path":"$.BANK"
}
eol

Part-wise explanation of the intent

  • The first line contains the query pattern that the user can use while querying. You can see that a wildcard character (*) is used in the pattern. It contains the IFSC of the bank that we wish to know, and will later on use to fetch the details via the API.
  • The second line contains an example query, followed by third line that contains the expected answer.
  • Last part of the rule contains the answer that is fetched from an external API –  https://ifsc.razorpay.com/<:ifsc>  ,via the console service  provided by SUSI Skills. Here, <:ifsc> refers to the IFSC that the user wants to know about. We get it from the user query itself, and can access it by the variable name $1$ as it matches with the 1st wildcard present in the query. If there would be 2 wildcards, we could have accessed them by $1$ and $2$ respectively.
  • The console service provides us with an option to enter the url of the API that we want to hit and path of the key we want to use.

The sample response of the endpoint looks like this :

{
  "BANK": "Karnataka Bank",
  "IFSC": "KARB0000001",
  "BRANCH": "RTGS-HO",
  "ADDRESS": "REGD. & HEAD OFFICE, P.B.NO.599, MAHAVEER CIRCLE, KANKANADY, MANGALORE - 575002",
  "CONTACT": "2228222",
  "CITY": "DAKSHINA KANNADA",
  "RTGS": true,
  "DISTRICT": "MANGALORE",
  "STATE": "KARNATAKA"
}

 

  • Since, we want to extract the name of the bank, the BANK key contains our desired value and we will use $.BANK in the path of the console service. And it can be accessed by $object$ in the answer. We frame the answer using $object$ and $1$ variables, and it like the one mentioned in the expected answer. eol marks the end of the console service.
  • Similarly, the intent that gives us the address of the bank looks like this –
Address of bank with IFSC code * | Bank's address with IFSC code *
!example:Address of bank with IFSC code SBIN0007245
!expect: The address of bank is TILAK ROAD HAKIMPARA, P.O.SILIGURI DARJEELING, WEST BENGAL ,PIN - 734401
!console:The address of bank with IFSC code $1$ is $object$
{
  "url":"https://ifsc.razorpay.com/$1$",
  "path":"$.BANK"
}
eol

Testing the skill

  • Open any SUSI Client and then write dream <your dream name> so that dreaming is enabled for SUSI. We will write down dream ifsc. Once dreaming is enabled, you can now test any skills which you’ve made in your Etherpad.
  • We can test the skills by asking queries and matching it with the expected answer. Once the testing is done, write stop dreaming to disable dreaming for SUSI.

  • After the testing was successful completely, we will go ahead and add it to the susi_skill_data.
  • The general skill format is –
::name <Skill_name>
::author <author_name>
::author_url <author_url>
::description <description> 
::dynamic_content <Yes/No>
::developer_privacy_policy <link>
::image <image_url>
::term_of_use <link>

#Intent
User query1|query2|query3....
Answer answer1|answer2|answer3...

We will add the basic skill details and author details to the etherpad file and make it in the format as mentioned above. The final text file looks like this –

::name IFSC to Bank Details
::author Akshat Garg
::author_url https://github.com/akshatnitd
::description It is a bank lookup skill that takes in IFSC code from the user and provides you all the necessary details for the Bank. It is valid for banks in India only
::dynamic_content Yes
::developer_privacy_policy 
::image images/download.jpeg
::terms_of_use 

Name of bank with IFSC code * | Bank's name with IFSC code *
!example:bank with IFSC code *
!expect: The name of bank is SBI
!console:The name of bank with IFSC code $1$ is $object$
{
"url":"https://ifsc.razorpay.com/$1$",
"path":"$.BANK"
}
eol

Address of bank with IFSC code * | Bank's address with IFSC code *
!example:Address of bank with IFSC code *
!expect: The address of bank is 
!console:The address of bank with IFSC code $1$ is $object$
{
"url":"https://ifsc.razorpay.com/$1$",
"path":"$.ADDRESS"
}
eol

Submitting the skill

The final part is adding the skill to the list of skills for SUSI. We can do it by 2 ways:

1st method (using the web interface)

  • Open https://susi.skills.com and login into SUSI account (or sign up, if not done).
  • Click on the create skill button.
  • Select the appropriate fields like Category, Language, Skill name, Logo.
  • Paste the text file that we had created.
  • Add comments regarding the skill and click on Save to save the skill.

2nd method (sending a PR)

  • Send a Pull Request to susi_skill_data repository providing the dream name. The PR should have the text file containing the skill.

So, this was a short blog on how we can develop a SUSI skill of our choice.

Resources

Continue ReadingMaking a SUSI Skill to get details about bank from IFSC

Open Event Frontend – Updating Ember Models Table from V1 to V2

FOSSASIA‘s Open Event Frontend uses the Ember Models Table for rendering all its tables. This provides features like easy sorting, pagination etc. Another major feature is that it can be modified to meet our styling needs. As we use Semantic UI for styling, we added the required CSS classes to our table.

In version 1 this was done by overriding the classes, as shown below :

const defaultMessages = {
  searchLabel            : 'Search:',
  searchPlaceholder      : 'Search',


  ..... more to follow 
};

const defaultIcons = {
  sortAsc         : 'caret down icon',
  sortDesc        : 'caret up icon',
  columnVisible   : 'checkmark box icon',
  
  ..... more to follow  
};

const defaultCssClasses = {
  outerTableWrapper              : 'ui ui-table',
  innerTableWrapper              : 'ui segment column sixteen wide inner-table-wrapper',
  table                          : 'ui tablet stackable very basic table',
  globalFilterWrapper            : 'ui row',

 ... more to follow
};

const assign = Object.assign || assign;

export default TableComponent.extend({
  layout,

  _setupMessages: observer('customMessages', function() {
    const customIcons = getWithDefault(this, 'customMessages', {});
    let newMessages = {};
    assign(newMessages, defaultMessages, customIcons);
    set(this, 'messages', O.create(newMessages));
  }),

  _setupIcons() {
    const customIcons = getWithDefault(this, 'customIcons', {});
    let newIcons = {};
    assign(newIcons, defaultIcons, customIcons);
    set(this, 'icons', O.create(newIcons));
  },

  _setupClasses() {
    const customClasses = getWithDefault(this, 'customClasses', {});
    let newClasses = {};
    assign(newClasses, defaultCssClasses, customClasses);
    set(this, 'classes', O.create(newClasses));
  },

  simplePaginationTemplate: 'components/ui-table/simple-pagination',

  ........
});

And was used in the template as follows:

<div class="{{classes.outerTableWrapper}}">
  <div class="{{classes.globalFilterDropdownWrapper}}">

But in version 2, some major changes were introduced as follows:

  1. All partials inside a models-table were replaced with components
  2. models-table can now be used with block content
  3. New themes mechanism introduced for styling

Here, I will talk about how the theming mechanism has been changed. As I mentioned above, in version 1 we used custom classes and icons. In version 2 the idea itself has changed. A new type called Theme was added. It provides four themes out of the box – SemanticUI, Bootstrap4, Bootstrap3, Default.

We can create our custom theme based on any of the predefined themes. To suit our requirements we decided to modify the SemanticUI theme. We created a separate file to keep our custom theme so that code remains clean and short.

import Default from 'ember-models-table/themes/semanticui';

export default Default.extend({
 components: {
   'pagination-simple'    : 'components/ui-table/simple-pagination',
   'numericPagination'    : 'components/ui-table/numeric-pagination',
   .....  
 },

 classes: {
   outerTableWrapper              : 'ui ui-table',
   innerTableWrapper              : 'ui segment column sixteen wide inner-table-wrapper',
   .....
 },

 icons: {
   sortAsc         : 'caret down icon',
   sortDesc        : 'caret up icon',
   ......
 },

 messages: {
   searchLabel            : 'Search:',
   .....
 }
});

So a theme mostly consists of four main parts:

  • Components
  • Classes
  • Icons
  • Messages

The last three are same as customClasses and customIcons and customMessages in version 1. Components is the map for components used internally in the models-table. In case you need to use a custom component, that can be done as follows:

Make a new JavaScript file and provide its path in your theme file.

import DefaultDropdown from '../../columns-dropdown';
import layout from 'your layout file path';
export default DefaultDropdown.extend({
  layout
});

Now just create the theme file object and pass it to themeInstance in the ui-table file (can also be passed in the template and the controller, but this has to be done for each table individually).

import TableComponent from 'ember-models-table/components/models-table';
import layout from 'open-event-frontend/templates/components/ui-table';
import Semantic from 'open-event-frontend/themes/semantic';

export default TableComponent.extend({
 layout,

 themeInstance: Semantic.create()
});

Hence, version 2 introduces many new styling options and requires some refactoring for those who were using version 1. It is totally worth it though considering how easy and well managed it is now.

References

Continue ReadingOpen Event Frontend – Updating Ember Models Table from V1 to V2

Publish an Open Source app on Fdroid

Fdroid is a famous software repository hosted with numerous free and open source Android apps. They have a main repository where they allow developers hosting free and ad free software after a thorough check up on the app. This blog will tell you how to get your project hosted in their repository using steps I followed to publish the PSLab Android app.

Before you get started, make sure you have the consent from your developer community to publish their app on Fdroid. Fdroid requires your app to use all kind of open resources to implement features. If there is any closed source libraries in your app and you still want to publish it on Fdroid, you may have to reimplement that feature by any other mean without using closed source resources. They will also not allow to have Google’s proprietary “play-services” in your app along with proprietary ad services. You can find the complete inclusion policy document from their official page.

When your app is fully ready, you can get started with the inclusion procedure. Unlike how we are publishing apps on Google Play, publishing an app on Fdroid is as simple as sending a pull request to their main repository. That’s exactly what we have to do. In simple terms all we have to do is:

  1. Fork the Fdroid main data repository
  2. Make changes to their files to include our app
  3. Do a pull request

First of all you need a GitLab account as the Fdroid repository is hosted in GitLab. Once you are ready with a GitLab account, fork and clone the f-droid-data repository. The next step is to install the fdroid-server. This can be simply done using apt:

$ sudo apt install fdroidserver

Once that is done, go into the directory where you cloned the repository and run the following command to read current meta data where it saves all the information related to existing apps on Fdroid;

$ fdroid readmeta

This will list out various details about the current meta files. Next step is to add our app details into this meta file. This can be done easily using following command or you can manually create folders and files. But the following is safer;

$ fdroid import --url https://github.com/fossasia/pslab-android --subdir app

Replace the link to repository from the –url tag in the above command. For instance the following will be the link for fossasia-phimpme android;

$ fdroid import --url https://github.com/fossasia/phimpme-android --subdir app

This will create a file named as “org.fossasia.pslab” in the metadata directory. Open up this text file and we have to fill in our details.

  1. Categories
  2. License
  3. Web Site
  4. Summary
  5. Description

Description needs to be terminated with a newline and a dot to avoid build failures.

Once the file is filled up, run the following command to make sure that the metadata file is complete.

$ fdroid readmeta

Then run the following command to clean up the file

$ fdroid rewritemeta org.fossasia.pslab

We can automatically add version details using the following command:

$ fdroid checkupdates org.fossasia.pslab

Now run the lint test to see if the app is building correctly.

$ fdroid lint org.fossasia.pslab

If there are any errors thrown, fix them to get to the next step where we actually build the app:

$ fdroid build -v -l org.fossasia.pslab

Now you are ready to make the pull request which will then get reviewed by developers in Fdroid community to get it merged into their main branch. Make a commit and then push to your fork. From there it is pretty straightforward to make a pull request to the main repository. Once that is done, they will test the app for any insecurities. If all of them are passed, the app will be available in Fdroid!

Reference:

  1. Quick Start: https://gitlab.com/fdroid/fdroiddata/blob/master/README.md#quickstart
  2. Making merge requests: https://gitlab.com/fdroid/fdroiddata/blob/master/CONTRIBUTING.md#merge-requests
Continue ReadingPublish an Open Source app on Fdroid

Creating Logos for PSLab with KiCAD

We can make plenty of PCB designs using KiCAD, a powerful open source CAD tool. What makes them unique is customized logos and brand names. KiCAD offers us a feature to add logos in any of the silk screens; bottom or top. Rather than just a textual logos, a graphical logo makes the design look more unique just like the PSLab v5 revision.

The process is not a tedious task. We can simply start by getting the logo we want to add in the PCB silk screen. Just to make it more clear, silk screen is a paint made on top of the circuit board with all the markings and labels with a special ink. It will be either white or black according to user preference. As the first step, open the logo image file with inkscape.

We need to pre-process the image before we move onto KiCAD development space. The silk screen will have a black and white image as the input. It will convert all the black parts to invisible and white parts visible in the silk screen color. In that sense we have to color transform any logo into following format to get the desired output.

Once the logo image is ready, open KiCAD and from it’s toolbar;

Click and open “Bitmap2Component” icon which is similar to a “simple a”. This will open a window where you can import the logo image in png format.

In this figure, image height and width is massive. It is always a good practice to have a large image and then scale it down to prevent any detail losses. If the image is too big, from the “Resolution” section, try increasing the DPI value and observe the dimensions are shrinking. You can have a ruler and measure the actual size of the image you want and then adjust the DPI values to get the desired dimensions. In my case I had to use 2500×3000 DPI to get an image of 20mmx7mm,

The next step is to export the logo file. Click on the “Export” button and select the location to your custom component library and save the file in “kicad_mod” format.

Now open up “Pcbnew” layout where the PCB design is. From the toolbar to your right, click on the “Add footprint” icon.

A dialog box will pop up to select the component. Click on the button “Select by Browser” to get a more interactive selection menu or you can simply type the name if you remember it correctly.

From the component browser, browse to the library where you saved the kicad_mod file and import it to the layout. The final result will look like this. If the dimensions are not what you wanted, simply follow the previous steps again to increase the DPI values to get the correct dimensions. By pressing “f” you can flip the silk screen side, bottom or top to place the logo where ever you want.

Reference:

KiCAD Documentation: http://kicad-pcb.org/help/documentation/

Continue ReadingCreating Logos for PSLab with KiCAD

Implementing Clickable Images

PSLab Android application is a feature rich compact app to user interface the PSLab hardware device. Similarly the PSLab device itself is a compact device with a plenty of features to replace almost all the analytical instruments in a school science lab. When a first time user takes the device and connect it with the Android app, there are so many pins labeled with abbreviations. This creates lots of complications unless the user checks the pinout diagram separately.

As a workaround a UI is proposed to integrate a layout containing the PSLab PCB image where user can click on each pin to get a dialog box explaining him what that specific pin is and what it does. This implementation can be done it two ways;

  • Using an Image map
  • Using (x,y) coordinates

The first implementation is more practical and can be applied with any device with any dimension. The latter requires some transformation to capture the correct position when user has clicked on a pin. So the first method will be implemented.

The idea behind using an image map is to have two images with exact dimensions on top of each other. The topmost image will be the color map which we create ourselves using unique colors at unique heat points. This image will have the visibility setting invisible as the main idea is to let the  user see a meaningful image and capture the positions using a secondary in the back end.

To make things much clear, let’s have a look at a color map image I am suggesting here for a general case.

If we overlap the color map with the PSLab layout, we will be able to detect where user has clicked using Android onTouchEvent.

@Override
public boolean onTouchEvent(MotionEvent ev) {
   final int action = ev.getAction();
   final int evX = (int) ev.getX();
   final int evY = (int) ev.getY();
   switch (action) {
       case MotionEvent.ACTION_UP :
         int touchColor = getHotspotColor (R.id.backgroundMap, evX, evY);
         /* Display the relevant pin description dialog box here */
         break;
   }
   return true;
}

 
Color of the clicked position can be captured using the following code;

public int getHotspotColor (int hotspotId, int x, int y) {
   ImageView img = (ImageView) findViewById (hotspotId);
   img.setDrawingCacheEnabled(true);
   Bitmap hotspots = Bitmap.createBitmap(img.getDrawingCache());
   img.setDrawingCacheEnabled(false);
   return hotspots.getPixel(x, y);
}

 
If we go into details, from the onTouchEvent we capture the (x,y) coordinates related to user click. Then this location is looked up for a unique color by creating a temporary bitmap and then getting the pixel value at the captured coordinate.

There is an error in this method as the height parameter always have an offset. This offset is introduced by the status bar and the action bar of the application. If we use this method directly, there will be an exception thrown out saying image height is less than the height defined by y.

Solving this issue involves calculating status bar and actionbar heights separately and then subtract them from the y coordinate.

Actionbar and status bar heights can be calculated as follows;

Rect rectangle = new Rect();
Window window = getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectangle);
int statusBarHeight = rectangle.top;
int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int titleBarHeight= contentViewTop - statusBarHeight;

 
Using them, we can modify the captured coordinates as follows;

int touchColor = getHotspotColor (R.id.imageArea, evX, evY - statusBarHeight);

 
This way the exception is handled by adjusting the cursor position. Once this is done, it is all about displaying the correct pin description dialog box.

Reference:

Calculate status bar height: https://stackoverflow.com/questions/3407256/height-of-status-bar-in-android

Continue ReadingImplementing Clickable Images

Making Shapes with PSLab Oscilloscope

Looking back to history, the first ever video game was ‘Pong’ which was played on an analog oscilloscope with a very small screen. Oscilloscopes are not made to play video games, but by just tinkering around its basic functionality which is display waveforms, we can do plenty of cool things. PSLab device also has an oscilloscope; in fact it’s a four channel oscilloscope.

This blog post will show you how the oscilloscope in PSLab is not just a cheap oscilloscope but it has lots of functionalities an industry grade oscilloscope has (except for the bandwidth limitation to a maximum of 2 MHz)

To produce shapes like above figures, we are using another instrument available in PSLab. That is ‘Waveform Generator’. PSLab Waveform Generator can generate three different waveforms namely Sine waves, Triangular waves and Square waves ranging from 5 Hz to 5 kHz.

To get started, first connect two jumper wires between SI1-CH1 and SI2-CH2 pins. We needn’t worry about ground pins as they are already internally connected. Now it’s time to open up the PSLab oscilloscope. Here we are going to utilize two channels for this activity and they will be CH1 and CH2. Check the tick boxes in front of ‘Chan 1’ and ‘Chan 2’ and set ‘Range’ to “+/-4V” to have the maximum visibility filling the whole screen with the waveform.

The shapes are drawn using a special mode called ‘X-Y Mode’ in PSLab oscilloscope. In this mode, two channels will be plotted against their amplitudes at every point in time.

As it is already mentioned that PSLab can generate many waveform types and also they can have different phase angles relative to each other. They can have different independent frequencies. With all these combinations, we can tweak the settings in Waveform Generator to produce different cool shapes in PSLab oscilloscope.

These shapes can vary from basic geometric shapes such as circle, square, rectangle to complicated shapes such as rhombus, ellipse and polynomial curves.

Circle

A circular shape can be made by generating two sine waves having the same frequency but with a phase difference of 90 degrees or 270 degrees between the two wave forms.

 

 
 

 


Square

Square shape can be made by generating two triangular waveforms again having the same frequency but with a phase difference of either 90 degrees or 270 degrees between the two.

 

 

 
 


Rectangle

Similar to creating a Square, by having the same frequency for both triangular waveforms but a different phase angle greater than or less than 90 degree will do the trick.

 

 

 
 


Rhombus

Keeping the waveform settings same for the rectangle, by changing the amplitude of the SI1 waveform using the knob we can generate a rhombic shape on the XY graph plot.

 

 

 
 


Ellipse

Generating ellipse is also similar to creating a rhombus. But here we are using sine waves instead of triangular waves. By changing the amplitude of SI1 using the knob we can change the curvature.

 

 

 


Helix

Helix or spiral shape can be generated using two sine waves having same phase but two different frequencies. Frequencies better be integer multiples of the smaller frequency to  have a steady shape.

 

 

 


Parabola

Parabolic shapes can be generated by mixing up triangular waves with sine waves with different phase angles.

 

 

 

 
 

More random shapes


References:

https://www.aps.org/publications/apsnews/200810/physicshistory.cfm

Continue ReadingMaking Shapes with PSLab Oscilloscope

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