Record audio using MediaRecorder in Android

Hi everyone!

More often than not, you might have come across Android applications that allow users to record memos, meetings and more. The quality of audio plays an important role in such applications. Recordings can also be saved and played later. Audio capture from an Android device is a bit more complicated than audio and video playback.

The MediaRecorder class is used to record audio and video. Through this post, we will learn how to record audio from a device microphone, save the audio and play it back.

Pre-requisites: Eclipse IDE, Android SDK

Create a new Activity class called RecordAudioActivity in any of your existing Android projects and add the following code!

RecordAudioActivity.java

import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class RecordAudioActivity extends Activity {

   private MediaRecorder mMediaRecorder;
   private MediaPlayer mPlayer;
   private String outputFile = null;
   private Button btnRecordStart;
   private Button btnRecordStop;
   private Button btnPlay;
   private Button btnStopPlay;
   private TextView mRecordStatus;
   
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_audio);
      
      mRecordStatus = (TextView) findViewById(R.id.tv_recordStatus);
   
      // store it to sd card
      outputFile = Environment.getExternalStorageDirectory().
    		  getAbsolutePath() + "/sampleAudioRecord.3gpp";

      mMediaRecorder = new MediaRecorder();
      mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
      mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
      mMediaRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
      mMediaRecorder.setOutputFile(outputFile);
      
      btnRecordStart = (Button)findViewById(R.id.start);
      btnRecordStart.setOnClickListener(new OnClickListener() {
		
		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			start(v);
		}
      });
      
      btnRecordStop = (Button)findViewById(R.id.stop);
      btnRecordStop.setOnClickListener(new OnClickListener() {
  		
  		@Override
  		public void onClick(View v) {
  			// TODO Auto-generated method stub
  			stop(v);
  		}
      });
      
      btnPlay = (Button)findViewById(R.id.play);
      btnPlay.setOnClickListener(new OnClickListener() {
  		
  		@Override
  		public void onClick(View v) {
  			// TODO Auto-generated method stub
				play(v);	
  		}
      });
      
      btnStopPlay = (Button)findViewById(R.id.stopPlay);
      btnStopPlay.setOnClickListener(new OnClickListener() {
  		
  		@Override
  		public void onClick(View v) {
  			// TODO Auto-generated method stub
  			stopPlay(v);
  		}
      });
   }

   public void start(View view){
	   try {
          mMediaRecorder.prepare();
          mMediaRecorder.start();
       } catch (IllegalStateException e) {
          e.printStackTrace();
       } catch (IOException e) {
          
           e.printStackTrace();
        }
	   
       mRecordStatus.setText("Record status: now recording");
       btnRecordStart.setEnabled(false);
       btnRecordStop.setEnabled(true);
       
     
   }

   public void stop(View view){
	   try {
	      mMediaRecorder.stop();
	      mMediaRecorder.release();
	      mMediaRecorder  = null;
	      
	      btnRecordStop.setEnabled(false);
	      btnPlay.setEnabled(true);
	      mRecordStatus.setText("Record status: Stopped recording");
	      
	     
	   } catch (IllegalStateException e) {
			e.printStackTrace();
	   } catch (RuntimeException e) {
			e.printStackTrace();
	   }
   }
  
   public void play(View view) {
	   try{
		   mPlayer = new MediaPlayer();
		   mPlayer.setDataSource(outputFile);
		   mPlayer.prepare();
		   mPlayer.start();
		   
		   btnPlay.setEnabled(false);
		   btnStopPlay.setEnabled(true);
		   mRecordStatus.setText("Record status: Playing audio");
		   
		 
	   } catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
   }
   
   public void stopPlay(View view) {
	   try {
	       if (mPlayer != null) {
	    	   mPlayer.stop();
	           mPlayer.release();
	           mPlayer = null;
	           btnPlay.setEnabled(true);
	           btnStopPlay.setEnabled(false);
	           mRecordStatus.setText("Record status: stopped playing");
	           
	           
	       }
	   } catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
   }

}

activity_audio.xml

<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"
    android:background="#FFFFFF"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_recordStatus"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="Record status:" />

    <ImageView
        android:id="@+id/iv_Microphone"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_below="@+id/text1"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="20dp"
        android:src="@drawable/audio_record" />

    <LinearLayout
        android:id="@+id/linear1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/micImage"
        android:layout_marginTop="10dp"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/start"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="start" />

        <Button
            android:id="@+id/stop"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:enabled="false"
            android:text="stop" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/linear2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/linear1"
        android:layout_marginTop="10dp"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/play"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:enabled="false"
            android:text="play" />

        <Button
            android:id="@+id/stopPlay"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:enabled="false"
            android:text="stop playing" />
    </LinearLayout>

</RelativeLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.app.test"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />
 
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
    <application
        android:allowBackup="true"
        android:configChanges="orientation|keyboardHidden"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name">
        <activity
            android:name="com.app.test.RecordAudioActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>     
        </activity>     
    </application>
</manifest>

In order to record audio, we first need to create an instance of the MediaRecorder class. We then need to set the microphone as the audio source and specify the format and name of the output file. The methods prepare(), start(), stop() and release() are called in respective order for playing/stopping of media content.

Save all changes and make sure no errors are present. Run the application on an Android device and you should see the following output!

output_1

output_2

output_3

Reference: Android audio capture

Using Proximity sensor in Android

Hello everyone!

The term proximity is basically the fact, condition or position of being near or close by in space. A proximity sensor is a device capable of detecting presence of nearby objects without any physical contact. Some of the Android phones in the market today come equipped with a proximity sensor.

Through this post, we will learn how to use a proximity sensor in Android. As mentioned in the developer’s guide, the Android platform provides a sensor that lets you determine how close the face of a device is to an object (known as the proximity sensor).

Begin by creating a new Activity called ProximityTestActivity in any of your existing Android projects and add the following code!

ProximityTestActivity.java


import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;

public class ProximityTestActivity extends Activity {
	/** Called when the activity is first created. */

	private TextView txtProximitySensor, txtMaxProximity, txtReadingProximity;
	private SensorManager mSensorManager;
	private Sensor mProximitySensor;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_proximity);
		
		txtProximitySensor = (TextView)findViewById(R.id.txtProximitySensor);
		txtMaxProximity = (TextView)findViewById(R.id.txtProximityMax);
		txtReadingProximity = (TextView)findViewById(R.id.txtProximityReading);

		mSensorManager = (SensorManager)getSystemService(
				Context.SENSOR_SERVICE);
		mProximitySensor = mSensorManager.getDefaultSensor(
				Sensor.TYPE_PROXIMITY);

		if (mProximitySensor == null){
			txtProximitySensor.setText("Proximity sensor is not present!"); 
		
		}else{
			txtProximitySensor.setText("Sensor present with name:" + " " +mProximitySensor.getName());
			txtMaxProximity.setText("Maximum Range: "
					+ String.valueOf(mProximitySensor.getMaximumRange()));
			mSensorManager.registerListener(proximitySensorEventListener,
					mProximitySensor,
					SensorManager.SENSOR_DELAY_NORMAL);
		}
	}

	SensorEventListener proximitySensorEventListener
	= new SensorEventListener(){
		@Override
		public void onAccuracyChanged(Sensor sensor, int accuracy) {
			// TODO Auto-generated method stub
		}

		@Override
		public void onSensorChanged(SensorEvent event) {
			// TODO Auto-generated method stub
			if(event.sensor.getType()==Sensor.TYPE_PROXIMITY)
			{
				txtReadingProximity.setText("Proximity Sensor Reading:"
						+ String.valueOf(event.values[0]));
			}
		}
	};
}

activity_proximity.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/txtProximitySensor"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/txtProximityMax"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/txtProximitySensor"/>

    <TextView
        android:id="@+id/txtProximityReading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/txtProximityMax"/>

</RelativeLayout>

Save all changes. Make sure no errors are present. Run the application on an Android device and you should see the following output!

output_1

output_2

Reference: Position sensors

What’s seen through [Glass]

Hey everyone!

Google Glass has been creating waves in the ocean of technology even since it’s inception at Google I/O 2012. The device has it’s own pros and cons and after having used it for over a month now, here’s a glimpse of what you see through;

[Glass]

This slideshow requires JavaScript.

Developing applications for Google Glass is pretty straightforward. Both the Mirror API and the GDK enable developers to create web based and native applications respectively for the wearable device. In addition, one can also try out various features that include winking to take photos, head angle detection, real time search and language translate options.

Recently, the second generation Google Glass device was launched in the United Kingdom that works with prescription glasses and has a detachable ear piece to improve voice-activated commands. To know more check out this space later…

Display static Google Maps in Android

Hi friends!

The Google Static Map web service enables developers to dynamically create a map image based on URL parameters (i.e. latitude, longitude, zoom level etc) sent through a standard HTTP request. When called it returns the map as an image allowing developers to display it on the user interface.

As mentioned on the developer’s page, the Google Static Maps API lets you embed a Google Maps image on your web page without requiring JavaScript or any dynamic page loading. The Google Static Map service creates your map based on URL parameters sent through a standard HTTP request and returns the map as an image that you can display on your web page.

Through this post, we will learn how to display a static Google map in Android.

Pre-requisites: Eclipse IDE, Android SDK

Create a new Activity class called TestStaticMapActivity in any of your existing Android projects and add the following code!

package com.app.test;

import java.io.IOException;
import java.io.InputStream;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.ImageView;

public class TestStaticMapActivity extends Activity {
	
	private ImageView iv;
	
	@Override
	public void onCreate(Bundle s){
		super.onCreate(s);
		setContentView(R.layout.activity_main);
		iv = (ImageView)findViewById(R.id.img1);
		new SendTask().execute();
		
	}
	
	private class SendTask extends AsyncTask<Bitmap, String, Bitmap>{

		@Override
		protected void onPostExecute(Bitmap bmp){
			iv.setImageBitmap(bmp);
		}

		@Override
		protected Bitmap doInBackground(Bitmap... params) {
			// TODO Auto-generated method stub
			Bitmap bm = getGoogleMapThumbnail(18.9750,72.8258);
			return bm;

		}	
		
	};

	public static Bitmap getGoogleMapThumbnail(double latitude, double longitude){
		
		String URL = "http://maps.google.com/maps/api/staticmap?center=" +latitude + "," + longitude + "&zoom=15&size=600x600&sensor=false";
		
		Bitmap bmp = null;
		HttpClient httpclient = new DefaultHttpClient();   
		HttpGet request = new HttpGet(URL); 

		InputStream in = null;
		try {
			in = httpclient.execute(request).getEntity().getContent();
			bmp = BitmapFactory.decodeStream(in);
			in.close();
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return bmp;
	}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
     
    <ImageView
        android:id="@+id/img1"
        android:layout_centerInParent="true"
        android:layout_width="match_parent"
        android:layout_height="fill_parent">
    </ImageView>

</RelativeLayout>

Do not forget to add the android.permission.INTERNET permission in your AndroidManifest.xml file.

Save all changes. Make sure no errors are present. Run the application on an Android device and you should see the following output!

output

Using JSoup in Android

Hello everyone!

As Android developers, we often need to call web services in order to fetch data from a server. We also need to parse the data for displaying it on the user interface. There are various parsers available that enable developers to retrieve data efficiently from a web service.

JSoup is one such open source library that provides an API for extracting and manipulating data. Basically, it is an HTML parser used for working with various HTML elements, attributes etc. It can also find and extract data, using DOM traversal or CSS selectors.

Through this post, we will learn how to use the JSoup library in Android

Pre-requisites: Eclipse IDE, Android SDK

Step 1: To start with let’s create a new Android application project called AndroidJSoupDemo with package name com.app.jsoupexample

JSoup implements the WHATWG HTML5 specification, and parses HTML to the same DOM as modern browsers do. In this case, we will parse an HTML page and display the data on the user interface.

Step 2: Create Activity class

Create the MainActivity class to parse HTML from a URL, file, or string. In this case, we have chosen a URL. JSoup will help create a sensible parse tree.

MainActivity.java

package com.app.jsoupexample;

import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {

	private static final String URL = "http://karanbalkar.com/2014/06/populate-highcharts-with-json-data-using-jquery/";
	ProgressDialog mProgressDialog;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		Button btnFetchData = (Button) findViewById(R.id.btnData);
		btnFetchData.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				new FetchWebsiteData().execute();
			}
		});

	}

	private class FetchWebsiteData extends AsyncTask<Void, Void, Void> {
		String websiteTitle, websiteDescription;

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			mProgressDialog = new ProgressDialog(MainActivity.this);
			mProgressDialog.setMessage("Loading...");
			mProgressDialog.setIndeterminate(false);
			mProgressDialog.show();
		}

		@Override
		protected Void doInBackground(Void... params) {
			try {
				// Connect to website
				Document document = Jsoup.connect(URL).get();
				// Get the html document title
				websiteTitle = document.title();
				Elements description = document.select("meta[name=description]");
				// Locate the content attribute
				websiteDescription = description.attr("content");
			} catch (IOException e) {
				e.printStackTrace();
			}
			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			// Set title into TextView
			TextView txttitle = (TextView) findViewById(R.id.txtData);
			txttitle.setText(websiteTitle + "\n" + websiteDescription);
			mProgressDialog.dismiss();
		}
	}
}

activity_main.xml

<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" >

    <TextView
        android:id="@+id/txtData"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center" />

    <Button
        android:id="@+id/btnData"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/txtData"
        android:text="@string/data" />

</RelativeLayout>

Note: Before running the application, make sure you add the android.permission.INTERNET in your AndroidManifest.xml file.

Save all changes. Make sure no errors are present. Run the project on an Android device and you should see the following output!

output_1

output_2

Populate Highcharts with JSON data using jQuery

Hello everyone!

Graphs and charts help make information easier to visualize. Developers can display charts for better analysis and understanding. Highcharts help develop interactive JavaScript charts for web pages. It is basically a charting library written in pure JavaScript, offering an easy way of adding charts to your web site or web application.

Through this post, we will learn how to populate and display a bar chart dynamically using JSON data received via a RESTful web service.

Pre-requisites: Eclipse IDE, Notepad , Apache Tomcat 7

Step 1: Create dynamic web project

Let’s first create a web project that exposes a web service to send JSON data. Launch Eclipse IDE and create a Dynamic Web Project called TestHttpJson. Create a new Service class called DataService and add the following code!

DataService.java

package com.example;

import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import org.json.JSONArray;
import org.json.JSONObject;

@Path("/rest")
public class DataService {

	@Context org.jboss.resteasy.spi.HttpResponse response;
	@Path("/json")
	@Produces("application/json")
	@GET
	public Response getJSONData() {

		Map<String, String> data1 = new HashMap<String,String>();
		data1.put( "key", "Computers");
		data1.put( "value","114");

		Map<String, Object> data2 = new HashMap<String, Object>();
		data2.put( "key", "Electronics");
		data2.put( "value","214");

		Map<String, Object> data3 = new HashMap<String, Object>();
		data3.put( "key", "Mechanical");
		data3.put( "value","514");

		JSONObject json1 = new JSONObject(data1);
		JSONObject json2 = new JSONObject(data2);
		JSONObject json3 = new JSONObject(data3);

		JSONArray array = new JSONArray();
		array.put(json1);
		array.put(json2);
		array.put(json3);

		JSONObject finalObject = new JSONObject();
		finalObject.put("student_data", array);

		response.getOutputHeaders().putSingle("Access-Control-Allow-Origin", "*");
		return Response.status(200).entity(finalObject.toString()).build();
	}

}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0">
	<display-name>TestHttpJson</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>

	<!-- Auto scan REST service -->
	<context-param>
		<param-name>resteasy.scan</param-name>
		<param-value>true</param-value>
	</context-param>

	<context-param>
		<param-name>resteasy.servlet.mapping.prefix</param-name>
		<param-value>/</param-value>
	</context-param>

	<listener>
		<listener-class>
			org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
	</listener>

	<servlet>
		<servlet-name>resteasy-servlet</servlet-name>
		<servlet-class>
			org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>resteasy-servlet</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>

</web-app>

Note: You need to include the REST API specific jars before running the application. Please refer this post for more information.

Now, run the project on the Tomcat server and enter the following URL,

http://localhost:8080/TestHttpJson/rest/json

You should see the JSON data in the browser page.

output_3

Step 2: Create HTML page

Next, we need to use HighCharts API to create our bar chart using JSON data of the web service. The jQuery.getJSON() method helps load JSON-encoded data from the server using a GET HTTP request.

index.html

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>College student data</title>
    <script type="text/javascript" src="js/jquery-1.9.1.js"></script>
    <script type="text/javascript" src="js/highcharts.js"></script>
    <script type="text/javascript">
        $(function () {
         
				var processed_json = new Array();	
				$.getJSON('http://localhost:8080/TestHttpJson/rest/json', function(data) {
		
					// Populate series
					for (i = 0; i < data.student_data.length; i++){
						processed_json.push([data.student_data[i].key, parseInt(data.student_data[i].value)]);
					}
				
				    // draw chart
					$('#container').highcharts({
					chart: {
						type: "column"
					},
					title: {
						text: "Student data"
					},
					xAxis: {
						allowDecimals: false,
						title: {
							text: "Branch of studies"
						}
					},
					yAxis: {
						title: {
							text: "Number of students"
						}
					},
					series: [{
						data: processed_json
					}]
				});	
			});
		});
    </script>
</head>
<body>
    <div id="container" style="height: 400px"></div>
</body>
</html>

Finally, open the above HTML page in the browser. If no errors occur, then you should see the following output!

output_1

output_2

In addition, one can also use the various chart types and options for better customization. Hope this helps! Thanks for visiting! :)

Tutorial #84: Implement SearchView in Android

Hi everyone!

Android allows developers to add search functionality to their application by implementing the user interface with a search dialog. The user can initiate a search from any activity where the search dialog or widget is available. Basically, a search dialog is a UI component that’s controlled by the Android system.

On the other hand, a search widget, an instance of SearchView provides a user interface for the user to enter a search query and submit a request to a search provider. It shows a list of query suggestions or results, if available, and allows the user to pick a suggestion or result to launch into.

In this tutorial, we will learn how to implement a SearchView in Android.

Pre-requisites: Eclipse IDE, Android SDK

Step 1: Let’s begin by creating a new Android application project called AndroidSearchViewExample with package name com.app.search. Set the minimum SDK version to API 11 and the target SDK version to API 19.

Step 2: Create searchable XML

Android uses the value android.intent.action.SEARCH for the action within the intent when calling your search activity. So you must include this string within your activity’s intent filters. If not included, your Activity would be ignored. Hence, one needs to create an XML file to configure your search.

Create a new folder called xml under the res folder and add the below Android XML file called searchable.xml as follows!

searchable.xml

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/contact"
    android:hint="@string/contact"
    android:includeInGlobalSearch="true"
    android:queryAfterZeroResults="true"
    android:searchMode="queryRewriteFromText"
    android:searchSettingsDescription="@string/contact"
    android:searchSuggestAuthority="com.android.contacts"
    android:searchSuggestIntentAction="android.provider.Contacts.SEARCH_SUGGESTION_CLICKED"
    android:searchSuggestIntentData="content://com.android.contacts/contacts/lookup" >

    <actionkey
        android:keycode="KEYCODE_CALL"
        android:queryActionMsg="call"
        android:suggestActionMsg="call" />

</searchable>

Step 3: Create Activity class

We would be using the search functionality to fetch all phone contacts. One can retrieve a list of contacts by matching the search string to all or part of the contact name data. The Contacts Provider allows multiple instances of the same name, so this technique can return a list of matches. This is what the Activity class finally looks like,

MainActivity.java

package com.app.search;

import android.app.Activity;
import android.app.SearchManager;
import android.app.SearchableInfo;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.SearchView;
import android.widget.TextView;

public class MainActivity extends Activity {

	private TextView displayText;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		displayText = (TextView)findViewById(R.id.searchViewResult);
		
		initSearchView();
	}

	private void initSearchView() {
		SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
		final SearchView searchView = (SearchView) findViewById(R.id.searchView);
		SearchableInfo searchableInfo = searchManager.getSearchableInfo(getComponentName());
		searchView.setSearchableInfo(searchableInfo);
	}

	@Override
	protected void onNewIntent(Intent intent) {
		if (ContactsContract.Intents.SEARCH_SUGGESTION_CLICKED.equals(intent.getAction())) {
			String displayName = getContactName(intent);
			displayText.setText(displayName);
		} else if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
			String query = intent.getStringExtra(SearchManager.QUERY);
			displayText.setText("search for: '" + query + "'...");
		}
	}

	private String getContactName(Intent intent) {
		Cursor phoneCursor = getContentResolver().query(intent.getData(), null, null, null, null);
		phoneCursor.moveToFirst();
		int colNameIndex = phoneCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
		String contactName = phoneCursor.getString(colNameIndex);
		phoneCursor.close();
		return contactName;
	}

}

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">AndroidSearchViewExample</string>
    <string name="hello_world">AndroidSearchViewExample</string>
    <string name="action_settings">Settings</string> 
    <string name="contact">find a contact&#8230;</string>
    <string name="search">Search</string>

</resources>

In order to fetch all contacts, you need the android.permission.READ_CONTACTS in your AndroidManifest.xml file as follows!

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.app.search"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="19" />

    <uses-permission android:name="android.permission.READ_CONTACTS" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.app.search.MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTask" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.intent.action.SEARCH" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            
               <meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchable" />
               
        </activity>
    </application>

</manifest>

Finally, save all changes. Make sure no errors are present. Run the application on an Android device. If no errors occur, then you should see the following output!

output_1

output_2

Reference: Android SearchView

Draw route between two places using Google Maps

The Google Maps API for Android enables developers to draw a custom route between two places by providing the latitude and longitude. For this reason, the Maps API includes the Polyline class. As the name suggests, a polyline is a list of points, where line segments are drawn between consecutive points.

Some of the properties of a polyline include:

1. Points

The vertices of the line. Line segments are drawn between consecutive points. A polyline is not closed by default; to form a closed polyline, the start and end points must be the same.

2. Color

Line segment color in ARGB format, the same format used by android.graphics.Color. The default value is black (0xff000000).

3. Width

Line segment width in screen pixels. The width is constant and independent of the camera’s zoom level. The default value is 10.

4. Visibility

Indicates if the polyline is visible or invisible, i.e., whether it is drawn on the map. An invisible polyline is not drawn, but retains all of its other properties. The default is true, i.e., visible.

Through this post, we will learn how to draw our own route between two places using Google Maps.

Pre-requisites: Eclipse IDE, Android SDK

Create a new Activity class called DrawRouteActivity in any of your existing Android projects and add the following code!

DrawRouteActivity.java

import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.widget.Toast;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;

public class DrawRouteActivity extends Activity {

	private GoogleMap googleMap;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		try {
			
			//load map
			initilizeMap();

			//specify latitude and longitude of both source and destination
			Polyline line = googleMap.addPolyline(new PolylineOptions()
			.add(new LatLng(19.0222, 72.8666), new LatLng(19.0180, 72.8448))
			.width(5)
			.color(Color.RED));

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	@SuppressLint("NewApi")
	private void initilizeMap() {
		if (googleMap == null) {
			googleMap = ((MapFragment) getFragmentManager().findFragmentById(
					R.id.map)).getMap();

			//check if map is created 
			if (googleMap == null) {
				Toast.makeText(getApplicationContext(),
						"Sorry! unable to create maps", Toast.LENGTH_SHORT)
						.show();
			}
		}
	}

	@Override
	protected void onResume() {
		super.onResume();
		initilizeMap();
	}

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
 
    <fragment
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
 
</RelativeLayout>

You need to include the following permissions in the AndroidManifest.xml file!

AndroidManifest.xml

   
    <permission
        android:name="com.app.maps.permission.MAPS_RECEIVE"
        android:protectionLevel="signature" />

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
  
    <!-- Required to show current location -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Finally, save all changes. Make sure no errors are present. Run the application on an Android device and you should see the following output!

output

Reference: Google Map – Polyline

Implement DrawerLayout in Android

Hello everyone!

Not too long ago, Google had introduced a new sliding panel menu to navigate between different parts of an Android application. This new concept called Navigation Drawer helps to display the application’s main navigation options on the left edge of the screen. As mentioned in the Android developer documentation, the Navigation Drawer panel is hidden most of the time, but is revealed when the user swipes a finger from the left edge of the screen or, while at the top level of the app, the user touches the app icon in the action bar.

In order to add a navigation drawer we must first declare our user interface with a DrawerLayout. Through this post, we will learn how to implement a DrawerLayout in Android.

Pre-requisites: Eclipse IDE, Android SDK

In any of your existing Android projects, create a new Activity class called DrawerLayoutActivity and add the following code!

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.DrawerLayout.DrawerListener;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class DrawerLayoutActivity extends Activity {

	private DrawerLayout drawerLayout;
	private View drawerView;
	private DrawerListener myDrawerListener;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		drawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
		drawerView = (View)findViewById(R.id.drawer);
		drawerLayout.setDrawerListener(myDrawerListener);


		drawerView.setOnTouchListener(new OnTouchListener() {		   
			@Override
			public boolean onTouch(View arg0, MotionEvent arg1) {
				// TODO Auto-generated method stub
				return true;
			}
		});

		myDrawerListener = new DrawerListener(){

			@Override
			public void onDrawerClosed(View drawerView) {
				Log.i("App","Drawer closed");
			}

			@Override
			public void onDrawerOpened(View drawerView) {
				Log.i("App","Drawer open");

			}

			@Override
			public void onDrawerSlide(View drawerView, float slideOffset) {
			}

			@Override
			public void onDrawerStateChanged(int newState) {
				switch(newState){
				case DrawerLayout.STATE_IDLE:
					break;
				case DrawerLayout.STATE_DRAGGING:
					break;
				case DrawerLayout.STATE_SETTLING:
					break;
				default:
				}
			}
		};

	}
}

activity_main.xml

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:id="@+id/relativeLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/txt1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:paddingLeft="25dp"
            android:text="@string/swipeContent"
            android:textSize="20sp" />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#FFFFFF"
        android:orientation="vertical"
        android:padding="5dp" >

        <TextView
            android:id="@+id/txt2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/drawerContent"
            android:textSize="20sp" />
    </RelativeLayout>

</android.support.v4.widget.DrawerLayout>

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="drawerContent">Sample Drawer content</string>
    <string name="swipeContent">Swipe left to view drawer content</string>
</resources>

Save all changes and run the application on an Android device. If no errors occur, then you should see the following output!

output_1

output_2

A musical evening!

Last evening couldn’t have been much better. It’s not quite often that one witnesses ordinary people with extra-ordinary talent. World No Tobacco Day (WNTD) is observed around the world every year on May 31st. In order to spread the awareness of cancer, NGO Helping Hand had organized a special musical evening in Mumbai.

The event saw eminent personalities including Mrs. Priya Dutt, Mrs. Manisha Koirala and Mr. Johny Joseph felicitating cancer survivors. Luckily, I got a chance to attend the event, all thanks to Dada! :) The blind orchestra group Pride Of India delivered a breathtaking performance that mesmerized each individual present in the K.C College auditorium. It was the first time I had seen such an orchestra. At no point in time I felt the group went out of sync. The group brought back old Bollywood songs to life and presented the real picture of today’s India. On the whole, it was a wonderful musical experience and I look forward to attend many more such events! :)

Here are a few glimpses of the event!

IMG_20140531_192827714

IMG_20140531_193747083