Thursday 26 February 2015

Proximity Sensor in Android Part-2

In my previous post, We have some basic understanding of Proximity sensor in android. You can go through that post if you have not seen yet.

http://androidconceptspp.blogspot.in/2015/02/proximity-sensor-in-android-part-1.html

In this post we will have some fun with proximity sensor. The sample application is something like below picture. When you put your finger near the proximity sensor, image will changed from icon launcher to heart shape and when you put away your finger launcher icon will be restored. Also a text will be displayed showing number of time this sensor has produced the value.



Now, let us create the required source code for the application.

MainActivity.java



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

public class MainActivity extends Activity implements SensorEventListener {

SensorManager sManager;
Sensor proximity;
TextView counter;
ImageView imageView;
static int count=0;

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

sManager = (SensorManager) getSystemService(SENSOR_SERVICE);
counter = (TextView) findViewById(R.id.sensor_counter);
counter.setText("");

proximity = sManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
if (proximity == null) {
counter.setText("Proximity Sensor Not Available");
}
imageView = (ImageView)findViewById(R.id.imageView1);
}

@Override
protected void onResume() {
super.onResume();
sManager.registerListener(this, proximity,
SensorManager.SENSOR_DELAY_NORMAL);
}

@Override
protected void onPause() {
super.onPause();
sManager.unregisterListener(this);
}

@Override
public void onSensorChanged(SensorEvent event) {
count++;
counter.setText("Count: "+count);
float approx = event.values[0];
if(approx<2.0){
imageView.setImageResource(R.drawable.ic_action_favorite);
}else{
imageView.setImageResource(R.drawable.ic_launcher);
}
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}
}

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:id="@+id/LinearLayout1"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical"
   android:paddingBottom="@dimen/activity_vertical_margin"
   android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin"
   tools:context="test.example.proximitysensoactivity.MainActivity" >

   <TextView
       android:id="@+id/textView1"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_gravity="center_horizontal"
       android:text="Proximity Sensor Fun"
       android:textSize="25sp"
       android:textStyle="bold"
       android:typeface="serif" />

   <TextView
       android:id="@+id/sensor_counter"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_gravity="center_horizontal"
       android:layout_marginTop="30dp"
       android:text="Medium Text"
       android:textAppearance="?android:attr/textAppearanceMedium" />

   <ImageView
       android:id="@+id/imageView1"
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_margin="50dp"
       android:layout_weight="1"
       android:src="@drawable/ic_launcher" />

</LinearLayout>

AndroidManifest.xml

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

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

   <application
       android:allowBackup="true"
       android:icon="@drawable/ic_launcher"
       android:label="@string/app_name"
       android:theme="@style/AppTheme" >
       <activity
           android:name=".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>




Proximity Sensor in Android Part-1

Proximity Sensor
It is one of the sensor which is available in almost all android devices.This sensor detects the near by objects and send a signal to the android device which you can be catched by Sensor framework. API provides by Sensor framework, you can use inside your application. The object that this sensors can detect is anything like human body part (hand, finger, ear etc) or any other objects.


Location of proximity sensor on your device


This is generally located in the upper part of device display area near the front speaker. Most of the device, this sensor gives only two values "NEAR" and "FAR". "NEAR" is approximately less than 5 cm. This is an event based sensor, so this sensors produce data only when there is a change it its values from NEAR to FAR and vice-versa. On some devices you will get float value.
Whenever you are on a "call" you generally put it near your ear, this sensors detects the ear and sends the signal that something is near its proximity. At that point of time many UI touch feature is disabled so that if some actionable buttons (stop call button) is touched even unintentionally, it will not be activated to close the call.This is one the main feature of this sensor.


How to use it ?


You can use this sensor in your application as a trigger point or as an event and can perform some funny action or the actions you wants.


First of all you need to check whether this sensor is available on your device or not...Most of the cases it will be for sure. Next, After checking that it is available in your device make a listener class which listens for this sensor events. You have to implements the SensorEventListener interface and implements the methods inside the listener class. Inside the onSensorChanged method you can capture the event values. Use this values according to your application requirements.


How to test?


To test your application for the sensor you need a physical device not an emulator.


1. Get an instance of SensorManager
1a. Get Available Sensor List
1b. Get a reference of Proximity Sensor
3. Implement SensorListener interface
4. Register your Listener
5. Unregister the Listener

public class ProximityActivity extends Activity implements SensorEventListener {
   SensorManager sManager;
   Sensor proximity;    

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_proximity);
       sManager=(SensorManager)getSystemService(SENSOR_SERVICE);
       proximity=sManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);       
       if(proximity!=null){
       Log.i(“Proximity”,”Device has Proximity Sensor”);
   }
   @Override
   protected void onResume() {
       super.onResume();
       sManager.registerListener(this, proximity, SensorManager.SENSOR_DELAY_NORMAL);
   }
   @Override
   protected void onPause() {
       super.onPause();
      sManager.unregisterListener(this);
   }

   @Override
   public void onSensorChanged(SensorEvent event) {                
    // use the sensor value here...it may be near or far
    // or value in cm then you can define your own value like below
     float value_0 = event.values[0];
           String proximity;
           if(value_0<=5.0)
               proximity="NEAR";
           else
               proximity="FAR";   
   }

   @Override
   public void onAccuracyChanged(Sensor sensor, int accuracy) {
   }
}


In the next part, we will create a live example using proximity sensor…….;)

Wednesday 25 February 2015

Make Your Own Camera Part-2




In this part, We will make our own camera something like above. We have two activities, main activity and camera activity. Once you click on start button in main activity, it will launch the Camera activity. Camera preview will be automatically started and you only need to click the Take button to capture the image. After taking the picture, when you click the OK button it will take you back to the main activity and currently taken Image will be shown in the Image View of Main activity.

First we will create Main Activity java class.


package media.manager;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.Activity;
import android.view.View;
import android.widget.ImageView;


import sub_activities.MyCameraActivity;


public class FunActivity extends Activity     
{


   private static final String TAG=FunActivity.class.getSimpleName();


   public static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 101;
   private Uri imageUri=null;
   ImageView imageView;


   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
       imageView = (ImageView)findViewById(R.id.imageView);
       
   }


   
   public void buttonCameraClick(View v){
       Intent takePicture = new Intent();
       takePicture.setClass(this,MyCameraActivity.class);
       startActivityForResult(takePicture, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
   }   


   @Override
   protected void onActivityResult(int requestCode, int resultCode, Intent data) {        


       if(requestCode==CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
   
           imageUri = data.getData();
           imageView.setImageURI(imageUri);
           }
           
       }            
   }



Next we will create a helper class which we will use inside the Picture activity class. This class contains all the events related to camera activities.

BackCameraController.java


package media.manager;


import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;


import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;


public class BackCameraController {


   private static final String TAG = BackCameraController.class.getSimpleName();


   private boolean hasBackCamera;


   public Camera getCamera() {
       return camera;
   }
   public interface BackCameraControllerListener{
       public void afterTakePicture(File pictureFile, boolean finish);
   }


   private Camera camera;
   private Camera.CameraInfo info;
   private BackCameraControllerListener cameraListener;


   private int backCameraId;
   private int rotation;


   public BackCameraController(Context context, int rotation) {


       try {
           cameraListener=(BackCameraControllerListener)context;
       } catch (ClassCastException e) {
           throw new ClassCastException(context.toString()
                   + " must implement BackCameraControllerListener");
       }


       if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
           backCameraId=getBackCameraId();
           hasBackCamera = backCameraId != -1;
       }


       info = new Camera.CameraInfo();
       this.rotation=rotation;
   }


   public boolean hasBackCamera() {
       return hasBackCamera;
   }


   public void getBackCameraInstance(SurfaceView surfaceView) {
       Log.i(TAG, "hasBackCamera 1: " + hasBackCamera());
       camera = null;
       if (hasBackCamera) {
           try {
               camera = Camera.open(backCameraId);
               Log.i(TAG, "Camera is open");
               SurfaceHolder surfaceHolder = surfaceView.getHolder();
               camera.setPreviewDisplay(surfaceHolder);
               setCameraDisplayOrientation(backCameraId);
               camera.startPreview();
               Log.i(TAG, "Start Preview");


               Camera.Parameters params = camera.getParameters();
               params.setJpegQuality(100);
               camera.setParameters(params);


           } catch (Exception e) {
               hasBackCamera = false;
               Log.i(TAG, "Before take picture \n"+e.toString());
           }
       }
   }


   public void takeBackPicture() {
       Log.i(TAG, "hasBackCamera 2: " + hasBackCamera);
       if (hasBackCamera) {
           camera.takePicture(null, null, mBackPicture);
       }
   }


   private Camera.PictureCallback mBackPicture = new Camera.PictureCallback() {
       @Override
       public void onPictureTaken(byte[] data, Camera camera) {


           File pictureFile = getBackMediaFile();
           if (pictureFile == null) {
               Log.i(TAG, "Error creating media file, check storage permissions");
               return;
           }
           try {
               Log.d(TAG, "File created");
               FileOutputStream fos = new FileOutputStream(pictureFile);
               fos.write(data);
               fos.close();
           } catch (Exception e) {
               Log.i(TAG, "File not found: " + e.getMessage());
           }
           cameraListener.afterTakePicture(pictureFile, true);
           releaseCamera();
           Log.i(TAG,"Camera is released");
       }
   };


   private File getBackMediaFile() {


       File pictureDirectory = new File(Environment.getExternalStorageDirectory(),"MyCamera");
       if(!ALF_HOME_DIRECTORY.exists()){
           if(!ALF_HOME_DIRECTORY.mkdir()){
               Log.i(TAG,"Home Directory does not Exists");
           }
       }


       String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
       File picture = new File(pictureDirectory.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
       Log.i(TAG, "mediaFile: " + picture);
       return picture;
   }


   public void releaseCamera() {
       if (camera != null) {
           camera.stopPreview();
           camera.release();
           camera = null;
       }
   }


   private int getBackCameraId() {
       int camId = -1;
       int numberOfCameras = Camera.getNumberOfCameras();
       Camera.CameraInfo ci = new Camera.CameraInfo();


       for (int i = 0; i < numberOfCameras; i++) {
           Camera.getCameraInfo(i, ci);
           if (ci.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
               camId = i;
           }
       }
       return camId;
   }


   private   void setCameraDisplayOrientation(int camId) {


       Camera.getCameraInfo(camId, info);
       int degrees = 0;


       switch (rotation) {
           case Surface.ROTATION_0: degrees = 0; break;
           case Surface.ROTATION_90: degrees = 90; break;
           case Surface.ROTATION_180: degrees = 180; break;
           case Surface.ROTATION_270: degrees = 270; break;
       }


       int result;
       if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
           result = (info.orientation + degrees) % 360;
           result = (360 - result) % 360;  // compensate the mirror
       } else {  // back-facing
           result = (info.orientation - degrees + 360) % 360;
       }
       camera.setDisplayOrientation(result);
   }
}

Next, we will create Camera Activity java class. This class has a layout which contain an three buttons Cancel, Take and OK. When you click the Take button it will take the photo and when you click OK it will be shown in first activity image view.



package media.manager;


import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;


import java.io.File;
import media.manager.BackCameraController;


public class MyCameraActivity extends Activity implements
       BackCameraController.BackCameraControllerListener
{


   private static final String TAG = MyCameraActivity.class.getSimpleName();


   BackCameraController cc;
   SurfaceView surfaceView;
   File picture;


   Button take, ok, cancel;


   boolean canFinish=false;
   boolean canTake=false;


   CameraTakeTask cameraTask;


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


       cc = new BackCameraController(this,270);
       surfaceView=(SurfaceView)findViewById(R.id.camera_surfaceView);
       take=(Button)findViewById(R.id.camera_button_take);
       ok=(Button)findViewById(R.id.camera_button_ok);
       cancel=(Button)findViewById(R.id.camera_button_cancel);


       ok.setEnabled(false);


       take.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               canTake=true;
               ok.setEnabled(true);
               cancel.setVisibility(View.INVISIBLE);
           }
       });


       ok.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {


               if(picture!=null){
                   Uri result = Uri.fromFile(picture);
                   Log.i(TAG, "Uri..... : "+result);
                   Intent data = new Intent(Intent.ACTION_PICK, result);
                   setResult(RESULT_OK, data);
               }else {
                   Toast.makeText(MyCameraActivity.this,"Wait..",Toast.LENGTH_SHORT).show();
               }


               if(canFinish)
                   finish();
           }
       });


       cancel.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               cc.releaseCamera();
               finish();
           }
       });


   }


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


       cameraTask=new CameraTakeTask();
       cameraTask.execute();
   }


   @Override
   protected void onPause() {
       super.onPause();
       if(cc!=null){
           if(cc.hasBackCamera()){
               cc.releaseCamera();
           }
           cc=null;
       }
   }


   @Override
   public void afterTakePicture(File pictureFile, boolean finish) {
       picture=pictureFile;
       canFinish=finish;
       ok.setEnabled(true);
   }


   class CameraTakeTask extends AsyncTask<Void,Void,Void>{


       int count=1;
       @Override
       protected Void doInBackground(Void... params) {
           if (cc!=null && cc.getCamera() == null) {
               cc.getBackCameraInstance(surfaceView);
           }else {
               Log.i(TAG, "Camera is occupied");
           }


           for (int i = 0; i < 10; i++) {
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               if(canTake) {
                   cc.takeBackPicture();
                   count++;
               }
               if(count>1)
                   break;
           }


           return null;
       }
   }


}

activity_main.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
   android:background="#f0800082">


   <TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="New Text"
       android:id="@+id/textView"
       android:layout_gravity="center_horizontal" />


   <ImageView
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:id="@+id/imageView"
       android:layout_gravity="center_horizontal"
       android:layout_weight="1"
       android:layout_margin="50dp"
       android:src="@drawable/ic_launcher" />


   <Button
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Start"
       android:id="@+id/my_camera_button"
       android:layout_gravity="center_horizontal"
andoid:onClick="buttonCameraClick"
       android:layout_margin="20dp" />
</LinearLayout>


activity_my_camera.xml


<FrameLayout 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:padding="2dp"
   tools:context="sub_activities.MyCameraActivity">


   <TextView
       android:text="@string/hello_world"
       android:layout_width="wrap_content"
       android:visibility="gone"
       android:layout_height="wrap_content" />


   <SurfaceView
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:id="@+id/camera_surfaceView"
       />


   <Button
       style="?android:attr/buttonStyleSmall"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@string/back_camera_ok"
       android:id="@+id/camera_button_ok"
       android:layout_gravity="end|bottom" />


   <Button
       style="?android:attr/buttonStyleSmall"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@string/back_camera_take"
       android:id="@+id/camera_button_take"
       android:layout_gravity="center_horizontal|bottom" />


   <Button
       style="?android:attr/buttonStyleSmall"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@string/back_camera_cancel"
       android:id="@+id/camera_button_cancel"
       android:layout_gravity="start|bottom" />


</FrameLayout>


Add following lines inside the your manifest.xml



<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="media.manager" >


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


   <uses-feature android:name="android.hardware.camera.autofocus" />
   <uses-feature android:name="android.hardware.camera" />
   <uses-permission android:name="android.permission.camera" />
   <uses-permission android:name="android.permission.CAMERA" />


   


   <application
       android:allowBackup="true"
       android:icon="@drawable/ic_launcher"
       android:label="MyCamera"
       android:theme="@style/AppTheme" >
       <activity
           android:name=".MainActivity"
           android:label="MyCamera"
           android:screenOrientation="portrait" >
           <intent-filter>
               <action android:name="android.intent.action.MAIN" />


               <category android:name="android.intent.category.LAUNCHER" />
           </intent-filter>
       </activity>
       <activity
           android:name=".MyCameraActivity"
           android:label="Camera"
           android:screenOrientation="portrait" >
       </activity>
      


</manifest>

To store picture in the mobile you need the permission for read and write using uses-permission tag like below inside manifest.xml

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

Hope you will get some thought about creating your own camera in a Android device. Enjoy......