Displaying images from SD card in Android

Hello friends!

In one of my earlier tutorials, we had learnt how to display images using the GridView layout in Android. Sometimes, developers need to fetch images from a SD card storage. In order to read or write files on the external storage, an Android application must acquire the READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE system permission.

Through this post, we will learn how to display images from a SD card in Android. In addition, we will display these images using a GridView.

Pre-requisites: Eclipse IDE, Android SDK

In any of existing Android projects create a new Activity class called DisplayImageActivity with package name com.example

Add the following code to your Activity class!

DisplayImageActivity.java

package com.example;

import java.io.File;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.widget.GridView;
import android.widget.Toast;

public class DisplayImageActivity extends Activity {

	private ImageAdapter imageAdapter;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_grid);

		GridView gridview = (GridView) findViewById(R.id.gridview);
		imageAdapter = new ImageAdapter(this);
		gridview.setAdapter(imageAdapter);

		String ExternalStorageDirectoryPath = Environment
				.getExternalStorageDirectory()
				.getAbsolutePath();

		String targetPath = ExternalStorageDirectoryPath + "/DCIM/Camera";

		Toast.makeText(getApplicationContext(), targetPath, Toast.LENGTH_LONG).show();
		File targetDirector = new File(targetPath);

		File[] files = targetDirector.listFiles();
		for (File file : files){
			imageAdapter.add(file.getAbsolutePath());
		} 
	}
}

ImageAdapter.java

package com.example;

import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;

public class ImageAdapter extends BaseAdapter {

	private Context context;
	ArrayList<String> imageList = new ArrayList<String>();

	public ImageAdapter(Context c) {
		context = c; 
	}

	void add(String path){
		imageList.add(path); 
	}

	@Override
	public int getCount() {
		return imageList.size();
	}

	@Override
	public Object getItem(int arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ImageView imageView;
		if (convertView == null) {  
			imageView = new ImageView(context);
			imageView.setLayoutParams(new GridView.LayoutParams(220, 220));
			imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
			imageView.setPadding(8, 8, 8, 8);
		} else {
			imageView = (ImageView) convertView;
		}

		Bitmap bm = decodeSampledBitmapFromUri(imageList.get(position), 220, 220);
		imageView.setImageBitmap(bm);
		return imageView;
	}

	public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth, int reqHeight) {

		Bitmap bm = null;
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(path, options);
		options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

		options.inJustDecodeBounds = false;
		bm = BitmapFactory.decodeFile(path, options); 

		return bm;   
	}

	public int calculateInSampleSize(

		BitmapFactory.Options options, int reqWidth, int reqHeight) {
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {
			if (width > height) {
				inSampleSize = Math.round((float)height / (float)reqHeight);    
			} else {
				inSampleSize = Math.round((float)width / (float)reqWidth);    
			}   
		}

		return inSampleSize;    
	}

}

activity_grid.xml

<LinearLayout 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:orientation="vertical">

    <GridView
        android:id="@+id/gridview"
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent"
        android:columnWidth="90dp"
        android:numColumns="auto_fit"
        android:verticalSpacing="10dp"
        android:horizontalSpacing="10dp"
        android:stretchMode="columnWidth"
        android:gravity="center"/>

</LinearLayout>

AndroidManifest.xml

Add the below permission in the manifest file!

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

output

Reference: Storage options in Android

Implement SwipeRefreshLayout in Android

Hello everyone!

The Android Support library got updated recently and now includes a new feature known as SwipeRefreshLayout. The SwipeRefreshLayout class is used whenever the user can refresh the contents of a view via a vertical swipe gesture. In order to get the latest update, one needs to open the Android SDK Manager and install the Android support library.

According to the Android developer guide, the layout should be made the parent of the view that will be refreshed. As a result, SwipeRefreshLayout can at present only support one direct child. If an activity wishes to show just the progress animation, it should call setRefreshing(true). To disable the gesture and progress animation, call setEnabled(false) on the view. Through this post, we will learn how to implement SwipeRefreshLayout in Android.

Pre-requisites: Eclipse IDE, Android SDK

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

SwipeToRefreshActivity.java

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;

public class SwipeToRefreshActivity extends Activity implements OnRefreshListener {

	private SwipeRefreshLayout swipeLayout;
	
	@SuppressLint("InlinedApi")
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.swipe_layout);

		swipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container);
		swipeLayout.setOnRefreshListener(this);
		swipeLayout.setColorScheme(android.R.color.holo_blue_bright, 
				android.R.color.holo_green_light, 
				android.R.color.holo_orange_light, 
				android.R.color.holo_red_light);
	}


	@Override public void onRefresh() {
		new Handler().postDelayed(new Runnable() {
			@Override public void run() {
				swipeLayout.setRefreshing(false);
			}
		}, 5000);
	}

}

Note: Make sure you add the android-support .jar file inside the libs folder of your project.

swipe_layout.xml

<android.support.v4.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipe_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
 
        <TextView
            android:text="@string/swipe"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:gravity="center"/>
    </ScrollView>
 
</android.support.v4.widget.SwipeRefreshLayout>

strings.xml

 <string name="swipe">Swipe down to refresh</string>

Run the application on an Android device. If no errors occur, then you should see the following output!

swipe_refresh_layout

Reference: SwipeRefreshLayout in Android

Tutorial #82: Connect to Dropbox using Android

Hello everyone!

Dropbox is a popular free service that helps share your files easily. It also provides certain API’s that developers can use to create applications that upload files directly on Dropbox. In order to connect to Dropbox, you first need to Create an Account on their website.

Once the account is created successfully, we can start writing our own applications using the Dropbox API’s. In order to create an application, visit the App Console and select the Create App option. In this tutorial we will learn how to create an Android application for uploading a file on Dropbox!

Pre-requisites: Eclipse IDE, Dropbox account, Android SDK

Step 1: Obtain API key and secret

On the App Console screen, click Create App and choose to create a new Dropbox API App. Select type of data as Files and Datastores and choose the option to access files the app will eventually create. Next, you need to provide an application name and Dropbox will generate an API key and secret for your application.

Step 2: Download Dropbox Android SDK

In order to use Dropbox functionalities, we need to download the Android SDK for Dropbox from over here. Add the .jar files that are required inside the libs folder once you create an Android project.

Step 3: Create Android project

Create a new Android application project called AndroidDropboxExample. Add the following Activity class in your src folder.

MainActivity.java

package com.app.dropbox;

import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import com.dropbox.client2.DropboxAPI;
import com.dropbox.client2.android.AndroidAuthSession;
import com.dropbox.client2.session.AccessTokenPair;
import com.dropbox.client2.session.AppKeyPair;
import com.dropbox.client2.session.Session.AccessType;
import com.dropbox.client2.session.TokenPair;

public class MainActivity extends Activity implements OnClickListener {

	private DropboxAPI<AndroidAuthSession> dropbox;

	private final static String FILE_DIR = "/MySampleFolder/";
	private final static String DROPBOX_NAME = "dropbox_prefs";
	private final static String ACCESS_KEY = "YOUR_API_KEY";
	private final static String ACCESS_SECRET = "YOUR_API_SECRET";
	private boolean isLoggedIn;
	private Button login;
	private Button uploadFile;
	

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

		login = (Button) findViewById(R.id.dropbox_login);
		login.setOnClickListener(this);
		uploadFile = (Button) findViewById(R.id.upload_file);
		uploadFile.setOnClickListener(this);
		

		loggedIn(false);

		AndroidAuthSession session;
		AppKeyPair pair = new AppKeyPair(ACCESS_KEY, ACCESS_SECRET);

		SharedPreferences prefs = getSharedPreferences(DROPBOX_NAME, 0);
		String key = prefs.getString(ACCESS_KEY, null);
		String secret = prefs.getString(ACCESS_SECRET, null);

		if (key != null && secret != null) {
			AccessTokenPair token = new AccessTokenPair(key, secret);
			session = new AndroidAuthSession(pair, AccessType.APP_FOLDER, token);
		} else {
			session = new AndroidAuthSession(pair, AccessType.APP_FOLDER);
		}

		dropbox = new DropboxAPI<AndroidAuthSession>(session);
	}

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

		AndroidAuthSession session = dropbox.getSession();
		if (session.authenticationSuccessful()) {
			try {
				session.finishAuthentication();

				TokenPair tokens = session.getAccessTokenPair();
				SharedPreferences prefs = getSharedPreferences(DROPBOX_NAME, 0);
				Editor editor = prefs.edit();
				editor.putString(ACCESS_KEY, tokens.key);
				editor.putString(ACCESS_SECRET, tokens.secret);
				editor.commit();

				loggedIn(true);
			} catch (IllegalStateException e) {
				Toast.makeText(this, "Error during Dropbox authentication",
						Toast.LENGTH_SHORT).show();
			}
		}
	}

	public void loggedIn(boolean isLogged) {
		isLoggedIn = isLogged;
		uploadFile.setEnabled(isLogged);
		login.setText(isLogged ? "Logout" : "Login");
	}

	
	@SuppressWarnings("deprecation")
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.dropbox_login:

			if (isLoggedIn) {
				dropbox.getSession().unlink();
				loggedIn(false);
			} else {
				dropbox.getSession().startAuthentication(MainActivity.this);
			}
			break;
		case R.id.upload_file:
			UploadFileToDropbox upload = new UploadFileToDropbox(this, dropbox,
					FILE_DIR);
			upload.execute();
			break;

		default:
			break;
		}
	}
}

UploadFileToDropbox.java

package com.app.dropbox;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;

import com.dropbox.client2.DropboxAPI;
import com.dropbox.client2.exception.DropboxException;

public class UploadFileToDropbox extends AsyncTask<Void, Void, Boolean> {

	private DropboxAPI<?> dropbox;
	private String path;
	private Context context;

	public UploadFileToDropbox(Context context, DropboxAPI<?> dropbox,
			String path) {
		this.context = context.getApplicationContext();
		this.dropbox = dropbox;
		this.path = path;
	}

	@Override
	protected Boolean doInBackground(Void... params) {
		final File tempDir = context.getCacheDir();
		File tempFile;
		FileWriter fr;
		try {
			tempFile = File.createTempFile("file", ".txt", tempDir);
			fr = new FileWriter(tempFile);
			fr.write("Test file uploaded using Dropbox API for Android");
			fr.close();

			FileInputStream fileInputStream = new FileInputStream(tempFile);
			dropbox.putFile(path + "sample.txt", fileInputStream,
					tempFile.length(), null, null);
			tempFile.delete();
			return true;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (DropboxException e) {
			e.printStackTrace();
		}
		return false;
	}

	@Override
	protected void onPostExecute(Boolean result) {
		if (result) {
			Toast.makeText(context, "File Uploaded Successfully!",
					Toast.LENGTH_LONG).show();
		} else {
			Toast.makeText(context, "Failed to upload file", Toast.LENGTH_LONG)
			.show();
		}
	}
}

In order to configure your Android application to use Dropbox features, we need to add the following Activity in the AndroidManifest.xml file.

AndroidManifest.xml

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

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

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.app.dropbox.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.dropbox.client2.android.AuthActivity"
            android:configChanges="orientation|keyboard"
            android:launchMode="singleTask" >
            <intent-filter>

                <!-- Change this to be db- followed by your app key -->
                <data android:scheme="db-YOUR_API_KEY" />
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>

</manifest>

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">
 
    <Button
        android:id="@+id/dropbox_login"
        android:layout_width="match_parent"
        android:layout_centerInParent="true"
        android:layout_height="wrap_content"
        android:text="@string/login" />
 
    <Button
        android:id="@+id/upload_file"
        android:layout_below="@+id/dropbox_login"
        android:layout_centerInParent="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/upload"/>

</RelativeLayout>

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_1

output_2

output_3

Display list of WiFi networks in Android

Hello everyone!

Android provides the WiFiManager class for managing all aspects of WiFi connectivity. It is used to to define the names of various Intent actions that are broadcast upon any sort of change in WiFi state.

Through this post, we will learn how to display a list of available WiFi networks to which an Android device can be connected. The list can be viewed and updated, and attributes of individual entries can be modified.

Pre-requisites: Eclipse IDE, Android SDK

In any of your existing Android projects, create a new Activity named CheckWifiNetworkActivity and add the following code!

CheckWifiNetworkActivity.java

package com.app.wifi;

import java.util.List;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.widget.TextView;

public class CheckWifiNetworkActivity extends Activity {

	private StringBuilder sb = new StringBuilder();
	private TextView tv;
	List<ScanResult> scanList;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main); 
		tv= (TextView)findViewById(R.id.txtWifiNetworks);
		getWifiNetworksList();
	}

	private void getWifiNetworksList(){      
		IntentFilter filter = new IntentFilter();
		filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
		final WifiManager wifiManager = 
				(WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE);;
				registerReceiver(new BroadcastReceiver(){

					@SuppressLint("UseValueOf") @Override
					public void onReceive(Context context, Intent intent) {
						sb = new StringBuilder();
						scanList = wifiManager.getScanResults();
						sb.append("\n  Number Of Wifi connections :" + " " +scanList.size()+"\n\n");    
						for(int i = 0; i < scanList.size(); i++){
							sb.append(new Integer(i+1).toString() + ". ");
							sb.append((scanList.get(i)).toString());
							sb.append("\n\n");
						}

						tv.setText(sb);  
					}

				},filter);        
		wifiManager.startScan();
	}
}

activity.main.xml

<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/txtWifiNetworks"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"/>
 
</RelativeLayout>

Make sure you add the necessary permissions in the manifest file!

AndroidManifest.xml

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

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

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
   
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.app.wifi.MainActivity"
            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>

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

detect_wifi_network

Hope this helps. Stay tuned for more! 🙂

Tutorial #81: Using Volley networking library in Android

At Google I/O last year, the search engine giant showcased a faster way to make network requests within an Android application by introducing the Volley networking library. Volley includes a lot of features useful for managing network requests and their response caches in a fast and easy way.

One can use Volley to run simultaneous requests on a pool of threads that can be given priority over another. In addition, it can be used to handle JSON requests, image request or files of that size and nature.

In this tutorial, we will learn how to setup Volley for Android and write a sample code to make a JSON request.

Pre-requisites: Eclipse IDE, Android SDK, Windows 7 (64 bit)

Step 1: Clone the Volley repository

In order to clone the Volley repository you need to have git client installed on your machine. Open a new git window and run the following command:

F:\programs\volley> git clone https://android.googlesource.com/platform/frameworks/volley

If you don’t have the git client installed then you can download it from over here. Once the project has been cloned you need to obtain the .jar file. To generate volley.jar, move into volley directory (cd volley) and execute below commands.

android update project -p .

ant jar

The volley.jar file will get created inside the bin folder.

Step 2: Create Android project

Once we have obtained the .jar file we can go ahead and create a new Android application project called AndroidVolleyDemo.

As recommended, lets create first a Singleton class that will return an instance of RequestQueue and one of ImageLoader. Also, we need to include a method to add our request to the RequestQueue.

VolleySingleton.java

package com.app.volley;

import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

public class VolleySingleton {

	private static VolleySingleton instance;
	private RequestQueue requestQueue;
	private ImageLoader imageLoader;

	private VolleySingleton(Context context) {
		requestQueue = Volley.newRequestQueue(context);

		imageLoader = new ImageLoader(requestQueue, new ImageLoader.ImageCache() {
			private final LruCache<String, Bitmap> cache = new LruCache<String, Bitmap>(20);


			@Override
			public Bitmap getBitmap(String url) {
				return cache.get(url);
			}

			@Override
			public void putBitmap(String url, Bitmap bitmap) {
				cache.put(url, bitmap);
			}
		});
	}


	public static VolleySingleton getInstance(Context context) {
		if (instance == null) {
			instance = new VolleySingleton(context);
		}
		return instance;
	}

	public RequestQueue getRequestQueue() {
		return requestQueue;
	}

	public ImageLoader getImageLoader() {
		return imageLoader;
	}

	public <T> void addToRequestQueue(Request<T> req) {
		req.setTag("App");
		getRequestQueue().add(req);
	}

}

Now, let’s create our Activity class as follows!

MainActivity.java

package com.app.volley;

import org.json.JSONObject;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.widget.TextView;
import com.android.volley.Request.Method;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.JsonObjectRequest;

public class MainActivity extends Activity {

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

		responseText = (TextView)findViewById(R.id.txt1);
		
		String url = "http://echo.jsontest.com/key/value/one/two";

		final ProgressDialog pDialog = new ProgressDialog(this);
		pDialog.setMessage("Loading...");
		pDialog.show();     

		JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.GET,
				url, null,
				new Response.Listener<JSONObject>() {

			@Override
			public void onResponse(JSONObject response) {
				Log.d("App", response.toString());
				responseText.setText("Response:" + " " +response.toString());
				pDialog.hide();
			}
		}, new Response.ErrorListener() {

			@Override
			public void onErrorResponse(VolleyError error) {
				VolleyLog.d("App", "Error: " + error.getMessage());
				// hide the progress dialog
				pDialog.hide();
			}
		});

		VolleySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsonObjReq);
		
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {

		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
}

Do not forget to add the Internet permission in the AndroidManifest.xml file!

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

Finally, run the application on an Android device. If no errors occur, you should see the response of the JSON request! 🙂

output

Display graphs using GraphView in Android

Hello everyone!

There are a few libraries available out there using which developers can programmatically create diagrams and graphs on a mobile platform. We often require solutions to display simple bar histograms, line graphs and other data visualizations.

GraphView is a library for Android to create flexible and nice-looking line and bar diagrams. It is easy to understand, to integrate and to customize it. Through this post, we will learn how to integrate GraphView in Android.

Step 1: Download the GraphView source

You first need to obtain the GraphView library project from over here. Import the project in Eclipse. Alternatively, one can also download the .jar file for the same.

Step 2: Create Android project

Create a new Android application project called AndroidGraphView with package name com.app.graph

We would be creating a real time graph using the GraphView library. Create a new class called RealtimeGraph and add the following code!

RealtimeGraph.java

package com.app.graph;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.widget.LinearLayout;
import com.jjoe64.graphview.BarGraphView;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.GraphView.GraphViewData;
import com.jjoe64.graphview.GraphViewSeries;
import com.jjoe64.graphview.LineGraphView;

public class RealtimeGraph extends Activity {
	
	private final Handler mHandler = new Handler();
	private Runnable mTimer1;
	private Runnable mTimer2;
	private GraphView graphView;
	private GraphViewSeries exampleSeries1;
	private GraphViewSeries exampleSeries2;
	private double graph2LastXValue = 5d;
	private GraphViewSeries exampleSeries3;
	
	//change graphType to line if bar chart not required
	private String graphType = "bar";

	private double getRandom() {
		double high = 3;
		double low = 0.5;
		return Math.random() * (high - low) + low;
	}

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.graphs);

		//example series data
		exampleSeries1 = new GraphViewSeries(new GraphViewData[] {
				new GraphViewData(1, 2.0d)
				, new GraphViewData(2, 1.5d)
				, new GraphViewData(2.5, 3.0d) 
				, new GraphViewData(3, 2.5d)
				, new GraphViewData(4, 1.0d)
				, new GraphViewData(5, 3.0d)
		});
		exampleSeries3 = new GraphViewSeries(new GraphViewData[] {});
		exampleSeries3.getStyle().color = Color.CYAN;

		
		if (graphType.equalsIgnoreCase("bar")) {
			graphView = new BarGraphView(
					this 
					, "GraphViewDemo" 
					);
		} else {
			graphView = new LineGraphView(
					this // context
					, "GraphViewDemo" 
					);
		}
		graphView.addSeries(exampleSeries1); 
		graphView.addSeries(exampleSeries3);

		LinearLayout layout = (LinearLayout) findViewById(R.id.graph1);
		layout.addView(graphView);

		// ----------
		exampleSeries2 = new GraphViewSeries(new GraphViewData[] {
				new GraphViewData(1, 2.0d)
				, new GraphViewData(2, 1.5d)
				, new GraphViewData(2.5, 3.0d) 
				, new GraphViewData(3, 2.5d)
				, new GraphViewData(4, 1.0d)
				, new GraphViewData(5, 3.0d)
		});

	
		if (graphType.equalsIgnoreCase("bar")) {
			graphView = new BarGraphView(
					this
					, "GraphViewDemo"
					);
		} else {
			graphView = new LineGraphView(
					this
					, "GraphViewDemo"
					);
			((LineGraphView) graphView).setDrawBackground(true);
		}
		
		graphView.addSeries(exampleSeries2);
		graphView.setViewPort(1, 8);
		graphView.setScalable(true);
		graphView.getGraphViewStyle().setGridColor(Color.BLACK);
		graphView.getGraphViewStyle().setHorizontalLabelsColor(Color.BLACK);
		graphView.getGraphViewStyle().setVerticalLabelsColor(Color.BLACK);

		layout = (LinearLayout) findViewById(R.id.graph2);
		layout.addView(graphView);
	}

	@Override
	protected void onPause() {
		mHandler.removeCallbacks(mTimer1);
		mHandler.removeCallbacks(mTimer2);
		super.onPause();
	}

	@Override
	protected void onResume() {
		super.onResume();
		mTimer1 = new Runnable() {
			@Override
			public void run() {
				exampleSeries1.resetData(new GraphViewData[] {
						new GraphViewData(1, getRandom())
						, new GraphViewData(2, getRandom())
						, new GraphViewData(2.5, getRandom()) 
						, new GraphViewData(3, getRandom())
						, new GraphViewData(4, getRandom())
						, new GraphViewData(5, getRandom())
				});
				exampleSeries3.resetData(new GraphViewData[] {
						new GraphViewData(2, getRandom())
						, new GraphViewData(2.5, getRandom()) 
						, new GraphViewData(3, getRandom())
						, new GraphViewData(4, getRandom())
				});
				mHandler.postDelayed(this, 300);
			}
		};
		mHandler.postDelayed(mTimer1, 300);

		mTimer2 = new Runnable() {
			@Override
			public void run() {
				graph2LastXValue += 1d;
				exampleSeries2.appendData(new GraphViewData(graph2LastXValue, getRandom()), true, 10);
				mHandler.postDelayed(this, 200);
			}
		};
		mHandler.postDelayed(mTimer2, 1000);
	}
}

GraphViewData.java

public class GraphViewData implements com.jjoe64.graphview.GraphViewDataInterface {
    private double x,y;

    public GraphViewData(double x, double y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public double getX() {
        return this.x;
    }

    @Override
    public double getY() {
        return this.y;
    }
}

GraphViewDataInterface.java

package com.app.graph;

public interface GraphViewDataInterface {
	public double getX();
	public double getY();
}

graphs.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/graph1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <LinearLayout
        android:id="@+id/graph2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" >
    </LinearLayout>

</LinearLayout>

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

android_graphview

Convert .apk file to .jar using dex2jar

Hey everyone!

Today, Android is an open source software stack for a wide range of mobile devices. Developers can easily obtain the source code from the Android Open Source Project and create their own applications. On the other hand, we can also reverse engineer the executable .apk file of an Android application and obtain the source code.

One of the ways of obtaining the underlying source code is by using the dex2jar library. Dex2jar is a lightweight API designed to read the Dalvik Executable (.dex/.odex) format.

The following steps are used to de-compile the apk!

Step 1: Obtain .apk file

You first need to obtain the .apk file of the application that you wish to decompile. For this purpose, third party applications like App Backup and Restore can be used. Rename the .apk file to a .zip file. Unzip the file to get the contents inside.

Step 2: Decompile .dex to .jar

Once the file is unzipped, one needs to decompile the classes.dex file. The dex file is the Dalvik executable file. The dex2jar tool is used to decode the .dex file to a .jar file as follows!

[On Windows-7]

C:\softwares\dex2jar> dex2jar.bat classes.dex

Step 3: View source code

Finally, you need to open the decoded .jar file using a decompiler of your choice. I would recommend downloading JD-GUI from over here.

output_1

Reference: Decompiling an Android apk file

Tutorial #80: Using Google Cloud Print in Android

Back in April 2010, Google had introduced Cloud Print as a solution for printing from the Chrome operating system. Google Cloud Print is nothing but a service that allows a print-aware application present on any device in the cloud to print to any printer.

Today, Google Cloud Print has been integrated with applications such as Google Docs allowing users to print from their mobile devices. Through this tutorial, we will learn how to create an Android application that uses the cloud print feature!

Pre-requisites: Eclipse IDE, Android SDK

Step 1: Let’s begin by creating a new Android application project called AndroidCloudPrintDemo with package name com.example

Step 2: Create Activity class

One way to print a file is using the “print” button from the application and selecting the file you want to print. Alternatively, one can also use the “share” button or menu item from almost any Android app and select “Cloud Print”. In this tutorial, we will go for the former approach.

MainActivity.java


import java.io.File;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity{

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

		btnPrint=(Button)findViewById(R.id.button1);

		btnPrint.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub

				if (isNetworkAvailable() == false) {
					Toast.makeText(MainActivity.this,
							"Network connection not available, Please try later",
							Toast.LENGTH_SHORT).show();
				} else {
					File file = new File("file://android_asset/sample.pdf");
					Intent printIntent = new Intent(MainActivity.this, PrintDialogActivity.class);
					printIntent.setDataAndType(Uri.fromFile(file), "application/pdf");
					printIntent.putExtra("title", "Android print demo");
					startActivity(printIntent);
				}
			}
		});
	}

	public boolean isNetworkAvailable() {

		ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo networkInfo = cm.getActiveNetworkInfo();
		// if no network is available networkInfo will be null
		// otherwise check if we are connected
		if (networkInfo != null && networkInfo.isConnected()) {
			Log.e("Network Testing", "***Available***");
			return true;
		}
		Log.e("Network Testing", "***Not Available***");
		return false;
	}


	@Override
	public boolean onCreateOptionsMenu(Menu menu) {

		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

}

Note: I have added a sample PDF file in my assets folder that I will be printing using the Cloud Print feature. Step 3: Integrate PrintDialogActivity class

Finally, you need to add the following code of the PrintDialogActivity class. The source code for the same can be obtained from over here.

PrintDialogActivity.java

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Intent;
import android.os.Bundle;
import android.util.Base64;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

public class PrintDialogActivity extends Activity {
	private static final String PRINT_DIALOG_URL = "https://www.google.com/cloudprint/dialog.html";
	private static final String JS_INTERFACE = "AndroidPrintDialog";
	private static final String CONTENT_TRANSFER_ENCODING = "base64";

	private static final String ZXING_URL = "http://zxing.appspot.com";
	private static final int ZXING_SCAN_REQUEST = 65743;

	/**
	 * Post message that is sent by Print Dialog web page when the printing dialog
	 * needs to be closed.
	 */
	private static final String CLOSE_POST_MESSAGE_NAME = "cp-dialog-on-close";

	/**
	 * Web view element to show the printing dialog in.
	 */
	private WebView dialogWebView;

	/**
	 * Intent that started the action.
	 */
	Intent cloudPrintIntent;

	@SuppressLint("JavascriptInterface") @Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);

		setContentView(R.layout.print_dialog);
		dialogWebView = (WebView) findViewById(R.id.webview);
		cloudPrintIntent = this.getIntent();

		WebSettings settings = dialogWebView.getSettings();
		settings.setJavaScriptEnabled(true);

		dialogWebView.setWebViewClient(new PrintDialogWebClient());
		dialogWebView.addJavascriptInterface(
				new PrintDialogJavaScriptInterface(), JS_INTERFACE);

		dialogWebView.loadUrl(PRINT_DIALOG_URL);
	}

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent intent) {
		if (requestCode == ZXING_SCAN_REQUEST && resultCode == RESULT_OK) {
			dialogWebView.loadUrl(intent.getStringExtra("SCAN_RESULT"));
		}
	}

	final class PrintDialogJavaScriptInterface {
		public String getType() {
			return cloudPrintIntent.getType();
		}

		public String getTitle() {
			return cloudPrintIntent.getExtras().getString("title");
		}

		public String getContent() {
			try {
				ContentResolver contentResolver = getContentResolver();
				InputStream is = contentResolver.openInputStream(cloudPrintIntent.getData());
				ByteArrayOutputStream baos = new ByteArrayOutputStream();

				byte[] buffer = new byte[4096];
				int n = is.read(buffer);
				while (n >= 0) {
					baos.write(buffer, 0, n);
					n = is.read(buffer);
				}
				is.close();
				baos.flush();

				return Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return "";
		}

		public String getEncoding() {
			return CONTENT_TRANSFER_ENCODING;
		}

		public void onPostMessage(String message) {
			if (message.startsWith(CLOSE_POST_MESSAGE_NAME)) {
				finish();
			}
		}
	}

	private final class PrintDialogWebClient extends WebViewClient {
		@Override
		public boolean shouldOverrideUrlLoading(WebView view, String url) {
			if (url.startsWith(ZXING_URL)) {
				Intent intentScan = new Intent("com.google.zxing.client.android.SCAN");
				intentScan.putExtra("SCAN_MODE", "QR_CODE_MODE");
				try {
					startActivityForResult(intentScan, ZXING_SCAN_REQUEST);
				} catch (ActivityNotFoundException error) {
					view.loadUrl(url);
				}
			} else {
				view.loadUrl(url);
			}
			return false;
		}

		@Override
		public void onPageFinished(WebView view, String url) {
			if (PRINT_DIALOG_URL.equals(url)) {
				// Submit print document.
				view.loadUrl("javascript:printDialog.setPrintDocument(printDialog.createPrintDocument("
						+ "window." + JS_INTERFACE + ".getType(),window." + JS_INTERFACE + ".getTitle(),"
						+ "window." + JS_INTERFACE + ".getContent(),window." + JS_INTERFACE + ".getEncoding()))");

				// Add post messages listener.
				view.loadUrl("javascript:window.addEventListener('message',"
						+ "function(evt){window." + JS_INTERFACE + ".onPostMessage(evt.data)}, false)");
			}
		}
	}
}

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

output_3

Reference: Google Cloud Print for Android

Display circular ProgressBar in Android

Hello friends!

In the past we have discussed about creating and displaying a ProgressBar in Android. A ProgressBar, as the name suggests is basically used to indicate the progress of an operation.

By default the progress bar is a spinning wheel (an indeterminate indicator). However, one can also create a circular ProgressBar by applying certain custom attributes. More such styles can be found over here.

In order to create a circular progress bar we need to add a new XML file in the drawable folder. If no “drawable” folder exists then you can always create one.

Let’s name our XML as circular_progress_bar.xml and add the following code!

circular_progress_bar.xml

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="90"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="360">

    <shape
        android:innerRadiusRatio="3"
        android:shape="ring"
        android:thicknessRatio="7.0">
        <gradient
            android:centerColor="#007DD6"
            android:endColor="#007DD6"
            android:startColor="#007DD6"
            android:angle="0"
            android:type="sweep"
            android:useLevel="false" />
    </shape>

</rotate>

Now, inside any of your existing Activity layouts, add a new ProgressBar widget and apply the above drawable.

activity_main.xml

....
 <ProgressBar
                android:id="@+id/progressBar"
                style="?android:attr/progressBarStyleHorizontal"
                android:layout_width="150dp"
                android:layout_height="150dp"
                android:layout_centerHorizontal="true"
                android:indeterminate="false"
                android:max="100"
                android:progressDrawable="@drawable/circular_progress_bar" />
...

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

output

Back to where I belong!

Hey everyone!

The past two months have been really frustrating. I realized how incomplete my life is without blogging. There’s so much happening in the world of technology, that one can’t turn a blind eye to this boom.

So here I am. Back to square one; continuing from where I left. I plan to share many more tutorials on my experiences in Android, Oracle and popular open source programming libraries.

As they say, “When the going gets tough, the tough get going!” 🙂

i_am_back