Face detection in Phimpme Android’s Camera

The Phimpme Android application comes with a well-featured camera application which offers almost all the functionality an advanced camera user searches for. It comes with a wide range of options to apply different scene modes in the camera and also to detect the faces using the front or the back camera of the device. In this tutorial, I will be discussing how we achieved the face detection functionality in Phimpme.

In the Phimpme application, we have the option in the settings to enable the face detection just as depicted in the screenshot below. After enabling it the Camera starts detecting the faces and draws rectangular boxes on the number of faces detected by the camera.

I will be explaining step by step to achieve this using some code snippets.

Step 1

First, we have to check whether our device supports the face detection functionality to avoid unnecessary application crashes using the Android’s Camera.Parameters class.

After the check we have to create a new class named My FaceDetectionListener which will be implementing the Android’s Camera.FaceDetectionListener. The face detection class overrides the function onFaceDetection and passes the array of Faces detected and the camera as the parameter to this function.

class MyFaceDetectionListener implements CameraController.FaceDetectionListener {
  @Override  
  public void onFaceDetection(CameraController.Face[] faces) { 
    faces_detected = new CameraController.Face[faces.length];     System.arraycopy(faces, 0, faces_detected, 0, faces.length);
  }
 }

Step 2

After creating this class, we need to start the camera of the application to set the face detection listener to it. This can be done by the code snippet provided below

camera = Camera.open(cameraId);

We can open the front camera and the back camera by simply changing the cameraId. If we want to open the front camera, then we need to set the camera Id value as 1 and if we want the back camera to open up we can set the camera Id to be 0.
After this, we can set the face detection listener in the camera. This can be done using the below code snippet.

mCamera.setFaceDetectionListener(fDetectionListener);
   mCamera.startFaceDetection();

The set face detection listener function takes in the object of the class we created in step 1 as the parameter and calls the Android’s pre defined function to start the face detection. The object of the class we created in step 1 can be created and initialised with the help of code snippet below.

MyFaceDetectionListener fDListener = new MyFaceDetectionListener();

After we have set the detection listener in the camera, as soon as it detects the face, it will call the overridden function onFaceDetection but how do the user know if the face has been detected or not. For this we have to create a rectangular box of size approximately that of the face detected. This can be done with the following code snippet.

int l = faces[i].rect.left;
               int r = faces[i].rect.right;
               int t = faces[i].rect.top;
               int b = faces[i].rect.bottom;
               Rect uRect = new Rect(l0, t0, r0, b0);

To get the full source code, please check out the Phimpme Android github repository.

Resources

  1. Phimpme Android Github repository
  2. Complete tutorial on face detection in Android
  3. Leafpic github repository
  4. Android Camera API Google developer page
Continue ReadingFace detection in Phimpme Android’s Camera

Multiple Color Effects in Phimpme Camera

The Phimpme Android’s camera comes with an option to switch between various color effects along with various other functionalities. To select different color modes, we have added a toggle button at the top right corner of the camera interface and which switches from the range of color effect available and on long clicking the toggle button, it resets the effect to normal. To show the functionality of the toggle button we have made use of the Showcase view in the application which displays all the functionality of the toggle button on the first run of the application.

In this tutorial, I will be discussing how we implemented the color effects feature in the Phimpme Android application with the help of some code snippets.

Step 1

Firstly we have to create a toggle button in the camera interface and have to set the onclicklistener on it to change the various color effects on the button click. This can be done with the following code snippet.

toggle.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
       //Actions here
}

Similarly, we have to set the long click listener on the toggle button which will handle the reset color effects function in the application.

Step 2

The next thing we need is to extract all the color modes supported by the device and to create an Arraylist of it so that we can call the respective values by just increasing the index on toggle button click. This can be done with the help of the following code snippet.

Now we have all the supported color modes along with the normal mode stored in the values list. For instance,

  1. Mono
  2. Negative
  3. Solarize
  4. Sepia
  5. Neon

Hence on button click, we have to get the color values using the list index and we have to set the value to the camera parameter from where we extracted the supported color effects.

For this, we can make use of a static variable named colorNum and initialise it with 0 and on button click we can just increment this variable by 1 and can set the color effect using the code snippet provided below

final String color = colorEffect.get(colorNum);
CameraController.SupportedValues supported_values = camera_controller.setColorEffect(color);
if (supported_values != null) {
    color_effects = supported_values.values;
   applicationInterface.setColorEffectPref(supported_values.selected_value);
}

And on the long click listener method of the camera, we can set the value of the variable to be 0 and can set the color values accordingly.

To get the full source code on changing the color effects in the camera and to know about adding the showcase view which we have used in this to show the functionality. Please refer to the Phimpme Android repository.

Resources

  1. Open camera Github repository
  2. Color effects in Android camera
  3. Camera API developer page
  4. Amlcurran Showcaseview

 

Continue ReadingMultiple Color Effects in Phimpme Camera

Authentication in SUSI.AI

Authentication is a part of AAA system which stands for Authentication, Authorization and Accounting System. In this blog, we will see how SUSI.AI authenticates its client. Let’s first see what each term of AAA means

  • Authentication : Authentication means identifying individual user with some unique information. Susi uses email addresses for non-anonymous identity and  anonymous identity users  are identified by their host name.
  • Authorization : It refers to identifying the access rights of the user and granting permissions depending on the user’s authorization level. In Susi we have BaseUserRole as   
    • ANONYMOUS  users who have not logged in
    • USER                  logged in Users
    • PRIVILEGED       users with special rights, like. moderators
    • ADMIN              maximum right, that user is allowed to do everything . Depending on the useroles, permissions are specified.
  • Accounting : Accounting is referred as keeping track of user’s activity. Susi Server uses DAO in which accounting object is stored as JSONTray. Susi also remembers the chat log of a user.

Now that we have basic idea about AAA, let’s check how Susi authenticates its user.

public class ClientIdentity extends Client {
    
    public enum Type {
        email(true), // non-anonymous identity
        host(false); // anonymous identity users which do not authentify; they are identified by their host name
        private final boolean persistent;
      }

}

Susi has ClientIdentity class which extends to base class Client, which has a string sufficient to identify an user. The user are represented with Objects of this class. The client identification string is defined as <typeName: untypedId> pair where <typeName> denotes an authentication method and <untypedId> a name within that authentication domain.

public class Authentication {

    private JsonTray parent;
    private JSONObject json;
    private ClientCredential credential;
...
}

This credential is used as key in DAO.authentication. Parent is used for the storage object , it is null if there is no parent file (no persistency). The DAO uses credential key and implements methods like getAuthentication, getAuthorization,getAccounting taking Non null parameter ClientIdentity and returns the object of respective classes. The method setExpireTime sets an expire time for anonymous users and tokens after end of duration in time seconds passed as parameter the Authentication expires.

public class DAO {
// AAA Schema for server usage
    private static JsonTray authentication;
    private static JsonTray authorization;
    private static JsonTray accounting;
    public  static UserRoles userRoles;
..
}

The JsonTray is class to hold the volume as <String,JsonObject> pairs as a Json file. The UserRequests  class holds all the user activities. The ClientIdentity class extend the base class Client and provides an Identification String for authentication of users.

public abstract class AbstractAPIHandler extends HttpServlet implements APIHandler {
    @Override
    public abstract BaseUserRole getMinimalBaseUserRole();

}

The AbstractAPIHandler checks the permissions of the user using the userroles of and comparing it with the value minimum base role of each servlet. Thus to specify the user permission for a servlet one just need to extend servlet to AbstractAPIHandler and  Override the getMinimalBaseUserRole method.

 public static ClientIdentity getIdentity(HttpServletRequest request, HttpServletResponse response, Query query) {

if(authentication.getIdentity() != null && authentication.checkExpireTime())   // check if login cookie is set
return authentication.getIdentity();
else if(request.getSession().getAttribute("identity") != null){ // check session is set
return (ClientIdentity) request.getSession().getAttribute("identity");
else if (request.getParameter("access_token") != null){ // check if access_token is valid
 return authentication.getIdentity();
else
 return getAnonymousIdentity(query.getClientHost());
}

It also implements method getIdentity()  which checks a request for valid login data, an existing session, a cookie or an access token and returns user identity if some login is active, otherwise the anonymous identity.  

This is how Susi uses credential to authenticate users and use it for accounting and authorization. The endpoints provided by server are used by Android and web clients. Susi accounts service is at  http://accounts.susi.ai. For more details do visit code repository and join gitter chat channel for discussions.

Resources

Continue ReadingAuthentication in SUSI.AI

Adding Unit Test For Local JSON Parsing in Open Event Android App

The Open Event project uses JSON format for transferring event information like tracks, sessions, microlocations and other. The event exported in the zip format from the Open Event server also contains the data in JSON format. The Open Event Android application uses this JSON data. Before we use this data in the app, we have to parse the data to get Java objects that can be used for populating views. There is a chance that the model and the JSON format changes in future. It is necessary that the models are able to parse the JSON data and the change in the model or JSON format don’t break JSON parsing.  In this post I explain how to unit test local JSON parsing so that we can ensure that the models are able to parse the local JSON sample data successfully.

Firstly we need to access assets from the main source set into the unit test. There is no way to directly access assets from main source set. We need to first add assets in test/resources directory. If assets are present in test/resources directory then we can use it using ClassLoader in the unit test. But we can’t just copy assets from the main source set to resources directory. If there is any change in sample JSON then we need to maintain both resources and it may make the sample inconsistent. We need to make assets shared.

Add the following code in the app level build.gradle file.

android {
    ...
    sourceSets.test.resources.srcDirs += ["src/main/assets"]
}

It will add src/main/assets as a source directory for test/resources directory.So after building the project the test will have access to the assets.

Create readFile() method

Now create a method readFile(String name) which takes a filename as a parameter and returns data of the file as a string.

private String readFile(String name) throws IOException {
        String json = "";
        try {
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(name);
            int size = inputStream.available();
            byte[] buffer = new byte[size];
            inputStream.read(buffer);
            inputStream.close();
            json = new String(buffer, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return json;
}

Here the getResourceAsStream() function is used to open file as a InputStream. Then we are creating byte array object of size same as inputStream data. Using read function we are storing data of file into byte array. After this we are creating a String object using a byte array.

Create ObjectMapper object

Create and initialize an ObjectMapper object in the Test class.

private ObjectMapper objectMapper;

    @Before
    public void setUp() {
        objectMapper = OpenEventApp.getObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
}

Here setting DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES to true is very important. It will fail the test for any unrecognized fields in the sample.

Create doModelDeserialization() method

In the Open Event Android App we are using Jackson for JSON serialization and deserialization. Converting JSON data to java is called deserialization or parsing.

Now create doModelDeserialization() method which takes three parameters,

  • Class<T> type: Model Class type of the data
  • String name: Name of the JSON data file
  • boolean isList: true if JSON string contains the list of object else false

This method returns true if parsing is successful and false if there is any error in parsing.

private <T> boolean doModelDeserialization(Class<T> type, String name, boolean isList) throws IOException {
        if (isList) {
            List<T> items = objectMapper.readValue(readFile(name), objectMapper.getTypeFactory().constructCollectionType(List.class, type));
            if (items == null)
                return false;
        } else {
            T item = objectMapper.readValue(readFile(name), type);
            if (item == null)
                return false;
        }
        return true;
}

Here ObjectMapper is doing the main work of parsing data and returns parsed object using readValue() method.

Add Test

Now all the setup is done we just need to assert value returned by doModelDeserialization() method by passing appropriate parameters.

@Test
public void testLocalJsonDeserialization() throws IOException {
        assertTrue(doModelDeserialization(Event.class, "event", false));
        assertTrue(doModelDeserialization(Microlocation.class, "microlocations", true));
        assertTrue(doModelDeserialization(Sponsor.class, "sponsors", true));
        assertTrue(doModelDeserialization(Track.class, "tracks", true));
        assertTrue(doModelDeserialization(SessionType.class, "session_types", true));
        assertTrue(doModelDeserialization(Session.class, "sessions", true));
        assertTrue(doModelDeserialization(Speaker.class, "speakers", true));
}

Here only event JSON file doesn’t have a list of the objects so passing false as isList parameter for others we are passing true because its data contains a list of objects.

Conclusion:

Running unit tests after every build helps you to quickly catch and fix software regressions introduced by code changes to your app

Continue ReadingAdding Unit Test For Local JSON Parsing in Open Event Android App

Generic Social Links Implementation in Open Event Android App

The Open Event Android App has an About Fragment which displays all the info about the event like name, time, location etc. It also shows social media buttons for the event. The problem was that the implementation of showing the social media buttons was not generic. The implementation was working fine for current FOSSASIA sample. If we generate the app for other events it creates a problem. It shows static buttons without proper mapping from social media button to social media link which creates a problem like on clicking GitHub button it opens Facebook link (issue #1792).

One solution to this problem is to implement recyclerview with social media buttons. In this post I explain how I have made social links implementation generic using RecyclerView.

Add RecyclerView in layout

The first step to do is to add recyclerview in the layout xml file and to create a list item for recyclerview which holds the image for the social link button. Then in the About Fragment find recyclerview element added in the xml file using findFragmentById() method.

1. Add recyclerview in xml file

In the layout xml file of About Fragment add recyclerview element. Define id, width, height, and gravity of recyclerview. Then specify list item for recyclerview using listitem attribute.

<android.support.v7.widget.RecyclerView
            android:id="@+id/list_social_links"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:overScrollMode="never"
            android:clipToPadding="false"
            tools:listitem="@layout/item_social_link" />

2. Create item_social_link.xml

Now create a item_social_link.xml file and add a FrameLayout element. Inside the FrameLayout add an ImageView with appropriate id, width, height and padding.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout_social_link_parent"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/img_social_link"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="?attr/selectableItemBackgroundBorderless"
        android:contentDescription="@string/social_link"
        android:padding="@dimen/padding_large"
        android:tint="@color/white" />
</FrameLayout>

Add and initialize RecyclerView

After adding recyclerview in xml file we need to add RecyclerView field in the About Fragment java file. Now add and initialize SocialLinksListAdapter which extends RecyclerView.Adapter and will be used for populating the recyclerview with the social links.

@BindView(R.id.list_social_links)
protected RecyclerView socialLinksRecyclerView;

private SocialLinksListAdapter socialLinksListAdapter;
private List<SocialLink> mSocialLinks = new ArrayList<>();

Here mSocialLinks is the list of social links which is fetched from the Event object.

Create ViewHolder for social link button

Now create SocialLinkViewHolder which extends RecyclerView.ViewHolder and holds one social link item defined in item_social_link.xml file. This file is where the magic happens. Add ImageView, FrameLayout, SocialLink and context fields in it.

public class SocialLinkViewHolder extends RecyclerView.ViewHolder {

    @BindView(R.id.img_social_link)
    protected ImageView imageView;

    @BindView(R.id.layout_social_link_parent)
    protected FrameLayout layout;

    private SocialLink socialLink;
    private Context context;

    public SocialLinkViewHolder(View itemView, Context context) {
        super(itemView);
        ButterKnife.bind(this, itemView);
        this.context = context;
    }

    public void bindSocialLink(@NonNull SocialLink socialLink) {...}

    private void setImageDrawable(@NonNull String name,@NonNull String link) {...}

    private Drawable getDrawable(@DrawableRes int id) {...}

    private void showView(boolean show) {...}
}

The bindSocialLink(SocialLink socialLink) method is called in the onBindViewHolder() method of the SocialLinksListAdapter. In this method initialize socialLink field and set drawable for ImageView according to SocialLink name using setImageDrawable() method.

public void bindSocialLink(@NonNull SocialLink socialLink) {
        this.socialLink = socialLink;
        setImageDrawable(socialLink.getName(), socialLink.getLink());
}

The setImageDrawable() method finds and sets appropriate image for social link button using the name of the social link. If the image for the social link is not found then it sets the visibility of the image view to GONE using showView(boolean show).

private void setImageDrawable(@NonNull String name,@NonNull String link) {

        if (Utils.isEmpty(name) || Utils.isEmpty(link) || Utils.getSocialLinkDrawableId(name) == 1) {
            showView(false);
            return;
        }
        imageView.setImageDrawable(getDrawable(Utils.getSocialLinkDrawableId(name)));
}

The showView(boolean show) method handles visibility of ImageView and ImageView’s parent FrameLayout using setVisibility() method.

private void showView(boolean show) {
        if (show) {
            imageView.setVisibility(View.VISIBLE);
            layout.setVisibility(View.VISIBLE);
        } else {
            imageView.setVisibility(View.GONE);
            layout.setVisibility(View.GONE);
        }
}

Set onClickListener to ImageView

Now it’s time to set the onClickListener in the constructor of the SocialLinkViewHolder to define what to do when user clicks on the ImageView.

imageView.setOnClickListener(view -> {
            if (socialLink != null && !Utils.isEmpty(socialLink.getLink())) {
                Utils.setUpCustomTab(context, socialLink.getLink());
            }
        });

Here we are setting custom tab for the social link using the setUpCustomTab() util method which will open the link.

Now run the app on the device or emulator. Here’s how it looks like,

Conclusion

The SocialLink impementation using the RecyclerView gives the great user experience in the application.

Additional resources

Continue ReadingGeneric Social Links Implementation in Open Event Android App

Presenters via Loaders in Open Event Organizer Android App

Open Event Organizer‘s App design follows Model View Presenter (MVP) architecture which facilitates heavy unit testing of the app. In this design pattern, each fragment/activity implements a view interface which uses a presenter interface to interact with a model interface. The presenter contains most of the data of the view. So it is very important to restore presenters after configuration changes like rotation. As on rotation, the complete activity is re-created hence all the fields are destroyed and as a result, everything is re-generated resulting in state loss on configuration change which is unexpected. Open Event Organizer App uses the loader to store/provide presenters to the activity/fragment. Loader survives configuration changes. The idea of using the loader to provide presenter is taken from Antonio Gutierrez’s blog on “Presenters surviving orientation changes with loaders“.

The first thing to do is make a PresenterLoader<T> class extending Loader<T> where T is your presenter’s base interface. The PresenterLoader class in the app looks like:

public class PresenterLoader<T extends IBasePresenter> extends Loader<T> {

   private T presenter;

   ...

   @Override
   protected void onStartLoading() {
       super.onStartLoading();
       deliverResult(presenter);
   }

   @Override
   protected void onReset() {
       super.onReset();
       presenter.detach();
       presenter = null;
   }

   public T getPresenter() {
       return presenter;
   }
}

 

The methods are pretty clear from the names itself. Once this is done, now you are ready to use this loader in for your fragment/activity. Creating a BaseFragment or BaseActivity will be clever as then you don’t have to add same logic everywhere. We will take a use case of an activity. A loader has a unique id by which it is saved in the app. Use unique id for each fragment/activity. Using the id, the loader is obtained in the app.

Loader<P> loader = getSupportLoaderManager().getLoader(getLoaderId());

 

When creating for the first time, the loader is set up with the loader callbacks where we actually set a presenter logic. In the Organizer App, we are using dagger dependency injection for injecting presenter in the app for the first time. If you are not using the dagger, you should create PresenterFactory class containing create method for the presenter. And pass the PresenterFactory object to the PresenterLoader in onCreateLoader. In this case, we are using dagger so it simplifies to this:

getSupportLoaderManager().initLoader(getLoaderId(), null, new LoaderManager.LoaderCallbacks<P>() {
   @Override
   public Loader<P> onCreateLoader(int id, Bundle args) {
       return new PresenterLoader<>(BaseActivity.this, getPresenterProvider().get());
   }

   @Override
   public void onLoadFinished(Loader<P> loader, P presenter) {
       BaseActivity.this.presenter = presenter;
   }

   @Override
   public void onLoaderReset(Loader<P> loader) {
       BaseActivity.this.presenter = null;
   }
});

 

getPresenterProvider method returns Lazy<Presenter> provider to ensure single presenter creation in the activity/fragment. The lifecycle to setup PresenterLoader in activity is onCreate and in the fragment is onActivityCreated. Use presenter field from next lifecycle that is start. If the presenter is used before the start, it creates null pointer exception. For example, if implementing with the BaseFragment, setup loader in onActivityCreated method.

@Override
   protected void onCreate(@Nullable Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       Loader<P> loader = getSupportLoaderManager().getLoader(getLoaderId());
       if (loader == null) {
           initLoader();
       } else {
           presenter = ((PresenterLoader<P>) loader).getPresenter();
       }
   }

 

Make sure that your base interface implements some of the basic methods. For example, onDetach, onAttach etc. getLoaderId method must be implemented in each fragment/activity using loaders. The method returns unique id for each fragment/activity. In Organizer App, the method returns layout id of the fragment/activity as a unique id.

Using the loader approach to store/restore presenters helps in surviving their instances in configuration changes in the app. Hence improves the performance.

Links:
Antonio Gutierrez’s blog post about Presenter surviving orientation changes with Loaders in Android
Android Documentation for Loaders

Continue ReadingPresenters via Loaders in Open Event Organizer Android App

Real time Sensor Data Analysis on PSLab Android

PSLab device has the capacity to connect plug and play sensors through the I2C bus. The sensors are capable of providing data in real time. So, the PSLab Android App and the Desktop app need to have the feature to fetch real time sensor values and display the same in the user interface along with plotting the values on a simple graph.

The UI was made following the guidelines of Google’s Material Design and incorporating some ideas from the Science Journal app. Cards are used for making each section of the UI. There are segregated sections for real time updates and plotting where the real time data can be visualised. A methods for fetching the data are run continuously in the background which receive the data from the sensor and then update the screen.

The following section denotes a small portion of the UI responsible for displaying the data on the screen continuously and are quite simple enough. There are a number of TextViews which are being constantly updated on the screen. Their number depends on the type and volume of data sent by the sensor.

<TextView
       android:layout_width="wrap_content"
       android:layout_height="30dp"
       android:layout_gravity="start"
       android:text="@string/ax"
       android:textAlignment="textStart"
       android:textColor="@color/black"
       android:textSize="@dimen/textsize_edittext"
       android:textStyle="bold" />

<TextView
       android:id="@+id/tv_sensor_mpu6050_ax"
       android:layout_width="wrap_content"
       android:layout_height="30dp"
       android:layout_gravity="start"
       android:textAlignment="textStart"
       android:textColor="@color/black"
       android:textSize="@dimen/textsize_edittext"
       android:textStyle="bold" />

 

The section here represents the portion of the UI responsible for displaying the graph. Like all other parts of the UI of PSLab Android, MPAndroidChart is being used here for plotting the graph.

<LinearLayout
       android:layout_width="match_parent"
       android:layout_height="160dp"
       android:layout_marginTop="40dp">

       <com.github.mikephil.charting.charts.LineChart
               android:id="@+id/chart_sensor_mpu6050"
               android:layout_width="match_parent"
               android:layout_height="match_parent"
               android:background="#000" />
</LinearLayout>

 

Since the updates needs to continuous, a process should be continuously run for updating the display of the data and the graph. There are a variety of options available in Android in this regard like using a Timer on the UI thread and keep updating the data continuously, using ASyncTask to run a process in the background etc.

The issue with the former is that since all the processes i.e. fetching the data and updating the textviews & graph will run on the UI thread, the UI will become laggy. So, the developer team chose to use ASyncTask and make all the processes run in the background so that the UI thread functions smoothly.

A new class SensorDataFetch which extends AsyncTask is defined and its object is created in a runnable and the use of runnable ensures that the thread is run continuously till the time the fragment is used by the user.

scienceLab = ScienceLabCommon.scienceLab;
i2c = scienceLab.i2c;
try {
    MPU6050 = new MPU6050(i2c);
} catch (IOException e) {
    e.printStackTrace();
}
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        while (true) {
            if (scienceLab.isConnected()) {
                try {
                    sensorDataFetch = new SensorDataFetch();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                sensorDataFetch.execute();
            }
        }
    }
};
new Thread(runnable).start();

 

The following is the code for the ASyncTask created. There are two methods defined here doInBackground and onPostExecute which are responsible for fetching the data and updating the display respectively.

The raw data is fetched using the getRaw method of the MPU6050 object and stored in an ArrayList. The data type responsible for storing the data will depend on the return type of the getRaw method of each sensor class and might be different for other sensors. The data returned by getRaw is semi-processed and the data just needs to be split in sections before presenting it for display.

The PSLab Android app’s sensor files can be viewed here and they can give a better idea about how the sensors are calibrated, how the intrinsic nonlinearity is taken care of, how the communication actually works etc.

After the data is stored, the control moves to the onPostExecute method, here the textviews on the display and the chart are updated. The updation is slowed down a bit so that the user can visualize the data received.

private class SensorDataFetch extends AsyncTask<Void, Void, Void> {
   MPU6050 MPU6050 = new MPU6050(i2c);
   ArrayList<Double> dataMPU6050 = new ArrayList<Double>();

   private SensorDataFetch(MPU6050 MPU6050) throws IOException {
   }

   @Override
   protected Void doInBackground(Void... params) {
       try {
           if (MPU6050 != null) {
               dataMPU6050 = MPU6050.getRaw();
           }
       } catch (IOException e) {
           e.printStackTrace();
       }
           return null;
   }

   protected void onPostExecute(Void aVoid) {
       super.onPostExecute(aVoid);
       tvSensorMPU6050ax.setText(String.valueOf(dataMPU6050.get(0)));
       tvSensorMPU6050ay.setText(String.valueOf(dataMPU6050.get(1)));
       tvSensorMPU6050az.setText(String.valueOf(dataMPU6050.get(2)));
       tvSensorMPU6050gx.setText(String.valueOf(dataMPU6050.get(3)));
       tvSensorMPU6050gy.setText(String.valueOf(dataMPU6050.get(4)));
       tvSensorMPU6050gz.setText(String.valueOf(dataMPU6050.get(5)));
       tvSensorMPU6050temp.setText(String.valueOf(dataMPU6050.get(6)));
   }
}

The detailed implementation of the same can be found here.

Additional Resources

  1. Learn more about how real time sensor data analysis can be used in various fields like IOT http://ieeexplore.ieee.org/document/7248401/
  2. Google Fit guide on how to use native built-in sensors on phones, smart watches etc. https://developers.google.com/fit/android/sensors
  3. A simple starter guide to build an app capable of real time sensor data analysis http://developer.telerik.com/products/building-an-android-app-that-displays-live-accelerometer-data/
  4. Learn more about using AsyncTask https://developer.android.com/reference/android/os/AsyncTask.html
Continue ReadingReal time Sensor Data Analysis on PSLab Android

How Meilix Generator sends Email Notifications with SendGrid

We wanted to notify the users once the build was ready for download. To solve this we attempted making an email server on Meilix Generator but that can send email when it starts but it would take around 20 minutes to get the build ready so we thought of checking the deploy link status and send email whenever the link status was available (200) but the problem with this method was that the link can be pre available if ISO is rebuilt for same event.

Then, we attempted sending mail by Travis CI but the problem in that was closed SMTP ports (they have a strict policy about that) then we thought that Travis CI can trigger the Sendgrid which can send email to the user with the help of API.

We will use this code so that once the deployment of ISO by Travis CI is done it can execute the email script which requests Sendgrid to send email to the user.

after_deploy:
  - ./mail.py

 

We can create code using code generation service of Sendgrid we are going to choose python as it is easier to manipulate strings in python and we are going to use email as an environment variable.

After generation of python 3 code from the sendgrid website we are going to edit the message and email and hide the API key as an environment variable and create an authorization string to be used there too.

The URL will be generated by the below script as the body of url remains same only two things will change the TRAVIS_TAG which is event name and date.

date = datetime.datetime.now().strftime('%Y%m%d')
url="https://github.com/xeon-zolt/meilix/releases/download/"+os.environ["TRAVIS_TAG"]+"/meilix-zesty-"+date+"-i386.iso"

 

We can use this to hide the api key and use it as an environment variable because if the api key is visible in logs anyone can use it to exploit it and use it for spamming purpose.

authorization = "Bearer " + os.environ["mail_api_key"]
headers = {
    'authorization': authorization,

 

The main thing left to edit in the script is the message which is in the payload and is a string type so we are going to use the email received by Meilix generator as an environment variable and concatenate it with the payload string the message sent is in the value which is in the HTML format and we add the generated URL in similar way we added email variable to string.

payload = "{\"personalizations\":[{\"to\":[{\"email\":\"" + os.environ["email"] + "\"}],\"subject\":\"Your ISO is Ready\"}],\"from\":{\"email\":\"xeon.harsh@gmail.com\",\"name\":\"Meilix Generator\"},\"reply_to\":{\"email\":\"xeon.harsh@gmail.com\",\"name\":\"Meilix Generator\"},\"subject\":\"Your ISO is ready\",\"content\":[{\"type\":\"text/html\",\"value\":\"<html><p>Hi,<br>Your ISO is ready<br>URL : "+url+"<br><br>Thank You,<br>Meilix Generator Team</p></html>\"}]}"

 

The sent email looks like this

References

Continue ReadingHow Meilix Generator sends Email Notifications with SendGrid

Creating a Four Quadrant Graph for PSLab Android App

While working on Oscilloscope in PSLab Android, we had to implement XY mode. XY plotting is part of regular Oscilloscope and in XY plotting the 2 signals are plotted against each other. For XY plotting we require a graph with all 4 quadrants but none of the Graph-View libraries in Android support a 4 quadrants graph. We need to find a solution for this. So, we used canvas class to draw a 4 quadrants graph.  The Canvas class defines methods for drawing text, lines, bitmaps, and many other graphics primitives. Let’s discuss how a 4 quadrants graph is implemented using Canvas.

Initially, a class Plot2D extending View is created along with a constructor in which context, values for X-Axis, Y-Axis.

public class Plot2D extends View {
public Plot2D(Context context, float[] xValues, float[] yValues, int axis) {
   super(context);
   this.xValues = xValues;
   this.yValues = yValues;
   this.axis = axis;
   vectorLength = xValues.length;
   paint = new Paint();
   getAxis(xValues, yValues);
}

 

So, now we need to convert a particular float value in a pixel. This is the most important part and for this, we create a function where we send the value of the pixels, the minimum and the maximum value of the axis and array of float values. We get an array of converted pixel values in return. p[i] = .1 * pixels + ((value[i] – min) / (max – min)) * .8 * pixels; is the way to transform an int value to a respective pixel value.

private int[] toPixel(float pixels, float min, float max, float[] value) {
   double[] p = new double[value.length];
   int[] pInt = new int[value.length];

   for (int i = 0; i < value.length; i++) {
       p[i] = .1 * pixels + ((value[i] - min) / (max - min)) * .8 * pixels;
       pInt[i] = (int) p[i];
   }
   return (pInt);
}

 

For constructing a graph we require to create the axis, add markings/labels and plot data in the graph. To achieve this we will override onDraw method. The parameter to onDraw() is a Canvas object that the view can use to draw itself. First, we need to get various parameters like data to plot, canvas height and width, the location of the x axis and y axis etc.

@Override
protected void onDraw(Canvas canvas) {

   float canvasHeight = getHeight();
   float canvasWidth = getWidth();
   int[] xValuesInPixels = toPixel(canvasWidth, minX, maxX, xValues);
   int[] yValuesInPixels = toPixel(canvasHeight, minY, maxY, yValues);
   int locxAxisInPixels = toPixelInt(canvasHeight, minY, maxY, locxAxis);
   int locyAxisInPixels = toPixelInt(canvasWidth, minX, maxX, locyAxis);

 

Drawing the axis

First, we will draw the axis and for this, we will use the white color. To draw the white color axis line we will the following code.

paint.setColor(Color.WHITE);
paint.setStrokeWidth(5f);
canvas.drawLine(0, canvasHeight - locxAxisInPixels, canvasWidth,
       canvasHeight - locxAxisInPixels, paint);
canvas.drawLine(locyAxisInPixels, 0, locyAxisInPixels, canvasHeight,
       paint);

 

Adding the labels

After drawing the axis lines, now we need to mark labels for both x and y axis. For this, we use the following code in onDraw method. By this, the axis labels are automatically marked after a fixed distance. The no. of labels depends on the value of n. The code ensures that the markings are apt for each of the quadrant, for example in the first quadrant the markings of the x axis is below the axis, whereas markings of the y axis are to the left.

float temp = 0.0f;
int n = 8;
for (int i = 1; i <= n; i++) {
    if (i <= n / 2) {
           temp = Math.round(10 * (minX + (i - 1) * (maxX - minX) / n)) / 10;
           canvas.drawText("" + temp,
                   (float) toPixelInt(canvasWidth, minX, maxX, temp),
                   canvasHeight - locxAxisInPixels - 10, paint);
           temp = Math.round(10 * (minY + (i - 1) * (maxY - minY) / n)) / 10;
           canvas.drawText("" + temp, locyAxisInPixels + 10, canvasHeight
                           - (float) toPixelInt(canvasHeight, minY, maxY, temp),
                   paint);
       } else {
           temp = Math.round(10 * (minX + (i - 1) * (maxX - minX) / n)) / 10;
           canvas.drawText("" + temp,
                   (float) toPixelInt(canvasWidth, minX, maxX, temp),
                   canvasHeight - locxAxisInPixels + 30, paint);
           temp = Math.round(10 * (minY + (i - 1) * (maxY - minY) / n)) / 10;
           canvas.drawText("" + temp, locyAxisInPixels - 65, canvasHeight
                           - (float) toPixelInt(canvasHeight, minY, maxY, temp),
                   paint);

By using this code we get the following results

Plotting the data

The last step is to plot the data, to achieve this we first convert float values of x axis and y axis data point to pixels using toPixel method and simply draw it on the graph. In addition to this, we set a red color to the line.

paint.setStrokeWidth(2);
canvas.drawARGB(255, 0, 0, 0);
for (int i = 0; i < vectorLength - 1; i++) {
   paint.setColor(Color.RED);
   canvas.drawLine(xValuesInPixels[i], canvasHeight
           - yValuesInPixels[i], xValuesInPixels[i + 1], canvasHeight
           - yValuesInPixels[i + 1], paint);
}

 

This implements a 4 quadrants graph in PSLab Android app for XY plotting in Oscilloscope Activity. The entire code for the same is available in here.

Resources

  1. A simple 2D Plot class for Android
  2. Android.com reference of Custom Drawing
Continue ReadingCreating a Four Quadrant Graph for PSLab Android App