Android Accelerometer And Android Sensor Example

HOW TO DETECT FORWARD AND BACKWARD TILT

A lot of charade games use this feature to do an action on forward or backward tilt.  This tutorial will show you how to detect forward and backward tilts when the phone is in landscape mode. You can check out  Bollywood Charades the app I’ve created using this feature to see how it works.

AndroidManifest

This specific code detects tilt movements in landscape mode. So add android:screenOrientation=”landscape” to the manifest file first.

File: AndroidManifest.xml

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

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="21" />

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

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

</manifest>

You can make it work to detect vertical tilt movements by changing the inclination in the isTiltUpward and isTiltDownward method.

Implement Sensors

We’ll be using the accelerometer and geomagnetic field sensor to accomplish this. Move on and implement the code below in your MainActivity.

File: MainActivity.java

package com.ahotbrew.detecttilt;

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.util.Log;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity implements SensorEventListener {

	private SensorManager mSensorManager;
	private Sensor accelerometer;
	private Sensor magnetometer;

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

		mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

		accelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
		magnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

		initListeners();
	}

	public void initListeners()
	{
		mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_FASTEST);
		mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_FASTEST);
	}

	@Override
	public void onDestroy()
	{
		mSensorManager.unregisterListener(this);
		super.onDestroy();
	}

	@Override
	public void onBackPressed()
	{
		mSensorManager.unregisterListener(this);
		super.onBackPressed();
	}

	@Override
	public void onResume()
	{
		initListeners();
		super.onResume();
	}

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

	float[] inclineGravity = new float[3];
	float[] mGravity;
	float[] mGeomagnetic;
	float orientation[] = new float[3];
	float pitch;
	float roll;

	@Override
	public void onSensorChanged(SensorEvent event) {
		//If type is accelerometer only assign values to global property mGravity
		if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
		{
			mGravity = event.values;
		}
		else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
		{
			mGeomagnetic = event.values; 

			if (isTiltDownward())
			{
				Log.d("test", "downwards");
			}
			else if (isTiltUpward())
			{
				Log.d("test", "upwards");
			}
		}

	}

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

	}

	public boolean isTiltUpward()
	{
		if (mGravity != null && mGeomagnetic != null)
		{
			float R[] = new float[9];
			float I[] = new float[9];

			boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);

			if (success)
			{
				float orientation[] = new float[3];
				SensorManager.getOrientation(R, orientation); 

				/*
				* If the roll is positive, you're in reverse landscape (landscape right), and if the roll is negative you're in landscape (landscape left)
				*
				* Similarly, you can use the pitch to differentiate between portrait and reverse portrait.
				* If the pitch is positive, you're in reverse portrait, and if the pitch is negative you're in portrait.
				*
				* orientation -> azimut, pitch and roll
				*
				*
				*/

				pitch = orientation[1];
				roll = orientation[2]; 

				inclineGravity = mGravity.clone();

				double norm_Of_g = Math.sqrt(inclineGravity[0] * inclineGravity[0] + inclineGravity[1] * inclineGravity[1] + inclineGravity[2] * inclineGravity[2]);

				// Normalize the accelerometer vector
				inclineGravity[0] = (float) (inclineGravity[0] / norm_Of_g);
				inclineGravity[1] = (float) (inclineGravity[1] / norm_Of_g);
				inclineGravity[2] = (float) (inclineGravity[2] / norm_Of_g);

				//Checks if device is flat on ground or not
				int inclination = (int) Math.round(Math.toDegrees(Math.acos(inclineGravity[2]))); 

				/*
				* Float obj1 = new Float("10.2");
				* Float obj2 = new Float("10.20");
				* int retval = obj1.compareTo(obj2);
				*
				* if(retval > 0) {
				* System.out.println("obj1 is greater than obj2");
				* }
				* else if(retval < 0) {
				* System.out.println("obj1 is less than obj2");
				* }
				* else {
				* System.out.println("obj1 is equal to obj2");
				* }
				*/
				Float objPitch = new Float(pitch);
				Float objZero = new Float(0.0);
				Float objZeroPointTwo = new Float(0.2);
				Float objZeroPointTwoNegative = new Float(-0.2);

				int objPitchZeroResult = objPitch.compareTo(objZero);
				int objPitchZeroPointTwoResult = objZeroPointTwo.compareTo(objPitch);
				int objPitchZeroPointTwoNegativeResult = objPitch.compareTo(objZeroPointTwoNegative);

				if (roll < 0 && ((objPitchZeroResult > 0 && objPitchZeroPointTwoResult > 0) || (objPitchZeroResult < 0 && objPitchZeroPointTwoNegativeResult > 0)) && (inclination > 30 && inclination < 40))
				{
					return true;
				}
				else
				{
					return false;
				}
			}
		}

		return false;
	}

	public boolean isTiltDownward()
	{
		if (mGravity != null && mGeomagnetic != null)
		{
			float R[] = new float[9];
			float I[] = new float[9];

			boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);

			if (success)
			{
				float orientation[] = new float[3];
				SensorManager.getOrientation(R, orientation); 

				pitch = orientation[1];
				roll = orientation[2]; 

				inclineGravity = mGravity.clone();

				double norm_Of_g = Math.sqrt(inclineGravity[0] * inclineGravity[0] + inclineGravity[1] * inclineGravity[1] + inclineGravity[2] * inclineGravity[2]);

				// Normalize the accelerometer vector
				inclineGravity[0] = (float) (inclineGravity[0] / norm_Of_g);
				inclineGravity[1] = (float) (inclineGravity[1] / norm_Of_g);
				inclineGravity[2] = (float) (inclineGravity[2] / norm_Of_g);

				//Checks if device is flat on groud or not
				int inclination = (int) Math.round(Math.toDegrees(Math.acos(inclineGravity[2]))); 

				Float objPitch = new Float(pitch);
				Float objZero = new Float(0.0);
				Float objZeroPointTwo = new Float(0.2);
				Float objZeroPointTwoNegative = new Float(-0.2);

				int objPitchZeroResult = objPitch.compareTo(objZero);
				int objPitchZeroPointTwoResult = objZeroPointTwo.compareTo(objPitch);
				int objPitchZeroPointTwoNegativeResult = objPitch.compareTo(objZeroPointTwoNegative);

				if (roll < 0 && ((objPitchZeroResult > 0 && objPitchZeroPointTwoResult > 0) || (objPitchZeroResult < 0 && objPitchZeroPointTwoNegativeResult > 0)) && (inclination > 140 && inclination < 170))
				{
					return true;
				}
				else
				{
					return false;
				}
			}
		}

		return false;
	}
}

We implement the SensorEventListener and override it’s two methods onAccuracyChanged and onSensorChanged. The method onSensorChanged is called every time the phone moves, but because it’s extremely sensible it is even called when the phone is laying flat on the ground.

In order to save battery life and make sure the sensors don’t run when the app is paused or stopped we must unregister them OnPause, OnDestroy and OnBackPressed and resume them accordingly.

You can play around with the values inclination, objZeroPointTwo, objZeroPointTwoNegative to fine tune the tilt angle.

Sit back, take a sip from your hot brew and run your project.

Don’t forget to join or newsletter and get free android tutorials to enjoy with your hot brew.

  • Deepanshu khurana

    Can you provide with the activity_main.xml?

  • Gurinder

    Hi Deepanshu, you can download the complete project example when you click on the blue button “Download Code”, after entering your email address.

  • Deepanshu khurana

    i have downloaded full code but the activity_main.xml is blank

  • Gurinder

    Ah got you now. There is no view layout. This tutorials explains how to check whether the phone was tilt upwards or downwards. So you could use it this way:

    If (isTiltUpward())
    {
    //Phone was tilt upwards, do some action (update view)
    }
    else if (isTiltDownward())
    {
    //Phone was tilt downwards, do some other action (update view)
    }

  • Deepanshu khurana

    i am having an error “sensor or listener is null”

    the code i tried to run

    @Override

    public void onSensorChanged(SensorEvent event) {

    //If type is accelerometer only assign values to global property mGravity

    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
    {
    mGravity = event.values;
    }
    else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
    {
    mGeomagnetic = event.values;
    if (isTiltDownward())
    {
    setContentView(R.layout.green);
    }
    else if (isTiltUpward())
    {
    setContentView(R.layout.red);
    }
    }
    }

    and if i am trying to run the if else statement in TYPE_ACCELEROMETER the output is always the statement in else.

  • Deepanshu khurana

    I am having an error “sensor or listener is null”

  • Pushpa

    its not coming any message in if else condition..means i am not getting any orientaion

  • Deepanshu khurana

    can you tell me how to count the method of how much time pass and correct is called???

  • Jemimah Dejucos Peñaredonda

    How about when in portrait mode?——-

  • joseph

    hi
    i put the code . i am getting only “upwards”. i tilt the phone in all directions , i don’t get “downwards”
    .
    why is this ? help…

    • zahid

      flip your phone for example : put your phone like screen back
      side and back is upside