blob: 44500357a44195d5a1271eb1b1155017c2689d07 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/device/generic_sensor/platform_sensor_provider_android.h"
#include <utility>
#include <vector>
#include "base/android/scoped_java_ref.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "jni/PlatformSensorProvider_jni.h"
#include "services/device/generic_sensor/absolute_orientation_euler_angles_fusion_algorithm_using_accelerometer_and_magnetometer.h"
#include "services/device/generic_sensor/orientation_euler_angles_fusion_algorithm_using_quaternion.h"
#include "services/device/generic_sensor/orientation_quaternion_fusion_algorithm_using_euler_angles.h"
#include "services/device/generic_sensor/platform_sensor_android.h"
#include "services/device/generic_sensor/platform_sensor_fusion.h"
#include "services/device/generic_sensor/relative_orientation_euler_angles_fusion_algorithm_using_accelerometer.h"
using base::android::AttachCurrentThread;
using base::android::ScopedJavaLocalRef;
namespace device {
// static
PlatformSensorProviderAndroid* PlatformSensorProviderAndroid::GetInstance() {
return base::Singleton<
PlatformSensorProviderAndroid,
base::LeakySingletonTraits<PlatformSensorProviderAndroid>>::get();
}
PlatformSensorProviderAndroid::PlatformSensorProviderAndroid() {
JNIEnv* env = AttachCurrentThread();
j_object_.Reset(Java_PlatformSensorProvider_create(env));
}
PlatformSensorProviderAndroid::~PlatformSensorProviderAndroid() = default;
void PlatformSensorProviderAndroid::SetSensorManagerToNullForTesting() {
JNIEnv* env = AttachCurrentThread();
Java_PlatformSensorProvider_setSensorManagerToNullForTesting(env, j_object_);
}
void PlatformSensorProviderAndroid::CreateSensorInternal(
mojom::SensorType type,
SensorReadingSharedBuffer* reading_buffer,
const CreateSensorCallback& callback) {
JNIEnv* env = AttachCurrentThread();
// Some of the sensors may not be available depending on the device and
// Android version, so the fallback ensures selection of the best possible
// option.
switch (type) {
case mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES:
CreateAbsoluteOrientationEulerAnglesSensor(env, reading_buffer, callback);
break;
case mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION:
CreateAbsoluteOrientationQuaternionSensor(env, reading_buffer, callback);
break;
case mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES:
CreateRelativeOrientationEulerAnglesSensor(env, reading_buffer, callback);
break;
default: {
ScopedJavaLocalRef<jobject> sensor =
Java_PlatformSensorProvider_createSensor(env, j_object_,
static_cast<jint>(type));
if (!sensor.obj()) {
callback.Run(nullptr);
return;
}
auto concrete_sensor = base::MakeRefCounted<PlatformSensorAndroid>(
type, reading_buffer, this, sensor);
callback.Run(concrete_sensor);
break;
}
}
}
// For ABSOLUTE_ORIENTATION_EULER_ANGLES we use a 3-way fallback approach
// where up to 3 different sets of sensors are attempted if necessary. The
// sensors to be used are determined in the following order:
// A: ABSOLUTE_ORIENTATION_QUATERNION (if it uses TYPE_ROTATION_VECTOR
// directly)
// B: TODO(juncai): Combination of ACCELEROMETER, MAGNETOMETER and
// GYROSCOPE
// C: Combination of ACCELEROMETER and MAGNETOMETER
void PlatformSensorProviderAndroid::CreateAbsoluteOrientationEulerAnglesSensor(
JNIEnv* env,
SensorReadingSharedBuffer* reading_buffer,
const CreateSensorCallback& callback) {
if (static_cast<bool>(Java_PlatformSensorProvider_hasSensorType(
env, j_object_,
static_cast<jint>(
mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION)))) {
auto sensor_fusion_algorithm =
std::make_unique<OrientationEulerAnglesFusionAlgorithmUsingQuaternion>(
true /* absolute */);
// If this PlatformSensorFusion object is successfully initialized,
// |callback| will be run with a reference to this object.
PlatformSensorFusion::Create(reading_buffer, this,
std::move(sensor_fusion_algorithm), callback);
} else {
auto sensor_fusion_algorithm = std::make_unique<
AbsoluteOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndMagnetometer>();
// If this PlatformSensorFusion object is successfully initialized,
// |callback| will be run with a reference to this object.
PlatformSensorFusion::Create(reading_buffer, this,
std::move(sensor_fusion_algorithm), callback);
}
}
// For ABSOLUTE_ORIENTATION_QUATERNION we use a 2-way fallback approach
// where up to 2 different sets of sensors are attempted if necessary. The
// sensors to be used are determined in the following order:
// A: Use TYPE_ROTATION_VECTOR directly
// B: ABSOLUTE_ORIENTATION_EULER_ANGLES
void PlatformSensorProviderAndroid::CreateAbsoluteOrientationQuaternionSensor(
JNIEnv* env,
SensorReadingSharedBuffer* reading_buffer,
const CreateSensorCallback& callback) {
ScopedJavaLocalRef<jobject> sensor = Java_PlatformSensorProvider_createSensor(
env, j_object_,
static_cast<jint>(mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION));
if (sensor.obj()) {
auto concrete_sensor = base::MakeRefCounted<PlatformSensorAndroid>(
mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION, reading_buffer,
this, sensor);
callback.Run(concrete_sensor);
} else {
auto sensor_fusion_algorithm =
std::make_unique<OrientationQuaternionFusionAlgorithmUsingEulerAngles>(
true /* absolute */);
// If this PlatformSensorFusion object is successfully initialized,
// |callback| will be run with a reference to this object.
PlatformSensorFusion::Create(reading_buffer, this,
std::move(sensor_fusion_algorithm), callback);
}
}
// For RELATIVE_ORIENTATION_EULER_ANGLES we use RELATIVE_ORIENTATION_QUATERNION
// (if it uses TYPE_GAME_ROTATION_VECTOR directly).
void PlatformSensorProviderAndroid::CreateRelativeOrientationEulerAnglesSensor(
JNIEnv* env,
SensorReadingSharedBuffer* reading_buffer,
const CreateSensorCallback& callback) {
if (static_cast<bool>(Java_PlatformSensorProvider_hasSensorType(
env, j_object_,
static_cast<jint>(
mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION)))) {
auto sensor_fusion_algorithm =
std::make_unique<OrientationEulerAnglesFusionAlgorithmUsingQuaternion>(
false /* absolute */);
// If this PlatformSensorFusion object is successfully initialized,
// |callback| will be run with a reference to this object.
PlatformSensorFusion::Create(reading_buffer, this,
std::move(sensor_fusion_algorithm), callback);
} else {
callback.Run(nullptr);
}
}
} // namespace device