In the former articles, "Detect rotation around X, Y & Z axis, using SensorManager and SensorEventListener" and "Implement a Simple Compass using SensorManager and SensorEventListener" have been describe. In this article, I will show how to implement a Horizontal Indicator.
A point float on the screen to indicate horizontal of the phone.

Create a custom view, HorizontalView.java, extends View. It display the drawing of our indicator.
Modify the layout file, main.xml, to add HorizontalView.
Modify the main code, AndroidHorizontal.java, to handle SensorManager and SensorEventListener.
Modify AndroidManifest.xml to disable the auto-rotate feature, otherwise it will point to wrong direction.
Download the files.
A point float on the screen to indicate horizontal of the phone.
Create a custom view, HorizontalView.java, extends View. It display the drawing of our indicator.
package com.exercise.AndroidHorizontal;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class HorizontalView extends View {
private float pitch = 0, roll = 0;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private boolean firstDraw;
final float radiusPt = (float)3;
public HorizontalView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}
public HorizontalView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}
public HorizontalView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}
private void init(){
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);
paint.setTextSize(20);
firstDraw = true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
int cxPlan = getMeasuredWidth()/2;
int cyPlan = getMeasuredHeight()/2;
float fullLength, halfLength, ptPerDegree;
if(cxPlan > cyPlan){
fullLength = (float)(getMeasuredHeight() * 0.9);
}
else{
fullLength = (float)(getMeasuredWidth() * 0.9);
}
halfLength = fullLength/2;
ptPerDegree = fullLength/360;
canvas.drawRect(cxPlan-halfLength, cyPlan-halfLength,
cxPlan+halfLength, cyPlan+halfLength, paint);
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint);
if(!firstDraw){
float yPt = cyPlan + (pitch * ptPerDegree);
float xPt = cxPlan + (roll * ptPerDegree);
canvas.drawCircle(xPt, yPt, radiusPt, paint);
}
}
public void updateHorizontal(float tPitch, float tRoll)
{
firstDraw = false;
pitch = tPitch;
roll = tRoll;
invalidate();
}
}
Modify the layout file, main.xml, to add HorizontalView.
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
android:id="@+id/textpitch"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
android:id="@+id/textroll"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
class="com.exercise.AndroidHorizontal.HorizontalView"
android:id="@+id/myhorizontalview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
Modify the main code, AndroidHorizontal.java, to handle SensorManager and SensorEventListener.
package com.exercise.AndroidHorizontal;
import java.util.List;
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;
import android.widget.Toast;
public class AndroidHorizontal extends Activity {
private static SensorManager mySensorManager;
private boolean sersorrunning;
private HorizontalView myHorizontalView;
private TextView textviewPitch, textviewRoll;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myHorizontalView = (HorizontalView)findViewById(R.id.myhorizontalview);
textviewPitch = (TextView)findViewById(R.id.textpitch);
textviewRoll = (TextView)findViewById(R.id.textroll);
mySensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
List mySensors = mySensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
if(mySensors.size() > 0){
mySensorManager.registerListener(mySensorEventListener, mySensors.get(0), SensorManager.SENSOR_DELAY_NORMAL);
sersorrunning = true;
Toast.makeText(this, "Start ORIENTATION Sensor", Toast.LENGTH_LONG).show();
}
else{
Toast.makeText(this, "No ORIENTATION Sensor", Toast.LENGTH_LONG).show();
sersorrunning = false;
finish();
}
}
private SensorEventListener mySensorEventListener = 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
textviewPitch.setText("Pitch: " + String.valueOf(event.values[1]));
textviewRoll.setText("Roll: " + String.valueOf(event.values[2]));
myHorizontalView.updateHorizontal(
(float)event.values[1], (float)event.values[2]);
}
};
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if(sersorrunning){
mySensorManager.unregisterListener(mySensorEventListener);
}
}
}
Modify AndroidManifest.xml to disable the auto-rotate feature, otherwise it will point to wrong direction.