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

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

问题描述

我有一个Android应用程序,是一个使用旋转矢量传感器。看了评论<一个href="http://stackoverflow.com/questions/21357100/android-rotation-vector-sensor-error?newreg=d6e19da4953c4261aea95505aef32ae6">here,我看到,新的API等级,SensorEvent包含4-5值,而不是3我的code使用的arraycopy的数据。

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]的数组。下面是的code响应传感器事件的相关部分。

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
   }
}

我已经很难codeD只使用在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.

推荐答案

<一个href="http://stackoverflow.com/questions/21357100/android-rotation-vector-sensor-error?newreg=d6e19da4953c4261aea95505aef32ae6">The帖子您引用实际上指的是在一些三星设备(银河S4,银河注3)错误 - 看的这个Android开发者名单张贴。实际上,你不应该做的SDK二者之间的特殊处理此code工作在正常的设备。但是,唉,碎片...

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...

<一个href="https://src.chromium.org/viewvc/chrome/trunk/src/content/public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java?pathrev=246398"相对=nofollow>铬处理这个问题通过截断阵列中,如果大小大于4:

Chromium handles this issue by truncating the array if the size is greater than 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 发现,这种解决方案似乎并没有工作,银河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.

下面是在code片段(也支持与API的水平低于姜饼(即,之前被引入所述ROTATION_VECTOR传感器时)的设备取向传感器,并处理重新映射的坐标系统的取向变化),它使用一类成员 mTruncateVector 被初始化为

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);
        }
    }

全面实施是<一个href="https://github.com/barbeau/gpstest/blob/master/GPSTest/src/main/java/com/android/gpstest/GpsTestActivity.java#L565"相对=nofollow>这里Github上。

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

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