Creating Activity for Visualizing Recorded Sensor Data from List Items

In previous blog Using RealmRecyclerView Adapter to Show Recorded Sensor Experiments[2], I  have created a DataLoggerActivity in PSLab Android app containing RecyclerView showing a list having all the recorded experiments where every list item shows the date, time and the sensor instrument used for recording the data, but there arises below questions:- What if the user wants to see the actual recorded data in form of a graph? How the user can see the location recorded along with the data on the map? How can the user export that data? There is no way I could show all of that information just on a list item so I created another activity called “SensorGraphViewActivity” the layout of that activity is shown in the figure below: The layout contains three views:- At the top there is graph view which I created using Android MP chart which will show the recorded data plotted on it forming the exact same curve that was created while recording it, this way it is useful to visualize the data and also there is also a play button on the top which simulates the data as it was being plotted on the graph in real time. In the middle, there is a Card view containing two rows which will simply show the date and time of recording. At the bottom, there is a Map view which shows the location of the user which would be fetched when the user recorded the data. This is the gist of the layout file created for the activity. But now the question arises:- How to show the data in the activity for the item that the user wanted? For that, I implemented click listener on every list item by simply adding it inside the onBindViewHolder() method @Override public void onBindViewHolder(@NonNull final ViewHolder holder, int position) { SensorLogged temp = getItem(position); holder.sensor.setText(temp.getSensor()); Date date = new Date(temp.getDateTimeStart()); holder.dateTime.setText(String.valueOf(sdf.format(date))); holder.cardView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ... }); } and inside the click listener I performed following three steps:- First I stored the position of the item clicked inside a variable. int positionVar = holder.getAdapterPosition(); Then I used that position from the variable to fetch related data from the Realm database by simply using getItem() method which returns the SensorLogged[1] RealmObject at that position as I used a special type of RecyclerView Adapter called as RealmRecyclerViewAdapter[2]. int positionVar = holder.getAdapterPosition(); Then I created an Intent to open the SensorGraphViewActivity and passed the related data (i.e., sensortype, foreignkey, latitude, longitude, timezone, date, time) from SensorLogged[1] object to activity in form of extras. Intent intent = new Intent(context, SensorGraphViewActivity.class); intent.putExtra(SensorGraphViewActivity.TYPE_SENSOR, item.getSensor()); intent.putExtra(SensorGraphViewActivity.DATA_FOREIGN_KEY, item.getUniqueRef()); intent.putExtra(SensorGraphViewActivity.DATE_TIME_START,item.getDateTimeStart()); intent.putExtra(SensorGraphViewActivity.DATE_TIME_END,item.getDateTimeEnd()); intent.putExtra(SensorGraphViewActivity.TIME_ZONE,item.getTimeZone()); intent.putExtra(SensorGraphViewActivity.LATITUDE,item.getLatitude()); intent.putExtra(SensorGraphViewActivity.LONGITUDE,item.getLongitude()); context.startActivity(intent); And, in the SensorGraphViewActivity, I used getIntent() method to fetch all those extra data in the form of Bundle. For showing the data in the graph I used the foreign key fetched from the intent and queried all the LuxData[1] RealmObject containing that foreignkey in the form of RealmResult<LuxData>[2] ArrayList and used that list to populate the…

Continue ReadingCreating Activity for Visualizing Recorded Sensor Data from List Items

Using RealmRecyclerView Adapter to show list of recorded sensor data from Realm Database

In previous blog Storing Recorded Sensor Data in Realm Database we have stored the data fetched from sensors into the Realm Database by defining model classes. In this blog, we will use the data stored in the Realm to display a list of recorded experiments in the form of well defining card view items so that it is easier for the user to understand. For showing the list we will make use of RecyclerView  widget provided by Android which is a more advanced version of the List view and is used to display large data sets in a vertical list, horizontal list, grid, staggered grid etc. RecyclerView  works in accordance with RecyclerView Adapter which is core engine that is responsible of inflating the layout of list items, populating the items with data, recycling of list item views when they go out of viewing screen and much more. For this blog, we are going to use a special RecyclerView Adapter provided by Realm itself because it integrates properly with the Realm Database and handles modifying, addition, deletion or updating of Realm data automatically and efficiently.    Step 1 Adding the dependencies As always first we need to add the following code in our build.gradle file to add the dependency of Realm database and RealmRecyclerViewAdapter. dependencies { implementation"com.android.support:recyclerview-v7:27.1.1 " implementation 'io.realm:android-adapters:2.1.1' } Step 2 Adding RecyclerView widget in our Activity layout file First, we need to create an activity and name it as “DataLoggerActivity”, inside the layout of the Activity add the <RecyclerView> widget. This RecyclerView will act as a container of our list item. <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" tools:context=".activity.DataLoggerActivity"> <android.support.v7.widget.RecyclerView android:layout_below="@id/top_app_bar_layout" android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout> Step 3 Creating the layout and View holder for the list item We have to create the layout of the list item which will be inflated by the Adapter. So for this create an XML file in res folder and name it “data_list_item.xml”. For the list of the experiments, we want to show Name of the experiment, recording time, recording date for every list item. For this we will make use of <CardView> and <TextView>. This gist shows the code of xml file. The layout of the list item created is shown in Figure 2 Now we need to create a view holder for this layout which we need to pass to the Adapter, the following code shows the implementation of View Holder for above list item layout. public class ViewHolder extends RecyclerView.ViewHolder { private TextView sensor, dateTime; ImageView deleteIcon; private CardView cardView; public ViewHolder(View itemView) { super(itemView); dateTime = itemView.findViewById(R.id.date_time); sensor = itemView.findViewById(R.id.sensor_name); deleteIcon = itemView.findViewById(R.id.delete_item); cardView = itemView.findViewById(R.id.data_item_card); } } Step 4 Creating the adapter for RecyclerView   In this step, we will start by creating a class called “SensorLoggedListAdpater” and for using use the RecyclerView adapter provided by Realm we need to make this class extend the RealmRecyclerViewAdpater class. But for that we need to pass two generic parameter: Model Class : This is class which define a…

Continue ReadingUsing RealmRecyclerView Adapter to show list of recorded sensor data from Realm Database

Storing Recorded Sensor Data in Realm Database

PSLab android app provides various new features like accessing data from the sensors that are either inbuilt into the Android phone or common I2C sensors which are connected to the PSLab device through PIC microcontroller. But the problem is that if the user records the data one time he/she may not be able to view that data in the future as there was no way to save that data somewhere. Saved data can be used for school experiments, preparing reports, research purposes etc. So, now we have integrated Realm database with the Sensor Data Logger module which is a mobile database that can be used to store real-time data in fast and flawless manner. It is a object oriented database so it stores data in the form of objects which makes it usage with object oriented programming language like Java much easier. In this blog we will demonstrate the process of storing data from one instrument  i.e., Lux Meter which records illuminance with respect to time to understand the process. First, we have defined a model class “SensorLogged” which contains information pertaining to all one experiment performed by the user. It will have fields like time of start of recording, the time of the end of the recording, date of recording, sensor name etc. Whenever a user performs an experiment we will store a object of the SensorLogged model class in realm database containing info for that experiment. public class SensorLogged extends RealmObject { private String sensor; private long dateTimeStart; @PrimaryKey private long uniqueRef; private long dateTimeEnd; public SensorLogged(String sensor) { this.sensor = sensor; } public void setSensor(String sensor) { this.sensor = sensor; } public void setDateTimeStart(long dateTimeStart) { this.dateTimeStart = dateTimeStart; } public void setUniqueRef(long uniqueRef) { this.uniqueRef = uniqueRef; } public void setDateTimeEnd(long dateTimeEnd) { this.dateTimeEnd = dateTimeEnd; } }   For storing Lux data we have to define a model class “LuxData” which defines all the fields in one reading of experiment. public class LuxData extends RealmObject { private long foreignKey; private float lux; private long timeElapsed; public LuxData() { } public LuxData(float lux, long timeElapsed) { this.lux = lux; this.timeElapsed = timeElapsed; } public long getForeignKey() { return foreignKey; } public void setForeignKey(long foreignKey) { this.foreignKey = foreignKey; } } We will use the object of this class for every reading of one measurement and provide them with the same Foreign Key which will be Primary key uniqueRef of “SensorLogged” model class. In this way, we can query all the reading belonging to one measurement from the database containing all the LuxData entries. For storing the data in Realm database we will follow these steps: Begin the Realm transaction. realm.beginTransaction(); Create a object of “SensorLogged” model class for every measurement with the unique Ref as the primary key and store the information like time of start, date of start, sensor name etc. copy it to the Realm Database. SensorLogged sensorLogged = realm.createObject(SensorLogged.class, uniqueRef); sensorLogged.setSensor("Lux Meter"); sensorLogged.setDateTimeStart(startTime); realm.copyToRealm(sensorLogged); For every sensor, reading create a object of LuxData…

Continue ReadingStoring Recorded Sensor Data in Realm Database

Implement Sensor Data Fetching Using AsyncTask

In PSLab android app we have implemented sensor data fetching of various sensors inbuilt in the mobile device like light sensor, accelerometer, gyrometer. We can use PSLab to log the data and show in the form of the graph or maybe export the data in the form of CSV format for future use. But recording data from the phone sensor imposes a serious problem in the performance of the Android app as it is a costly to process in terms of memory, resources and time. In CS terms there is too much work that has to be done on the single main thread which sometimes leads to lag and compromises the UX. So as a solution we applied a concept of the Multithreading provided by Java in which we can shift the heavy process to a separate background thread so that the main thread never gets interrupted during fetching the sensor data and the background thread handles all the fetching and updates the UI as soon as it gets the data, till then the Main thread continues to serves the user so to user the application remains always responsive. For implementing this we used a special class provided by Android Framework called AsyncTask. Which provides below methods:- doInBackground() : This method contains the code which needs to be executed in the background. In this method, we can send results multiple times to the UI thread by publishProgress() method. onPreExecute() : This method contains the code which is executed before the background processing starts. onPostExecute() : This method is called after doInBackground method completes processing. Result from doInBackground is passed to this method. onProgressUpdate() : This method receives progress updates from doInBackground() method, which is published via publishProgress() method, and this method can use this progress update to update the UI thread. onCancelled(): This method is called when the background task has been canceled. Here we can free up resources or write some cleanup code to avoid memory leaks. We created a class SensorDataFetch and extended this AsyncTask class and override its methods according to our needs. private class SensorDataFetch extends AsyncTask<Void, Void, Void> implements SensorEventListener { private float data; private long timeElapsed; @Override protected Void doInBackground(Void... params) { sensorManager.registerListener(this, sensor, updatePeriod); return null; } protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); visualizeData(); } @Override protected void onPreExecute() { super.onPreExecute(); //do nothing } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); //do nothing } @Override protected void onCancelled() { super.onCancelled(); //do nothing } In doInBackground() method we implemented the fetching raw data from the sensor by registering the listener and in onPostExecute() method we updated that data on the UI to be viewed by the user. When this process is being run in the background thread the Main UI thread is free and remains responsive to the user. We can see in Figure 1 below that the UI is responsive to the user swipe action even when the sensor data is updating continuously on the screen.   Resources https://developer.android.com/reference/android/os/AsyncTask - Android Developer documentation for Async…

Continue ReadingImplement Sensor Data Fetching Using AsyncTask

Snackbar Implementation in PSLab Android App

In PSLab android app we have developed the functionality of logging sensor data in CSV format. We can start and stop the data recording using the save button in the upper right corner of the menu bar and toast message was shown to notify the user for logging status whether it is started or stopped but it leads to some problem like:- The user doesn’t know where the logged file has been created in the external storage. If the user accidentally clicked on the save button the data logging will start the user have to manually go the storage location and delete the recently created unwanted CSV file. What’s the solution? The solution to both these problem is solved by implementing Snackbar instead of Toast message. According to Material Design documentation:- The Snackbar widget provides brief feedback about an operation through a message at the bottom of the screen. Snackbar disappears automatically, either after a timeout or after a user interaction elsewhere on the screen, and can also be swiped off the screen. Snackbar can also offer the ability to perform an action, such as undoing an action that was just taken or retrying an action that had failed.     To implement the Snackbar in our Android app I started by creating a custom snack bar class which contains all the code to create and show the Snackbar on the screen. public class CustomSnackBar { public static void showSnackBar(@NonNull CoordinatorLayout holderLayout, @NonNull String displayText, String actionText, View.OnClickListener clickListener){ Snackbar snackbar = Snackbar.make(holderLayout,displayText,Snackbar.LENGTH_LONG) .setAction(actionText, clickListener); //do your customization here } The custom class contains a static method ‘showSnackBar()’ having parameters: Parameter Return Type Description holderLayout CoordinatorLayout Container layout in which the snack bar will be shown at the bottom (should not be null) displayText String Text to be displayed in the content of Snackbar (should not be null) actionText String Clickable text which has some action associated with it clickListener View.OnClickListener On click listener specifying an action to be performed when actionText is clicked   Inside the method, I called the static make()  method provided by the Snackbar class and passed holderlayout, displayText and duration of Snackbar in this case Snackbar.LENGTH_LONG as parameters. Then I called setAction() and passed in the actionText and the clickListener as parameters in it to set the action text. If we pass in null no action text will be generated. Then, if we want to changes the action text color we can do that by calling setActionTextColor() and passing in the desired color. snackbar.setActionTextColor(ContextCompat.getColor(holderLayout.getContext(), R.color.colorPrimary)); And if we want to change the content text color then we need to first get the view then we need to get the instance of TextView containing the content text using findViewById() and passing android.support.design.R.id.snackbar_text which is default ID for context TextView, and then call setTextColor() to set the desired color. View sbView = snackbar.getView(); TextView textView = sbView.findViewById(android.support.design.R.id.snackbar_text); textView.setTextColor(Color.WHITE); } So, now our Snackbar engine is complete now we need to call CustomSnackBar class static method showSnackbar() in our sensor data logger. For…

Continue ReadingSnackbar Implementation in PSLab Android App

Implementing Settings for Lux Meter Instrument in PSLab Android App

In PSLab android app, we have included sensor instruments which use either inbuilt sensor of smartphone or external sensor to record sensor data. For example, Lux Meter uses the light sensor to record lux data but the problem is that these instruments doesn’t contain settings option to configure the sensor record-setting like which sensor to use, change the update period etc. Therefore, we need to create a settings page for the Lux Meter instrument which allows the user to modify the properties of the sensor instrument. For that I will use Android Preference APIs to build a settings interface that is similar to setting activity in any other android app. The main building block of the settings activity is the Preference object. Each preference appears as a single setting item in an activity and it corresponds to key-value pair which stores the settings in default Shared Preferences file. Every time any setting is changed by the user the Android will store the updated value of the setting in the default shared preferences which we can read in any other activity across the app. In the following steps I will describe instruction on how to create the setting interface in Android app:  Step1 Include the dependency First, we need to include the dependency for v7 Preference Support Library by including the following code: dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:design:23.1.1' compile 'com.android.support:preference-v7:23.1.1' }  Step 2 Creating the preferences screen in XML For this step, I have created a preference screen which will be inflated when the settings fragment is being created. I created a file named  “lux_meter_settings.xml” and place it in the res/xml/ directory. The root node for the XML file must be a <PreferenceScreen> element. We have to add each Preference within this element. Each child I added within the <PreferenceScreen> element appears as a single item in the list of settings. The preference which I have used are: <EdittextPreference> This preference opens up a dialog box with edit text and stores whatever value is written by the user in the edit text. I have used this preference for inputting update period and high limit of data during recording. <CheckboxPreference> shows an item with a checkbox for a setting that is either enabled or disabled. The saved value is a boolean (true if it's checked). I have used this preference for enabling or disabling location data with the recorded data. <ListPreference> opens a dialog with a list of radio buttons. The saved value can be any one of the supported value types. I have used this preference to allow the user to choose between multiple sensor types. <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <EditTextPreference android:key="setting_lux_update_period" android:title="@string/update_period" android:dialogTitle="@string/update_period" android:defaultValue="1000" android:dialogMessage="Please provide time interval(in ms) at which data will be updated" android:summary="Update period is 900ms"/> <EditTextPreference android:key="setting_lux_high_limit" android:title="High Limit" android:dialogTitle="High Limit" android:defaultValue="2000" android:dialogMessage="Please provide maximum limit of LUX value to be recorded" android:summary="High Limit is 2000 Lux"/> <CheckBoxPreference android:defaultValue="false" android:key="include_location_sensor_data" android:summary="Include the location data in the logged file" android:title="Include Location…

Continue ReadingImplementing Settings for Lux Meter Instrument in PSLab Android App

Producing Waveforms using Wave Generator module in the PSLab Android App

This blog will demonstrate how to produce different waveforms using the Wave Generator module in the PSLab android app and view them on the Oscilloscope. The Wave Generator in PSLab android app is simple to use and has a UI which is similar to physical commodity wave generators. It is capable of producing different waveforms like sine, sawtooth and square wave. Apparatus Required Before getting started with the wave generator we require the following items: PSLab device An android phone with PSLab app installed in it. USB cable (Mini B) OTG(On the Go) wire Some connecting wires having pins at both ends Understanding the Wave Generator Pins Let me briefly explain the use of the pins that are going to be used in the Wave generator module: S1 and S2 pins The PSLab device contains two pins (S1, S2) which are capable of producing two independent analog waveforms (sine,  sawtooth) having different frequencies and phase offset. The frequency range is from 10Hz to 5Khz. SQR1, SQR2, SQR3 and SQR4 pin The SQR1 pin is used for producing the square waveform and all the SQ pins can be used together to produce four different PWM signal having the same frequency. These PWM signal can have a different duty cycle and phase. CH1, CH2 and CH3 pin The CH pins are used by the oscilloscope in the  PSLab android app to monitor waveform signals produced by the wave generator pins. They can be used together to simultaneously monitor multiple waveforms. Setting up the Device We need to connect the PSLab device with the mobile phone as shown in Figure 2 which can be done by following steps: Connect a micro USB(Mini B) to the PSLab device. Connect the other end of the micro USB cable to the OTG. Connect the OTG to the phone. Producing Waveforms Now, once the device has been properly connected to the device (which is shown at the top right corner of the app), then in the instruments page scroll down to the Wave Generator card and click on it to open the WaveGenerator activity. Here you will see a screen like shown in Figure 4 containing two monitors and a controlling panel with lots of buttons. Here the Waveform panel is used to control the S1 and S2 pins whose properties are shown on the left monitor screen and the Digital panel is used to control the SQR pins whose properties are shown on the right monitor screen. For sine/sawtooth wave: Connect the S1 pin to the CH1 pin using a connecting wire, then in the Waveform panel select the Wave1 button, choose the type of waveform(either sine or sawtooth), then click on the Freq button to change the frequency of the wave, then use the Seek bar or the up/down arrow buttons to change the value of frequency and then press the set button to set the frequency for the S1 pin as shown below: Now, click the view button at bottom right corner, this will directly…

Continue ReadingProducing Waveforms using Wave Generator module in the PSLab Android App

Implementing the discrete Seekbar for Wave Generator

The Wave Generator instrument in PSLab Android app allows us to produce waveforms having different values of properties like frequency, duty, phase etc. The range of these properties allowed by PSLab Device are : Table showing the range of properties that can be set for waves by PSLab device Wave Property Range Min Max Step Size Frequency 10 Hz 5000 Hz 1 Hz Phase 0° 360° 1° Duty 10% 100% 10% We can set these values using the up/down arrow buttons provided by the wave generator but the problem is that the range of values is very high and least counts are small so it is convenient to set the values using only the up and down arrow buttons. Therefore we need something that could allow us to directly set any value of our choice while keeping the UI interactive. The solution to this problem - “Discrete Seekbar”. It contains a slider having points at equal intervals and whose length represents the range of the values and a head that slides over the slider and is used to select a specific value from a range of values. I have included the discrete Seekbar in Wave Generator by using a third-party library if you want to add Seekbar directly you can do that by directly using the default Seekbar widget provided by Android SDK and setting the following attribute in as shown below. android:theme = “@style/Widget.AppCompat.SeekBar.Discrete” Refer to this post[2] for implementing Seekbar directly without an external library. The reason I chose this library is that:- It offers various implementation of different types of Seekbar like discrete and continuous. Implementation of Seekbar is simpler and it offers various customizations like thumb color, track color, tick text etc.   In following steps I will implement the discrete Seekbar: Step 1 Adding the dependency For this project, I will be using an external library “IndicatorSeekbarLibrary” by Warkiz[1], for adding the dependency we need to include the following code in our build.gradle file. dependencies{ implementation 'com.github.warkiz.widget:indicatorseekbar:2.0.9' } Step 2 Including the Seekbar in layout For this step, we need to add the Seekbar widget using <com.warkiz.widget.IndicatorSeekBar> XML tag in our wave generator layout file to include the Seekbar in our layout as shown in the code below: <com.warkiz.widget.IndicatorSeekBar android:layout_width="match_parent" android:layout_height="wrap_content" app:isb_max="5000" app:isb_min="0" app:isb_ticks_count="5" app:isb_thumb_color="@color/color_green" app:isb_thumb_size="20dp" app:isb_track_background_color="@color/color_gray" app:isb_track_background_size="2dp" app:isb_track_progress_color="@color/color_blue" app:isb_track_progress_size="4dp" /> Some important attributes used above: app:isb_max : defines the max value that can be achieved by the Seekbar. app:isb_min :  defines the min value that can be achieved by the Seekbar app:isb_ticks_count: no. of ticks(interval) that has to be shown on the slider We can see different components of Seekbar like track, indicator, thumb, tick of SeekBar in the following diagram[2]. Step 3 Attaching the listener to the Seekbar in Java file In this step we need to attach the listener to the Seekbar to record changes in the Seekbar made by the user, for this we will create a new listener with the help of onSeekBarChangeListener interface and attach it with the Seekbar as shown in following code…

Continue ReadingImplementing the discrete Seekbar for Wave Generator

Making Bottomsheet responsive using Custom Gesture Detector in PSLab Android App

In the previous blog Creating Instruction Guide using Bottomsheet, I have created the Bottom Sheet guide in instrument activities in PSLab Android app. But simply adding the Bottom Sheet in the layout is not enough as it could lead to some UI issues like no proper way to show or hide the Bottom Sheet, therefore, he/she will find it difficult to work with Bottom Sheet that could degrade User Experience. We need to make the Bottom Sheet responsive and interactive which we can do by capturing swipe gestures done by the user and overriding their functionality i.e. when the user slides up with the finger then the Bottom Sheet will reveal itself and when the user slides the finger down the Bottom Sheet will hide. For this Android provides a class GestureDetector which is used with another class SimpleOnGestureListener which acts as a listener to capture Gesture events like swipe, pinch, scroll, long press etc. In this blog, I will create a custom gesture listener that will listen to the swipe events and according to the gestures it will show/hide the Bottom Sheet. I will start by creating a gesture listener class called “SwipeGestureListener” extending the class ‘GestureDetector.SimpleOnGestureListener’ and also as I need swipe gestures to control the Bottom Sheet, so I will pass the reference of the Bottom Sheet as a parameter in the constructor. public class SwipeGestureListener extends GestureDetector.SimpleOnGestureListener{ private BottomSheetBehavior bottomSheet; public SwipeGestureDetector(BottomSheetBehavior bt) { bottomSheet = bt; } } Now in this listener class as we are concerned with the swipe events so will only override the below method provided by ‘GestureDetector.SimpleOnGestureListener’ interface public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) This method is called whenever the user swipes its finger in any direction. In the above code, we can see that the method provides with object e1 and e2 of type MotionEvent. The MotionEvent class is used to report movements in terms of Action Codes like ACTION_DOWN, ACTION_UP and also contains other information about the touch like the pressure of the touch, x and y coordinate, orientation of the contact area etc.  The e1 object will have the attribute values relating to the point when the swipe started and the e2 object will have attribute values relating to the point when the swipe has ended. Now, the main thing we need to determine if the direction of the swipe which is not directly available using the MotionEvent object. So, to determine the direction of the swipe I will fetch the coordinates of the initial point and terminal point of the swipe using the objects initial and final point i.e., e1 and e2. //Initial Point float x1 = e1.getX(), y1 = e1.getY(); //Final Point float x2 = e2.getX(), y2 = e2.getY(); Then, using these coordinates to calculate the angle of the swipe and based on the angle I will return the direction of the swipe as shown in the code below private Direction getDirection(float x1, float y1, float x2, float y2) { Double angle = Math.toDegrees(Math.atan2(y1 - y2,…

Continue ReadingMaking Bottomsheet responsive using Custom Gesture Detector in PSLab Android App

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 Sheet. Bottom 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 : 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. 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. Here is the gist[2] that contains code for the layout of the Bottom Sheet guide After this step, we can see a layout…

Continue ReadingCreating Instruction Guide using Bottomsheet