Get the Android device direction

Source: Internet
Author: User

Android devices with G-sensor can obtain the device's Motion Acceleration Through APIs. The application can use some assumptions and operations to calculate the device direction from the accelerometer.

The basic code for obtaining the Motion Acceleration of a device is:

        SensorManager sm = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);        sm.registerListener(new SensorEventListener() {            public void onSensorChanged(SensorEvent event) {                if (Sensor.TYPE_ACCELEROMETER != event.sensor.getType()) {                    return;                }                float[] values = event.values;                float ax = values[0];                float ay = values[1];                float az = values[2];                // TODO Have fun with the acceleration components...                            }            public void onAccuracyChanged(Sensor sensor, int accuracy) {            }        }, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
Copy code

Sendoreventlistener uses the sendorevent callback parameter to obtain the acceleration components of the current device in the X, Y, and Z axes of the coordinate system. The sensorevent API Doc defines the coordinate system used here:

I call it the "device coordinate system" for the time being. The device coordinate system is fixed on the device and has nothing to do with the direction of the device (orientation in the world coordinate system ).

Precisely, the acceleration value provided by the sensor event is the value after the device uses the earth as the reference object's acceleration minus the superposition of the gravity acceleration. I understand this as follows: when the gravity acceleration g moves freely to the ground, the mobile phone is in a weightless state, and g-sensor uses this state as the acceleration 0; when the mobile phone is in a static state (relative to the ground), in order to resist the trend of free falling body movement, it has a reverse (upward) g acceleration. Therefore, a conclusion is drawn:When the device is in a static or uniform motion state, it has a vertical ground up g acceleration, this g projection to the device coordinate system x, y, z axis, is the value of the three components provided by sensorevent.. Under the assumption that the device is in a static or uniform motion, you can calculate the direction of the device relative to the ground based on the three acceleration components provided by sensorevent.

The "device direction" mentioned above is a vague statement. Here we precisely describe the direction of the device: the direction perpendicular to the ground is positive, the angle ax, ay, and AZ between the X, Y, and Z axes of the device coordinate system and the positive axis are used to describe the direction of the device, as shown in. It can be seen that the device also has a degree of freedom, that is, it rotates around the positive axis, and ax, ay, and AZ remain unchanged. However, the constraints of ax, ay, and Az are sufficient to describe the relative position of the device relative to the positive axis. If you need to completely constrain the position of the device relative to the ground, in addition to the positive axis, you also need to introduce another reference axis, such as the ground axis connecting the South and North poles of the Earth (if the device has a Geomagnetic sensor, this constraint can be met)

The range of ax, ay, and AZ is [0, 2 * PI ). For example, when ay = 0, the Y axis of the mobile phone is vertical up; When ay = Pi, the Y axis of the mobile phone is downward; When ay = PI/2, the mobile phone is horizontal and the screen is upward; ay = 3 * PI/2, mobile phone horizontal, screen down

According to the Law of 3D vector algebra, we can see that:

  • GX = g * Cos (ax)
  • Gy = g * Cos (AY)
  • Gz = g * Cos (AZ)
  • G ^ 2 = GZ ^ 2 + Gy ^ 2 + Gz ^ 2

Therefore, according to GX, Gy, GZ, you can calculate ax, ay, az

2d simplification on x-y plane

When ax and ay are determined, AZ has two possible values. The difference between them is pi, which determines whether the orientation of the device screen is upward or downward. In most cases, we only care about ax and Ay (because the program UI is located in the x-y plane ?), While ignoring AZ, for example, Android's automatic screen rotation function, whether the user is looking at the screen with a low head (screen up) or lying in bed (screen down ), the UI is always the closest to the center of the bottom.

Then we set the vector of GX and Gy to G' (that is, the projection of G on the x-y plane) to simplify the calculation to the x-y 2D plane. The angle of Y axis relative to G' is a, and a is used to describe the direction of the device. The value is in the clockwise direction. The range of A is [0, 2 * PI)

Include:

  • G' ^ 2 = GX ^ 2 + Gy ^ 2
  • Gy = G' * Cos ()
  • GX = G' * sin ()

Then:

  • G' = SQRT (Gx ^ 2 + Gy ^ 2)
  • A = arccos (Gy/G ')

Because the arccos function value range is [0, Pi], and when a> Pi, GX = G' * sin (a) <0, calculate the value of a Based on the GX symbol as follows:

  • When GX> = 0, A = arccos (Gy/G ')
  • When GX is <0, A = 2 * pi-arccos (Gy/G ')

Note: The cos function curve is symmetric to the X = N * PI line. Therefore, if the arccos function curve is completed within the range of [0, 2 * Pi] in the Y axis, the linear y = pi is symmetric, so there is an algorithm above when GX is less than 0.

Consider application screen Rotation

The preceding figure shows the Rotation Angle of the "physical screen" of the Android device relative to the ground, compared with the physical screen, the application UI has four possible rotation angles: 0, 90, 180, and 270 degrees. That is to say:

  • Rotation Angle of the UI relative to the ground = Rotation Angle of the physical screen relative to the ground-Rotation Angle of the UI relative to the physical screen

The Android app obtains the screen rotation angle using the following methods:

        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();        int degree= 90 * rotation;        float rad = (float)Math.PI / 2 * rotation;
Copy code demo

According to the above algorithm, I wrote a "tumbler" demo. When the device rotates, the tumbler is always standing. The implementation principle of many applications in the software market, such as "level", should be the same

Download demo source code

Activity implements sensoreventlistener and registers it to sensormanager. Set the screen direction to landscape at the same time:

    private GSensitiveView gsView;    private SensorManager sm;    @Override    public void onCreate(Bundle savedInstanceState) {        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);        super.onCreate(savedInstanceState);        gsView = new GSensitiveView(this);        setContentView(gsView);        sm = (SensorManager) getSystemService(SENSOR_SERVICE);        sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);    }    @Override    protected void onDestroy() {        sm.unregisterListener(this);        super.onDestroy();    }
Copy code

The callback when G-sensor data changes is as follows. Here, the angle of UI rotation is calculated based on the algorithm we deduced above, and the gsensitiveview. setrotation () method is called to notify view update.

    public void onSensorChanged(SensorEvent event) {        if (Sensor.TYPE_ACCELEROMETER != event.sensor.getType()) {            return;        }        float[] values = event.values;        float ax = values[0];        float ay = values[1];        double g = Math.sqrt(ax * ax + ay * ay);        double cos = ay / g;        if (cos > 1) {            cos = 1;        } else if (cos < -1) {            cos = -1;        }        double rad = Math.acos(cos);        if (ax < 0) {            rad = 2 * Math.PI - rad;        }        int uiRot = getWindowManager().getDefaultDisplay().getRotation();        double uiRad = Math.PI / 2 * uiRot;        rad -= uiRad;        gsView.setRotation(rad);    }
Copy code

Gsensitiveview is a custom class for extended imageview. It mainly draws images based on the rotation angle:

    private static class GSensitiveView extends ImageView {        private Bitmap image;        private double rotation;        private Paint paint;        public GSensitiveView(Context context) {            super(context);            BitmapDrawable drawble = (BitmapDrawable) context.getResources().getDrawable(R.drawable.budaow);            image = drawble.getBitmap();            paint = new Paint();        }        @Override        protected void onDraw(Canvas canvas) {            // super.onDraw(canvas);            double w = image.getWidth();            double h = image.getHeight();            Rect rect = new Rect();            getDrawingRect(rect);            int degrees = (int) (180 * rotation / Math.PI);            canvas.rotate(degrees, rect.width() / 2, rect.height() / 2);            canvas.drawBitmap(image, //                    (float) ((rect.width() - w) / 2),//                      (float) ((rect.height() - h) / 2),//                      paint);        }        public void setRotation(double rad) {            rotation = rad;            invalidate();        }    }

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.