如何确保 RotationVector 的 Android API 级别之间的兼容性? [英] How can I ensure compatibility between Android API levels for RotationVector?

查看:31
本文介绍了如何确保 RotationVector 的 Android API 级别之间的兼容性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用旋转矢量传感器的 Android 应用.阅读了此处的评论后,我看到了更新的 API 级别,SensorEvent 包含 4-5 个值,而不是 3.我的代码使用数组复制数据.

I have an Android app that's using the Rotation Vector sensor. Having read the comment here, I see that with newer API levels, the SensorEvent contains 4-5 values, instead of 3. My code uses an arraycopy for the data.

lastRotVal 是一个类成员,并被初始化为一个大小为 [3] 的数组.这是响应传感器事件的代码的相关部分.

lastRotVal is a class member and is initialized as an array of size [3]. Here's the relevant parts of the code responding to the sensor events.

public void onSensorChanged(SensorEvent event) {
   System.arraycopy(event.values, 0, lastRotVal, 0, 3); //Hardcoded size
   lastRotValSet = true;
   updateDisplay(event);
}

private void updateDisplay(SensorEvent event){

   if (lastRotValSet){  
       float[] rotation = new float[9];
       float[] orientation = new float[3];

       SensorManager.getRotationMatrixFromVector(rotation, lastRotVal);
       SensorManager.getOrientation(rotation, orientation);
       double pitch = orientation[1];
       double roll = orientation[2];

       //Do stuff with roll and pitch
   }
}

我只在 arraycopy 中使用了 3 个值进行了硬编码.它似乎适用于旧的和新的 API 级别.这是保持版本之间兼容性的最佳方法,还是我可以做得更好?

I've hardcoded in only using 3 values in the arraycopy. It seems to be working on both older and the new API levels. Is this the best way to maintain that compatibility between versions, or could I be doing something better?

如已接受的答案所述,提示此问题的 IllegalArgumentException 显然是由于三星设备上的 API 中的错误而不是通用 API 版本引起的.所以我要补充一个事实,我的初始错误是在三星 Galaxy SIII 上遇到的.

As stated by the accepted answer, the IllegalArgumentException that prompted this question apparently arises as a consequence of a bug in the API on Samsung devices, not the general API version. So I'll add the fact that my initial error was encountered on a Samsung Galaxy SIII.

推荐答案

您引用的帖子实际上是指一些三星设备(Galaxy S4、Galaxy Note 3)中的错误 - 请参阅此 Android 开发人员列表帖子.您实际上不应该在 SDK 级别之间进行任何特殊处理,以便此代码在普通设备上工作.但是,唉,碎片化...

The post that you reference actually refers to a bug in a few Samsung devices (Galaxy S4, Galaxy Note 3) - see this Android Developer list post. You actually shouldn't have to do any special handling between SDK levels for this code to work on normal devices. But, alas, fragmentation...

Chromium 通过在数组大小大于 4 时截断数组来处理此问题:

if (values.length > 4) {
    // On some Samsung devices SensorManager.getRotationMatrixFromVector
    // appears to throw an exception if rotation vector has length > 4.
    // For the purposes of this class the first 4 values of the
    // rotation vector are sufficient (see crbug.com/335298 for details).
    if (mTruncatedRotationVector == null) {
        mTruncatedRotationVector = new float[4];
    }
    System.arraycopy(values, 0, mTruncatedRotationVector, 0, 4);
        getOrientationFromRotationVector(mTruncatedRotationVector);
} else {
    getOrientationFromRotationVector(values);
}

但是,我在我的应用 GPSTest 中发现该解决方案似乎不适用于Galaxy S3(请参阅 Github 问题此处).

However, I found in my app GPSTest that this solution didn't seem to work on the Galaxy S3 (see Github issue here).

因此,我最终只截断了抛出 IllegalArgumentException 的设备上的数组.这也避免了额外的 System.arraycopy() 除非绝对必要.

So, I ended up only truncating the array on devices that throw the IllegalArgumentException. This also avoids the extra System.arraycopy() unless its absolutely necessary.

这是代码片段(它还支持 API 级别低于 Gingerbread 的设备上的方向传感器(即,在引入 ROTATION_VECTOR 传感器之前),并处理重新映射坐标系以更改方向),它使用类成员mTruncateVector 被初始化为 false:

Here's the code snippet (that also supports orientation sensors on devices with API levels less than Gingerbread (i.e., prior to when the ROTATION_VECTOR sensor was introduced), and handles remapping the coordinate system for orientation changes), which uses a class member mTruncateVector that is initialized to false:

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
@Override
public void onSensorChanged(SensorEvent event) {

    double orientation = Double.NaN;
    double tilt = Double.NaN;

    switch (event.sensor.getType()) {
        case Sensor.TYPE_ROTATION_VECTOR:
            // Modern rotation vector sensors
            if (!mTruncateVector) {
                try {
                    SensorManager.getRotationMatrixFromVector(mRotationMatrix, event.values);
                } catch (IllegalArgumentException e) {
                    // On some Samsung devices, an exception is thrown if this vector > 4 (see #39)
                    // Truncate the array, since we can deal with only the first four values
                    Log.e(TAG, "Samsung device error? Will truncate vectors - " + e);
                    mTruncateVector = true;
                    // Do the truncation here the first time the exception occurs
                    getRotationMatrixFromTruncatedVector(event.values);
                }
            } else {
                // Truncate the array to avoid the exception on some devices (see #39)
                getRotationMatrixFromTruncatedVector(event.values);
            }

            int rot = getWindowManager().getDefaultDisplay().getRotation();
            switch (rot) {
                case Surface.ROTATION_0:
                    // No orientation change, use default coordinate system
                    SensorManager.getOrientation(mRotationMatrix, mValues);
                    // Log.d(TAG, "Rotation-0");
                    break;
                case Surface.ROTATION_90:
                    // Log.d(TAG, "Rotation-90");
                    SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_Y,
                            SensorManager.AXIS_MINUS_X, mRemappedMatrix);
                    SensorManager.getOrientation(mRemappedMatrix, mValues);
                    break;
                case Surface.ROTATION_180:
                    // Log.d(TAG, "Rotation-180");
                    SensorManager
                            .remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_MINUS_X,
                                    SensorManager.AXIS_MINUS_Y, mRemappedMatrix);
                    SensorManager.getOrientation(mRemappedMatrix, mValues);
                    break;
                case Surface.ROTATION_270:
                    // Log.d(TAG, "Rotation-270");
                    SensorManager
                            .remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_MINUS_Y,
                                    SensorManager.AXIS_X, mRemappedMatrix);
                    SensorManager.getOrientation(mRemappedMatrix, mValues);
                    break;
                default:
                    // This shouldn't happen - assume default orientation
                    SensorManager.getOrientation(mRotationMatrix, mValues);
                    // Log.d(TAG, "Rotation-Unknown");
                    break;
            }
            orientation = Math.toDegrees(mValues[0]);  // azimuth
            tilt = Math.toDegrees(mValues[1]);
            break;
        case Sensor.TYPE_ORIENTATION:
            // Legacy orientation sensors
            orientation = event.values[0];
            break;
        default:
            // A sensor we're not using, so return
            return;
    }
}

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
private void getRotationMatrixFromTruncatedVector(float[] vector) {
    System.arraycopy(vector, 0, mTruncatedRotationVector, 0, 4);
    SensorManager.getRotationMatrixFromVector(mRotationMatrix, mTruncatedRotationVector);
}

并在onResume()中注册传感器:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
        // Use the modern rotation vector sensors
        Sensor vectorSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
        mSensorManager.registerListener(this, vectorSensor, 16000); // ~60hz
    } else {
        // Use the legacy orientation sensors
        Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
        if (sensor != null) {
            mSensorManager.registerListener(this, sensor,
                    SensorManager.SENSOR_DELAY_GAME);
        }
    }

完整的实现是在 Github 上.

这篇关于如何确保 RotationVector 的 Android API 级别之间的兼容性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆