Creating Instruction Guide using Bottomsheet

The PSLab android app consists of different instruments like oscilloscope, multimeter, wave generator etc and each instrument has different functionality and usage so it is necessary that there should be an instruction guide for every instrument so that the user can easily read the instruction to understand the functionality of the instrument.

In this we will create an instruction guide for the Wave Generator which will contain information about the instrument, it’s functionalities, steps for how to use the instrument.

The main component that I used to create instruction guide is Bottom SheetBottom Sheet is introduced in Android Support v23.2 . It is a special UI widget which slide up from the bottom of the screen and it can be used to reveal some extra information that we cannot show on the main layout like bottom menus,  instructions etc.

They are of two types :

  1. Modal Bottom Sheet:–  This Bottom Sheet has properties very similar to normal dialogs present in Android like elevation only difference is that they pop up from the bottom of screen with proper animation and they are implemented using BottomSheetDialogFragment Class.

  2. Persistent Bottom Sheet:– This Bottom Sheet is included as a part of the layout and they can be slid up and down to reveal extra information. They are implemented using BottomSheetBehaviour Class.

For my project, I used persistent Bottom Sheet as modal Bottom Sheet can’t be slid up and down by the swipe of the finger whereas persistent Bottom Sheet can be slid up and down and can be hidden by swipe features.

Implementing the Bottom Sheet

Step 1: Adding the Dependency

To start using Bottom Sheet we have to add the dependency (We have also include Jake Wharton-Butterknife library for view binding but it is optional.)

dependencies {

   implementation fileTree(include: ['*.jar'], dir: 'libs')

   implementation "com.android.support:appcompat-v7:26.0.1"
   implementation "com.android.support:design:26.0.1"
   implementation "com.jakewharton:butterknife:8.8.1"

   annotationProcessor "com.jakewharton:butterknife-compiler:8.8.1"

Step 2: Creating Bottom Sheet layout file

In this step, we will create the layout of the Bottom Sheet, as our purpose of making Bottom Sheet is to show extra information regarding the instrument so we will include ImageView and TextView inside the layout that will be used to show the content later.

Some attributes in the layout worth noting are:

  • app:layout_behavior: This attribute makes the layout act as Bottom Sheet.
  • app:behavior_peekHeight: This is the height of the Bottom Sheet when it is minimized.
  • app:behavior_hideable: Defines if the Bottom Sheet can be hidden by swiping it down.

Here, we will also create one extra LinearLayout having height equal to the peek_height. This  LinearLayout will be at the top of the BottomSheet as shown in Figure 1 and it will be visible when the BottomSheet is in a minimized state(not hidden). Here we will put text view with like “Show guide” and an arrow pointing upwards so that it is easier for the user to understand that sheet can be viewed by sliding up.

Figure 1 LinearLayout containing textview and imageview

Here is the gist[2] that contains code for the layout of the Bottom Sheet guide

After this step, we can see a layout of Bottom Sheet in our Android Editor as shown in Figure 2

Figure 2 shows the layout of the Bottom Sheet

Step 3: Creating the Container view layout containing content and Bottom Sheet

For container view, we will create new layout under Res Layout and name it “container_view_wavegenerator.xml”

In this layout, we will use ‘Coordinator Layout’ as ViewGroup because persistent Bottom Sheet is implemented using BottomSheetBehavior class which can only be applied to the child of ‘CoordinatorLayout’.

Then add the main layout of our instrument and the layout of the Bottom Sheet inside this layout as its child.

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent">

   <include layout="@layout/activity_wave_generator" />

   <include layout="@layout/bottom_sheet_custom" />

Step 4: Setting Up Bottom Sheet and Handling callbacks

Now we will head over to the “WaveGenerator.java” file(or any instrument java file)Here we will handle set up Bottom Sheet and handle callbacks by using following classes:

BottomSheetBehavior provides callbacks and makes the Bottom Sheet work with CoordinatorLayout.

BottomSheetBehavior.BottomSheetCallback() provides the callback when the Bottom Sheet changes its state. It has two methods that need to be overridden:

  1. public void onSlide(@NonNull View bottomSheet, float slideOffset)

    This method is called when the Bottom Sheet slides up and down on the screen. It has slideOffset as a parameter whose value varies from -1.0 to 0.0 when the Bottom Sheet comes from the hidden state to collapsed and 0.0 to 1.0 when it goes from collapsed state to expanded state.

  2. public void onStateChanged(@NonNull View bottomSheet, int newState)

    This method is called when BottomSheet changed its state. Here, let us also understand the different states which can be attained by the Bottom Sheet:

    • BottomSheetBehavior.STATE_EXPANDED : When the Bottom Sheet is fully expanded showing all the content.
    • BottomSheetBehavior.STATE_HIDDEN : When the Bottom Sheet is hidden at the bottom of the layout.
    • BottomSheetBehavior.STATE_COLLAPSED : When the Bottom Sheet is in a collapsed state that is only the peek_height view part of the layout is visible.
    • BottomSheetBehavior.STATE_DRAGGING : When the Bottom Sheet is dragging.
    • BottomSheetBehavior.STATE_SETTLING : When the Bottom Sheet is settling either at expanded height or at collapsed height.

We will implement these methods in our instrument class, and also put the content that needs to be put inside the Bottom Sheet.

@BindView(R.id.bottom_sheet)
LinearLayout bottomsheet;
@BindView(R.id.guide_title)
TextView bottomSheetGuideTitle;
@BindView(R.id.custom_dialog_schematic)
ImageView bottomSheetSchematic;
@BindView(R.id.custom_dialog_desc)
TextView bottomSheetDesc;

BottomSheetBehavior bottomSheetBehavior;

@Override
protected void onCreate(Bundle savedInstanceState) { 
              
           //main instrument implementation code

           setUpBottomSheet()
}

private void setUpBottomSheet() {

   bottomSheetBehavior = BottomSheetBehavior.from(bottomsheet);

    bottomSheetGuideTitle.setText(R.string.wave_generator);
   bottomSheetSchematic.setImageResource(R.drawable.sin_wave_guide);
   bottomSheetDesc.setText(R.string.wave_gen_guide_desc);

  bottomSheetBehavior.setBottomSheetCallback(new 
  BottomSheetBehavior.BottomSheetCallback() {
       @Override
       public void onStateChanged(@NonNull View bottomSheet, int newState) {
           if (newState == BottomSheetBehavior.STATE_EXPANDED) {
               bottomSheetSlideText.setText(R.string.hide_guide_text);
           } else {
               bottomSheetSlideText.setText(R.string.show_guide_text);
           }
       }

       @Override
       public void onSlide(@NonNull View bottomSheet, float slideOffset) {
           Log.w("SlideOffset", String.valueOf(slideOffset));
        }
      });
}

After following all the above steps the Bottom Sheet will start working properly in the Instrument layout as shown in Figure 3

Figure 3 shows the Bottom Sheet in two different states

To read more about implementing Bottom Sheet in layout refer this: AndroidHive article- working with bottomsheet

Resources

  1. Developer Documentation – BottomSheetBehaviour
  2. Gist containing xml file for layout of Custom Bottomsheet
Continue ReadingCreating Instruction Guide using Bottomsheet

Creating Control Panel For Wave Generator using Constraint Layout

 

In the blog Creating the onScreen Monitor Using CardView I had created the monitors to view the wave properties in this blog we will create the UI of controlling panel that will be used for that monitors with multiple buttons for both analog and digital waveforms.

Which layout to choose?

In today’s world, there are millions of Android devices present with different screen sizes and densities and the major concern of an Android developer is to make the layout that fits all the devices and this task is really difficult to handle with a linear or relative layout with fixed dimensions.

To create a complex layout with lots of views inside the parent using linear layout we have to make use of the attribute layout_weight for their proper stretching and positioning, but such a complex layout require a lot of nesting of weights and  android tries to avoid it by giving a warning :

Nested Weights are bad for performance

This is because layout_weight attribute requires a widget to be measured twice[1]. When a LinearLayout with non-zero weights is nested inside another LinearLayout with non-zero weights, then the number of measurements increases exponentially.

So, to overcome this issue we will make use of special type of layout “Constraint Layout” which was introduced in Google I/O 2016.

Features of Constraint Layout:-

  • It is similar to Relative Layout as all views are laid out according to their relationship with the sibling, but it is more flexible than Relative Layout.
  • It helps to flatten the view hierarchy for complex layouts.
  • This layout is created with the help of powerful tool provided by Android which has a palette on the left-hand side from where we can drag and drop the different widgets like TextView, ImageView, Buttons etc. and on the right-hand side it provides options for positioning, setting margins and other styling option like setting color, change text style etc.
  • It automatically adjusts the layout according to the screen size and hence doesn’t require the use of layout_weight attribute.

In following steps, I will create the controlling panel for Wave generator which is a complex layout with lots of buttons with the help of constraint layout.

Step 1: Add the dependency of the Constraint Layout in the Project

To use Constraint layout add the following to your build.gradle file and sync the project

dependencies {
    implementation "com.android.support.constraint:constraint-layout:1.1.0"
}

Step 2: Applying Guidelines to the layout

Guidelines[3] are anchors that won’t be displayed in your app, they are like one line of a grid above your layout and can be used to attach or constraint your widgets to it. They are only visible on your blueprint or preview editor. These will help to position and constraint the UI components on the screen easily.

For adding guidelines :

As shown in Figure 1 Right-click anywhere on the layout -> Select helpers -> Select horizontal or vertical guideline according to your need.

Figure 1 shows the horizontal guideline being added to the layout.

And for positioning the guideline we have to set the value of attribute layout_constraintGuide_percent  

Let’s say we want the guideline to be at the middle of the screen so we’ll set :

app:layout_constraintGuide_percent=”0.50″

For my layout I have added three guideline :

  • One horizontal guideline at 50%
  • Two vertical guidelines at 30% and 65%

Doing this will bifurcate the screen into six square blocks as shown in below figure :

Figure 2 shows the blueprint of constraint layout containing two vertical and one horizontal guidelines with their percentage offset from respective bases

Step 3: Adding the buttons in the blocks

Until now we have created six squares blocks, now we have to put a button view in each of the boxes.

  • First drag and drop button view from the Palette (shown in Figure 3) on the left side inside the box.

    Figure 3 shows the layout editor palette

     

  • Then we have to set constraints of this button by clicking on the small circle present on the middle of edges and dragging it onto the side of the block facing it.

    Figure 4 shows the button widget getting constrained to sides

     

  • Set the layout_width and layout_height attribute of the button to be “0dp”, doing this the button will expand in all the direction occupying all the space with respect to the border it has been constrained with.

    Figure 6 shows the button widget expanding to all the available space in the box

Similarly, adding buttons in all the square blocks and providing proper theme color we will have a blueprint and layout as shown in Figure 6.

Figure 6 shows the waveform panel blueprint and actual layout for analog waves with six buttons

Following the same steps until now, I have created the other controlling panel layout having buttons for digital waves as shown in Figure 7

Figure 7 shows other constraint layout for digital waves having seven buttons

Detailing and combining the panels to form Complete UI

After adding both the panels we have created in this layout inside the Wave Generator we have the layout as shown in Figure 8

Figure 8 shows the UI of Wave Generator as shown by a actual Android device in the PSLab app.

As we can see on adding the panels the button created inside the layout shrink so as to adapt to the screen and giving out a beautiful button-like appearance.

Resources   

  1. Blog on Nested Weights are bad for performance
  2. Developer Article – Build a Responsive UI with ConstraintLayout
  3. Information about Guidelines
Continue ReadingCreating Control Panel For Wave Generator using Constraint Layout

Implementing Leak Canary in PSLab Android App

This post discusses the issue of memory leaks and how to handle them efficiently and what are the tools available which help developers in managing the memory leaks. After working on PR #824 opened under PSLab – Android repository I have got a greater idea about how to manage the memory efficiently and what are the tools that should be used to ease the work.

What are memory leaks and how it affects the quality of app?

In simple words, memory leaks happen when you hold on to an item for long after its purpose have been served. It is as simple as that. But let us dive in further to understand more about this topic. Programming languages like C and C++ need memory management done by user whereas in higher level languages like Java, Python, etc. low-level memory management and garbage collection is done automatically by the system. But it is due to programming faults that memory leaks happen and so care needs to be taken with higher level languages too in handling memory efficiently.

In Android or say in any OS (operating system), every item has to be destroyed or say deleted or freed from the memory after its purpose is served. But if the reference of this object is passed on to any other object which has a greater time of importance than this, then it will try to hold this object for long and so the garbage collector won’t be able to collect it and so there will be memory leaks in the code. This is how memory leaks occurs inside an app.

Now, the issue of memory leaks is utmost important among developers as due to it, the app becomes slow, laggy, eats up a lot of memory and the app crashes after some time of use which creates a very bad user experience. As the user keeps on using the app, the heap memory also keeps on increasing and due to memory leaks, this heap can’t be freed by the garbage collector. Thus, all these issues contribute to making the threads or processes running inside the app slower and it can result in a lag of time from microseconds to milliseconds too!!

How can you detect these memory leaks?

This blog is mostly for Android developers and so I will use the environment of Android Studio for reference. For controlling memory leaks, Android Studio has a very powerful tool named Monitors. There are individual monitors not only for memory usage but for CPU, GPU, and network usage as well. An example of it is shown in figure 1 below.

Figure 1. Monitor in Android Studio

Now how to observe the graphs that are produced by Monitors to see if there are any memory leaks? The first alarming case is when the memory usage graph constantly increases and doesn’t come down as time passes and even not decreases when you put the app in the background. The tools which are used to undo memory leaks as soon as they are found are:

  1. Allocation Tracker: The allocation tracker comes with an indicator to show the percentage of memory allocated to different types of objects in your app. The developer can have a clear idea about which object is taking what amount of memory and which objects are exceeding the memory limit. But it is itself not enough as the developer needs other tools to dump the extra memory.
  2. Leak Canary Library: It is the most used library by developers to check for memory leaks in an app. This library runs along with app and dumps memory when needed, looks for potential memory leaks  and gives a notification for a memory leak with a clean trace to find the root of the leak with sub-roots attached to it as shown in figure 2 :

Figure 2. Screenshot from Leaks application made by Leak Canary for PSLab app

It is clearly visible from the image that the applications show the root of the memory leak with an indication of how much memory is leaked in the toolbar.

Explanation of leak shown in figure 2 :

In the PSLab app, there is a navigation drawer consisting of all main functionalities in it. It is as shown in figure 3 :

Figure 3. Navigation drawer in PSLab

The memory leak as shown in figure 2 originated in the following steps :

  • It started with ArrayList which is here the list of items as shown in figure 3.
  • After it comes to the ScrollContainer which helps in scrolling this list on small screens.
  • Then comes the Drawer Layout which is the actual layout seen in figure 3 that slides over the main layout which is here the Instruments layout.
  • At last, comes the InputMethodManager which is introduced by Leak Canary library which watches the activity that is being opened.
  • Here, InputMethodManager kept watching on Drawer Layout but after closing the layout too it referenced it which is due to the source code of LeakCanary Library and so memory Leak occurred.

How to stop this leak from occurring ?

A simple way is to add a transparent activity as soon as the layout is closed for a very small time i.e. 500 ms so that the reference watcher gets shifted from the actual layout. This solution is based on the article published on Medium [5].

How to implement Leak Canary in your app?

Below is the step-by-step guide on implementing Leak Canary library in your app to implement a watcher for memory leaks :

    • Add dependencies (App Level) in your project to implement Leak Canary
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
      1. debugImplementation – For debug flavor of app
      2. releaseImplementation – For release flavor of app
      3. testImplementation – For testing the current flavor of the app

Add dependencies according to the need for the application.

Add Realm dependencies (Project Level) in your app to create a database which can be used by Leak Canary to maintain and provide crash reports as shown in the figure above.

NOTE: Any database can be used here according to the need of the app

buildscript {
            repositories {
                     jcenter()
                         }
            dependencies {
                classpath "io.realm:realm-gradle-plugin:0.88.2"
           }
       }
 apply plugin: 'realm-android'

App-level dependency :

compile 'io.realm:android-adapters:2.0.0'
  • Add an activity class in your application to construct the Leak Canary for your entire application. In PSLab Android application, it was made as under :
package org.fossasia.pslab;

import android.app.Application;

import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;

import io.realm.Realm;

public class PSLabApplication extends Application {

	public RefWatcher refWatcher;

	@Override
	public void onCreate() {
    	super.onCreate();
    	Realm.init(this);

    	initializeLeakCanary();
	}

	private void initializeLeakCanary() {
    	if (LeakCanary.isInAnalyzerProcess(this)) {
        	return;
    	}
    	refWatcher = LeakCanary.install(this);
	}
}

Explanation of the above-implemented code :

  1. First import all the necessary libraries
  2. Realm.init(this) is used to initiate the database as soon as the layout of the Leak Canary is ready to work so that before any crashes, the database is ready to accept the entry
  3. initializeLeakCanary() method first checks if the analyzer is in the process i.e. if the Leak Canary is already initiated so that there’s no need to again initiate it else a reference watcher is initiated with variable refWatcher which looks out for any potential memory leaks

After this, you can provide a watcher with an object to watch by writing :

refWatcher.watch(object);

Now your app is ready to handle any case of memory leaks and thus the developer can find the root of the issue if any and can solve it with ease. The app will now work 94% more efficiently than what it used to be with memory leaks. Thus, a greater user experience can be provided now but in the backend!!

Resources

  1. How to use Leak Canary – Article on Stack Overflow
  2. Everything you need to know about memory leaks – Article on medium.com
  3. Leak Canary: Detect all memory leaks -Another great article on medium.com
  4. https://github.com/square/leakcanary – Actual GitHub repo of Leak Canary library
  5. https://medium.com/@amitshekhar/android-memory-leaks-inputmethodmanager-solved-a6f2fe1d1348 – Medium article on how to solve InputMethodManager related leaks

 

Continue ReadingImplementing Leak Canary in PSLab Android App

Implementing search bar in PSLab app

PSLab offers a large range of functions with a large field of applications. This results in the long access path to certain information and functionality in the app, which affects the user experience (UX) negatively. In this blog post, I will show how the UX in Android applications with many functions can be improved by implementing a ‘Search Bar’. Further, I have created a screencast that follows the step-by-step description shown in this blog post [1].

Search Bar is the functionality which can be seen nowadays in almost all the apps. It is a handy widget for users to navigate the app. PSLab’s Android app was lacking this functionality and so I added it using an external library from Mirrajabi called ‘search-dialog’ [3]. I decided to use this library as it provides a search bar with built-in functionality of highlighting the text that’s selected or written down in the ‘Edit Text’ field by the user and also it overlays on the screen which provides a good user experience rather than other search bars which overlap on the text provided on the screen with a ListView. Further working with this dependency was easier than working with others as it seems well designed.

The Search Bar was added in the Saved Experiments section which contains a lot of default experiments along with their respective manuals. The search bar was intended to provide the user with a greater UI so that they don’t need to navigate through sections every time to find an experiment.

This blog is a step by step guide on how to implement it in any app.

  1. First, add dependencies in the gradle at both project level and app level. By adding these dependencies, we don’t need to worry about writing code for how the Search Bar will filter searches and how it will be placed on the screen.

App Level :

'com.github.mirrajabi:search-dialog:1.1'

Project Level :

maven { url "https://jitpack.io" }
  1.  Create a SearchModel class which will help to carry out the search operations.
public class SearchModel implements Searchable {

	private String mTitle;

	public SearchModel(String mTitle) {
    	this.mTitle = mTitle;
	}

	public void setTitle(String mTitle) {
    	this.mTitle = mTitle;
	}

	@Override
	public String getTitle() {
    	return mTitle;
	}
}

The SearchModel class helps to communicate with the filtered search results by returning the string which is selected:

  • SearchModel(String string) – It is a default constructor
  • setTitle(String string) – It is a method used to set the string provided in the search results
  • getTitle() – It is also a method to get the string selected by the user from the filtered search result provided
  1.  Now provide some data which needs to be searched using an ArrayList or by using StringArrays and then converting it to Search Model Object.
private ArrayList<SampleSearchModel> createSampleData(){
        ArrayList<SampleSearchModel> items = new ArrayList<>();
        items.add(new SampleSearchModel("First item"));
        items.add(new SampleSearchModel("Second item"));
        items.add(new SampleSearchModel("Third item"));
        items.add(new SampleSearchModel("Fourth item"));

        return items;
    }
  1.  At last add the constructor in MainActivity to make the search bar.
SimpleSearchDialogCompat(Context context, String title, String searchHint, @Nullable Filter filter, ArrayList<T> items,
SearchResultListener<T> searchResultListener)

All the parameters can be given according to requirement. The function of each and every parameter are as under :

  • Context – Provide context of the current activity
  • String title – To provide title to Search Bar
  • String searchHint – To provide hint text to the user
  • Filter – To provide any additional filters to the search made by the user
  • ArrayList<T> – To provide data that can be searched
  • SearchResultListener<T> – The method which handles what to do when a user clicks on the filtered searches provided

Let’s try to search for the Piezo Buzzer and UltraSonic Range Finder Experiments in the Search Bar :

Figure 1. GIF of implemented Search Bar

So, in this way, I have implemented the Search Bar functionality in the PSLab application. One last note that try to practice this widget before implementing it in the main project as it requires some practice of filters as per requirements and also its location needs to be defined as per the requirement of an organization as it can be placed anywhere from the main screen to the toolbar to navigation drawer. Below are some of the useful resources to get best practice.

Resources

  1. https://youtu.be/QyqbRHt1NUE – How to make a search bar like above (By – Harsh Patel (me))
  2. https://github.com/mirrajabi/search-dialog – This is the GitHub Page of the library which I used in making an attractive screen overlaying search bar rather than the old one with the list view placed in the toolbar
Continue ReadingImplementing search bar in PSLab app

Creating the onScreen Monitor Using CardView

The PSLab works as a Wave generator and the Oscilloscope when connected with the Android device. The mockup of the Wave Generator has been created in the blog Creating the Mockup for Wave Generator using Moqups.

In this blog, we will create the monitor screen in the PSLab Android app using Android studio.

Deciding the layout to use for monitors

As monitors with rounded border look appealing on android device screen so we will select CardView to be the base layout of our monitors. The CardView element allows us to add certain properties like rounded corners, elevation etc.

To use the CardView in your app, add the following dependency to build.gradle file and sync the project.

dependencies {    // CardView    
implementation 'com.android.support:cardview-v7:27.1.1'
}

Add the <android.support.v7.widget.CardView> widget to your layout and all the other views to be shown on monitor screen will be placed inside this card layout as its child layout.

Creating the monitor cards

We need to decide how much spacing is to be provided to the cards to properly view them on different screens. Here we make use of the special attribute in the View class.

android:layout_weight=1

This attribute assigns an “importance” value to a View in terms of how much space it should occupy on the screen. That is if we give equal weight to two views which inside the same parent then they will both occupy equal space.

To implement this create two CardViews inside <LinearLayout> with the same layout_weight.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.CardView
        android:layout_width="0dp"
        android:layout_height="250dp"
        android:layout_weight="1"
        card_view:cardCornerRadius="10dp" />

    <android.support.v7.widget.CardView
        android:layout_width="0dp"
        android:layout_height="250dp"
        android:layout_weight="1"
        card_view:cardCornerRadius="10dp" />

</LinearLayout>

So this will give us a screen like this with equally weighted monitor card views as shown in Figure 1.

Figure 1 shows two CardView with equal weights(w/2) and equal width

Both the cards have the width equal to half the screen width which is set automatically by the Android.

Creating partitions in the monitors

We have to make partitions in the monitor screen so that every characteristic of Wave Generator like wave frequency, phase, selected pin etc. can be viewed simultaneously on the screen with proper spacing.

For making partitions we need to make a separator line which we can create by using <View> and setting the attributes as below:

<View
        android:layout_width="@dimen/length_0dp"
        android:layout_height="@dimen/divider_width"
        android:background="@color/dark_grey" />

This will create a thin line having the grey color. We have to make four partitions of the card view for both monitors as shown in Figure 2.

Figure 2 shows two monitors with line separator making partitions

Populating the screen with text and image icons

We have to include the <TextView> and <ImageView> to show the property data on the monitors.

Figure 3 shows partitions in the monitor CardView

Different partitions as shown in Figure 3 can be used for showing different data such as:

  1. Top Partition:- To view the selected wave. 
  2. Left Partition:- To view the selected waveform eg:- sine, triangular 
  3. Right Partition:- To view the selected wave characteristics like frequency, phase etc. 
  4. Bottom Partition:-  To view the property selected which has been selected by user

After inserting all the desired Views and providing the Views with dummy data and icons and customizing the Views by giving proper color and spacing finally we will have a layout as shown in Figure 4.

Figure 4 shows ImageView and TextView showing different dummy data

In Figure 4, the left CardView shows all the properties for the Analog Wave Generator and the right CardView shows all the properties for Digital Wave Generator.

All the characteristics on the monitors can be controlled by the controlling panel which is work in progress.

Resources:

  1. https://developer.android.com/guide/topics/ui/layout/cardview– Article on How to Create a card based layout by Android Developer Documentation 
  2. https://stackoverflow.com/questions/5049852/android-drawing-separator-divider-line-in-layout – Stack Overflow post to create separator line

 

 

Continue ReadingCreating the onScreen Monitor Using CardView

Saving Sensor Data in CSV format

PSLab Android app by FOSSASIA provides a variety of features to its users. One of them is accessing various types of sensors both built into mobile phone and external sensors connected with PSLab device. In earlier versions users were only able to view the captured data. Moving forward, adding improvements to the app, now there is a feature to save those data displayed in graphs in csv format.

This feature is important in many ways. One is educational. In a classroom, teachers can ask students to perform an experiment and prepare a report using the data collected. By just visualizing they cannot do this. Actual data points must be made available. Another use is sharing data sets related to say environmental data over different demographics.

CSV, or comma-separated values file is a text file where stored data are separated by commas. The file stores these tabular data (numbers and text) in plain text format. Each line of the file represents a data record. Each data record consists of one or more fields, separated by commas. CSV files are commonly used to store sensor data because of its easy use. This post is about how PSLab device uses CSV file to write sensor data in it.

In PSLab android source code, there is a dedicated class to handle read sensor data from different instruments called “CSVLogger”. Developers can easily instantiate this class wherever they want a data logging as follows;

CSVLogger logger = new CSVLogger(<SUBFOLDER>); 
logger .writeCSVFile("Heading1,Heading2,Heading3\n");

 
This will create a blank folder in “PSLab” folder in device storage.  The CSV file is generated with the following convention according to the date and time where data is saved in the file.

yyyymmdd-hhmmss.csv

A sample file would have a name like 20180710-07:30:28.csv inside the SUBFOLDER which is specific to each instrument. Folder name will be the one used when initiating the CSVLogger.

With this method, logging data is pretty easy. Simply create a string which is a comma seperated and ended with a new line character. Then simply call the writeCSVFile(data) method with the string as a parameter added to it. It will keep appending string data until a new file is created. File creation can be handled by developers at their own interests and preferences.

String data = String.valueOf(System.currentTimeMillis()) + "," + item.getX() + "," + item.getY() + "\n";
logger.writeCSVFile(data);

 

To bring out an example let’s view how it’s implemented in Lux Meter instrument. This is a good source one can refer to when adding this feature in fragments

inside a main activity. In Lux Meter, there is the parent activity named Lux Meter and inside that there are two fragments, one is fragmentdata and the other one is fragmentsettings. Data capturing and saving occurs inside fragmentdata.

Menu icon controlling happens in the parent activity and we have bound a variable across the main activity and child fragment as follows;

LuxMeterActivity parent = (LuxMeterActivity) getActivity();
if (parent.saveData) {/* Save Data */}

 
This makes it easier listening menu icon clicks and start/stop recording accordingly. How to handle menu icons is beyond the scope of this blog and you can find tutorials on how to do that in the Resources section at the bottom of this blog post.

Once these CSV files are available, users can easily integrate them with advanced software like Matlab or Octave to do further analysis and processing to captured data sets.

Resources:

  1. CSV Logger: https://github.com/fossasia/pslab-android/blob/development/app/src/main/java/org/fossasia/pslab/others/CSVLogger.java
  2. Android Menu options: https://stackoverflow.com/questions/27984041/android-correct-use-of-invalidateoptionsmenu
Continue ReadingSaving Sensor Data in CSV format

Creating the Mockup for Wave Generator using Moqups

PSLab is a versatile device that can be used as a waveform signal generator, as it is capable of producing different types of waves. It provides a cheap and portable alternative as compared to the physical wave generators available in markets.

The current UI of the Wave Generator present in the PSLab app as shown in Figure 1 is very basic and makes use of some basic UI components which are not able to properly expose all the functionalities of the wave generator. This affects the user experience negatively.

Figure 1 shows the current layout of Wave Generator in PSLab android app

In this blog, we will discuss creating a mockup for the PSLab wave generator using modern design to improve the UI/UX of the app. I will try to keep the layout simple enough so that users can easily understand it. 

Understanding the Functionality of Waveform Generator

Figure 2 shows the schematic pin diagram of the PSLab

We can observe from the image that PSLab provide:

  • Two pins named W1 and W2 which are capable of producing two different sine or saw-tooth waves having different characteristics simultaneously.
  • Four Pins named SQ1, SQ2, SQ3, SQ4 which are capable of producing Square Wave and Pulse Width modulation signals.
  • It also allows us to change the properties of these waves such as frequency, phase, duty cycle.

Before starting with the mockup a physical commodity Waveform Signal Generator as shown in Figure 3 was inspected.

Figure 3 shows digital Wave Generator by HP

Most waveform generators in the market have a control panel with buttons and a monitor screen so that the user can view the changes while controlling the characteristics of the wave. I will try to create a layout similar to this in following steps by dividing it into two halves:

  1. Upper half containing monitor screens
  2. Lower half containing controlling panel having buttons

Steps for creating the mockup

Step 1: Choosing the Tool

The tool that we will be using here to create a mockup is moqups[1].

I have chosen this software because:-

  • It is an online tool and doesn’t require it to be set up first
  • It is very efficient and powerful tool for creating mobile or web wireframes.
  • It doesn’t require any prior knowledge of programming language.
  • It has a palette to drag & drop UI elements like Buttons, Textboxes, Checkboxes etc. on the left-hand side, allows modifying the features of each element (here on the right) and other options at the top related to prototyping, previewing etc as shown in figure 4.
Figure 4  shows Moqups prototyping tool webpage

Step 2: Creating the base of the layout

The mockup tool moqups[1] have a built-in template of Android screen which we can drag and drop from the palette and use it as our base.

Figure 5 shows the Android mobile template picked from the palette of available design elements in the ‘moqups’ application.

Step 3: Creating the Lower Half

Now as discussed above I will create controlling panel containing buttons in the lower half of the screen, for this I will drag and drop buttons from the palette on the right-hand side and design them according to the theme of the app that is making their border round shape, changing their color to match the theme color and editing text in them. As the PSLab has two groups of pins so I will create two different panels with buttons for properties related to the pins of that group.

At this point we have a layout looking like this:

Figure 6 shows the lower panel containing buttons being drawn for Wave Generator UI. At right-hand side, it shows the palette having different UI elements.

I will create the monitor screens in the upper half, for our purpose as I have two panels we will create two monitor screen as shown in Figure 6. The left panel will correspond to the left panel and the right monitor will correspond to the right panel.

Step 4: Creating the Upper Half

For creating monitor, I will use simple rectangles with rounded borders and give the background black to resemble the monitor in physical devices.

I will also create some partitions in the monitor to make compartment. I will use these compartments to position the text view that represents the characteristics of the wave so that they are clearly visible.

Figure 7 shows two monitor layout with the black background being drawn using text areas and lines

So, in this layout the user will be able to see all the properties corresponding to one type of waveform on the monitor together so he/she doesn’t have to click the buttons, again and again, to see the different properties as he/she have to do in a physical device.

For instance let’s say, if the user wants to generate sine wave he/she will have to click the Wave 1 button in the panel below and on clicking,all the values of characteristics related to waveform produced by W1 pin will be visible together to the user in one screen which makes it easier for the user to analyze and set the values.

Therefore, the final layout produced is shown in Figure 7

Figure 8 shows final Wave Generator Mockup.

As we can see this layout is quite interactive and looks very appealing to the user and this will help to improve UI/UX of the app.

Resources

  1. Moqups prototyping tool website: https://moqups.com
  2. Youtube Video – How to use moqups
Continue ReadingCreating the Mockup for Wave Generator using Moqups

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

Creating Device Screen to show connection status of PSLab Device

For using the PSLab Device the user needs to connect the PSLab device to an Android Phone having a PSLab android app. So there should be a screen that should be able to show the proper status of the PSLab device connection to the android app dynamically and it should also contain instructions on “How to connect the device to the app”.

So, in this blog we will create a device screen which shows the proper status of the connection of the PSLab device with the phone.

First step will be designing the layout for the device screen, for this we will create a fragment named HomeFragment and for its layout we will make use of the Relative Layout as view group and then create a Linearlayout inside it and position it at the center so that it always appears at the center in different screen sizes.

Then inside the LinearLayout, we will create(as shown in respective order) :

  1. ImageView and TextView for showing the status of device connection.
  2. Linear Layout with multiple TextView showing instructions on “How to connect the device to the screen”.
  3. A TextView that will direct the user to a webview showing PSLab website.

After creating all the above views we have created the layout will look like this: –

Now for showing the PSLab connection status dynamically, we have to implement following logic:

  1. When the device is connected it should show the connected icon and text and hide the instructions.
  2. When the device is disconnected it should show the disconnected icon and text and also the instructions.

For this, we will create a method inside the HomeFragment Java file which make use of Arguments deviceConnected and deviceFound to store device connected status.

public static HomeFragment newInstance(boolean deviceConnected, boolean deviceFound) {
HomeFragment homeFragment = new HomeFragment();
homeFragment.deviceConnected = deviceConnected;
homeFragment.deviceFound = deviceFound;
return homeFragment;
}

When both arguments are true we will show the connected text and icon and hide the instructions.

And when both arguments are false we will show the disconnected text and icon and display the instructions.

if (deviceFound && deviceConnected) {
   tvConnectMsg.setVisibility(View.GONE);
   tvVersion.setText(scienceLab.getVersion());
   tvVersion.setVisibility(View.VISIBLE);
   imgViewDeviceStatus.setImageResource(R.drawable.icons8_usb_connected_100);
   tvDeviceStatus.setText(getString(R.string.device_connected_successfully));
} else {
 imgViewDeviceStatus.setImageResource(R.drawable.icons_usb_disconnected_100);
 tvDeviceStatus.setText(getString(R.string.device_not_found));
}

How do we know that the device is connected?

For this, we have to handle the USB Attach event [1] that is whenever the USB is connected the Android will give a broadcast of USB connected and on receiving that broadcast in the app we will replace the HomeFragment giving setting both arguments to true. 

We will create a Broadcast Receiver[2] in the main activity which executes it’s onReceive() method on receiving USB attach event.

private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
   public void onReceive(Context context, Intent intent) {
     String action = intent.getAction();
     if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
       UsbDevice device =  intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
       if(device!=null){                                                  
         getSupportFragmentManager().beginTransaction().replace(R.id.frame,                                            
           HomeFragment.newInstance(true, true)).commitAllowingStateLoss();
         }           
      }
   }
};

Here In the OnReceive Method, we will replace our device screen fragment by passing parameters deviceConnected = true and deviceFound = true to HomeFragment newInstance() method.

Every time we create a Receiver we have to bind corresponding intent filters with broadcast receivers when the application is created.

IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED);
registerReceiver(mUsbReceiver, filter);

Similarly, we also have to handle the USB Detach event [2], here we will create a Broadcast Receiver[2] which executes in onReceive() method whenever the device is detached and here inside onReceive() method we will replace our device screen by passing parameters deviceConnected = false and deviceFound = false to newInstance() method in HomeFragment.

private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
   public void onReceive(Context context, Intent intent) {
     String action = intent.getAction();
     if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {                                           
getSupportFragmentManager().beginTransaction().replace(R.id.frame,                                            
           HomeFragment.newInstance(false, false)).commitAllowingStateLoss();
         }           
      }
   }
};

Thus, as shown in fig. 2 we have shown the PSLab device connection status dynamically on the screen by handling the USB attach/detach events.

Figure 2 shows the UI of ‘Device Screen’ for the two possible status: ‘not connected’ and ‘connected’

Resources

  1. Codepool Blog – “How to monitor USB events on Android?” by Xiao Ling
  2. Vogella article “What is Broadcast Receiver and how to insert it your app?”
Continue ReadingCreating Device Screen to show connection status of PSLab Device

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