Android project development: Compass (implemented in two ways)

Keywords: Java Android Android Studio

In Android, you can use built-in sensors (direction sensor, acceleration sensor, geomagnetic sensor, etc.) to realize the compass function and write an app that can identify the location of the mobile phone. This paper will describe two methods to write compass app, one is to use direction sensor, the other is to combine acceleration sensor and geomagnetic sensor.

1. Based on direction sensor

Direction sensor is one of the basic sensors of Android. It determines three directions (X,Y,Z) through three-dimensional coordinates to further realize the compass function.
ps: Sensor.TYPE_ORIENTATION is no longer recommended in the current Android system, but it can still be used to obtain data.

activity_main.xml

Simply put, only one imageview is designed in the layout to place the picture of the compass, so as to realize the compass function by rotating the picture through animation.

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical" 
  android:gravity="center"> 
  <ImageView
    android:id="@+id/imageview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/compass" /> 
</LinearLayout>

MainActivity.java

The idea is relatively simple. Monitor the sensor events through the SensorEventListener, obtain the data collected by the Z-axis of the direction sensor, and rotate the compass picture.

import androidx.appcompat.app.AppCompatActivity;

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.util.Log;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity implements SensorEventListener {

    //Writing a compass using a direction sensor
    private ImageView imageView;
    private float currentDegree;
    private SensorManager sensorManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView=(ImageView) findViewById(R.id.imageview);
        currentDegree=0f;
        sensorManager=(SensorManager) getSystemService(SENSOR_SERVICE);  //Get sensor services
    }

    @Override
    protected void onResume() {
        //Register listener for direction sensor
        super.onResume();
        sensorManager.registerListener(this,sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),sensorManager.SENSOR_DELAY_GAME);
    }

    @Override
    protected void onPause() {
        //Cancel listener
        super.onPause();
        sensorManager.unregisterListener(this);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        //Keep the equipment level and use a level sensor
        if(event.sensor.getType()==Sensor.TYPE_ORIENTATION){
            //Take the angle of rotation around the Z axis
            float degree=event.values[0];
            RotateAnimation rotateAnimation=new RotateAnimation(currentDegree,-degree, Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);  //Animation rotation angle
            rotateAnimation.setDuration(200); //Set animation duration
            rotateAnimation.setFillAfter(true); //Sets the retention state after the animation ends
            imageView.setAnimation(rotateAnimation);
            currentDegree=-degree;
        }
    }

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

    }
}

2. Based on acceleration sensor and geomagnetic sensor

The layout is consistent with the above method, so the above activity can be copied directly_ Main.xml code, introduce the java code in detail.
In the onCreate method, the acceleration sensor and geomagnetic sensor instances are obtained respectively, and their listeners are registered. Then judge in the onSensorChanged() method. If it is an acceleration sensor, assign the values array to the accelerometerValues array. If it is a geomagnetic sensor, assign the values array to the magneticValues array. When assigning values, you must call the clone() method of values, otherwise accelerometerValues and magneticValues will point to the same block reference.
Next, create a R array of 9 length and a values array of 3 length, respectively, and assign the value to the R array by calling the getRotationMatrix() method. Then, getOrientation() is called to assign the value to the values array, which is the arc in the values array containing all the directions of the mobile phone. (radians can be converted to degrees)
Finally, in the callback method, the image can be rotated by using RotateAnimation and the currently rotated angle value [0].

import androidx.appcompat.app.AppCompatActivity;

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.util.Log;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity implements SensorEventListener {
	//The compass is compiled by acceleration sensor and geomagnetic sensor
    private SensorManager sensorManager;
    private ImageView imageView;
    private float lastRotateDegree;

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

        imageView = (ImageView) findViewById(R.id.imageview);
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        //Acceleration sensor
        Sensor magneticSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        //Geomagnetic sensor
        Sensor accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

        sensorManager.registerListener(this, magneticSensor, SensorManager.SENSOR_DELAY_GAME);

        sensorManager.registerListener(this, accelerometerSensor, SensorManager.SENSOR_DELAY_GAME);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (sensorManager != null) {
            sensorManager.unregisterListener(this);
        }
    }

    float[] accelerometerValues = new float[3];

    float[] magneticValues = new float[3];

    @Override
    public void onSensorChanged(SensorEvent event) {
        // Determine whether it is an acceleration sensor or a geomagnetic sensor
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            //Call clone method after assignment
            accelerometerValues = event.values.clone();
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            //Call clone method after assignment
            magneticValues = event.values.clone();
        }
        float[] R = new float[9];
        float[] values = new float[3];
        SensorManager.getRotationMatrix(R,null,accelerometerValues,magneticValues);
        sensorManager.getOrientation(R, values);
        Log.d("Main","values[0] :"+Math.toDegrees(values[0]));
        //The value range of values[0] is - 180 to 180 degrees.
        //+-180 indicates due south, 0 degrees indicates due north, - 90 indicates due west, and + 90 indicates due east

        //The calculated rotation angle is reversed and used to rotate the compass background image
        float rotateDegree = -(float) Math.toDegrees(values[0]);
        if (Math.abs(rotateDegree - lastRotateDegree) > 1) {
            RotateAnimation animation = new RotateAnimation(lastRotateDegree,rotateDegree, Animation.RELATIVE_TO_SELF,0.5f,
                    Animation.RELATIVE_TO_SELF,0.5f);
            animation.setFillAfter(true);
            imageView.startAnimation(animation); //Animation effect rotation sensor
            lastRotateDegree = rotateDegree;
        }
    }

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

    }
}

Finally, attached Project link

Posted by swizzer on Wed, 24 Nov 2021 18:36:37 -0800