diff options
| author | JosJuice <josjuice@gmail.com> | 2022-09-17 12:12:39 +0200 |
|---|---|---|
| committer | JosJuice <josjuice@gmail.com> | 2023-03-03 22:28:23 +0100 |
| commit | 065481d9899e6debc94bdbbb812512757f8eac62 (patch) | |
| tree | 641ffa48d25f06764162361271e7dcdfd702257e /Source/Core/InputCommon/ControllerInterface/Android | |
| parent | 36acb17700554f0789d8650b7fba77ac8a7796b6 (diff) | |
ControllerInterface/Android: Automatically suspend sensors
This is a battery-saving measure. Whether a sensor should be suspended
is determined in the same way as whether key events and motion events
should be handled by the OS rather than consumed by Dolphin.
Diffstat (limited to 'Source/Core/InputCommon/ControllerInterface/Android')
| -rw-r--r-- | Source/Core/InputCommon/ControllerInterface/Android/Android.cpp | 122 |
1 files changed, 82 insertions, 40 deletions
diff --git a/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp b/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp index cf7e602a77..058a9e3171 100644 --- a/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Android/Android.cpp @@ -67,8 +67,7 @@ jclass s_sensor_event_listener_class; jmethodID s_sensor_event_listener_constructor; jmethodID s_sensor_event_listener_constructor_input_device; jmethodID s_sensor_event_listener_set_device_qualifier; -jmethodID s_sensor_event_listener_enable_sensor_events; -jmethodID s_sensor_event_listener_disable_sensor_events; +jmethodID s_sensor_event_listener_request_unsuspend_sensor; jmethodID s_sensor_event_listener_get_axis_names; jmethodID s_sensor_event_listener_get_negative_axes; @@ -494,9 +493,45 @@ private: class AndroidSensorAxis final : public AndroidAxis { public: - AndroidSensorAxis(std::string name, bool negative) : AndroidAxis(std::move(name), negative) {} + // This class does not create its own global reference to the passed-in sensor_event_listener. + // That is, it's up to the device that contains this axis to keep sensor_event_listener valid. + // It does however create its own global reference to the passed-in name. + AndroidSensorAxis(JNIEnv* env, jobject sensor_event_listener, jstring j_name, bool negative) + : AndroidAxis(GetJString(env, j_name), negative), + m_sensor_event_listener(sensor_event_listener), + m_j_name(reinterpret_cast<jstring>(env->NewGlobalRef(j_name))) + { + } + + ~AndroidSensorAxis() { IDCache::GetEnvForThread()->DeleteGlobalRef(m_j_name); } bool IsDetectable() const override { return false; } + + ControlState GetState() const override + { + if (m_is_suspended.load(std::memory_order_relaxed)) + { + IDCache::GetEnvForThread()->CallVoidMethod( + m_sensor_event_listener, s_sensor_event_listener_request_unsuspend_sensor, m_j_name); + + // m_is_suspended is intentionally not updated here. To prevent the C++ suspended status from + // ending up desynced with the Java suspended status, we only update m_is_suspended when Java + // calls notifySensorSuspendedState (which calls NotifyIsSuspended). This way, Java is the + // authoritative source for the suspended status, and C++ mirrors it (possibly with a delay). + } + + return AndroidAxis::GetState(); + } + + void NotifyIsSuspended(bool is_suspended) + { + m_is_suspended.store(is_suspended, std::memory_order_relaxed); + } + +private: + const jobject m_sensor_event_listener; + const jstring m_j_name; + std::atomic<bool> m_is_suspended = true; }; class AndroidDevice final : public Core::Device @@ -611,40 +646,45 @@ private: jobject AddSensors(JNIEnv* env, jobject input_device) { - jobject sensor_event_listener; + jobject local_sensor_event_listener; if (input_device) { - sensor_event_listener = + local_sensor_event_listener = env->NewObject(s_sensor_event_listener_class, s_sensor_event_listener_constructor_input_device, input_device); } else { - sensor_event_listener = + local_sensor_event_listener = env->NewObject(s_sensor_event_listener_class, s_sensor_event_listener_constructor); } + jobject sensor_event_listener = env->NewGlobalRef(local_sensor_event_listener); + + env->DeleteLocalRef(local_sensor_event_listener); + jobjectArray j_axis_names = reinterpret_cast<jobjectArray>( env->CallObjectMethod(sensor_event_listener, s_sensor_event_listener_get_axis_names)); - std::vector<std::string> axis_names = JStringArrayToVector(env, j_axis_names); - env->DeleteLocalRef(j_axis_names); jbooleanArray j_negative_axes = reinterpret_cast<jbooleanArray>( env->CallObjectMethod(sensor_event_listener, s_sensor_event_listener_get_negative_axes)); jboolean* negative_axes = env->GetBooleanArrayElements(j_negative_axes, nullptr); - ASSERT(axis_names.size() == env->GetArrayLength(j_negative_axes)); - for (size_t i = 0; i < axis_names.size(); ++i) - AddInput(new AndroidSensorAxis(axis_names[i], negative_axes[i])); + const jsize axis_count = env->GetArrayLength(j_axis_names); + ASSERT(axis_count == env->GetArrayLength(j_negative_axes)); + for (jsize i = 0; i < axis_count; ++i) + { + const jstring axis_name = + reinterpret_cast<jstring>(env->GetObjectArrayElement(j_axis_names, i)); + AddInput(new AndroidSensorAxis(env, sensor_event_listener, axis_name, negative_axes[i])); + env->DeleteLocalRef(axis_name); + } + env->DeleteLocalRef(j_axis_names); env->ReleaseBooleanArrayElements(j_negative_axes, negative_axes, 0); env->DeleteLocalRef(j_negative_axes); - jobject global_sensor_event_listener = env->NewGlobalRef(sensor_event_listener); - - env->DeleteLocalRef(sensor_event_listener); - - return global_sensor_event_listener; + return sensor_event_listener; } const jobject m_sensor_event_listener; @@ -735,11 +775,8 @@ void Init() env->GetMethodID(s_sensor_event_listener_class, "<init>", "(Landroid/view/InputDevice;)V"); s_sensor_event_listener_set_device_qualifier = env->GetMethodID( s_sensor_event_listener_class, "setDeviceQualifier", "(Ljava/lang/String;)V"); - s_sensor_event_listener_enable_sensor_events = - env->GetMethodID(s_sensor_event_listener_class, "enableSensorEvents", - "(Lorg/dolphinemu/dolphinemu/features/input/model/SensorEventRequester;)V"); - s_sensor_event_listener_disable_sensor_events = - env->GetMethodID(s_sensor_event_listener_class, "disableSensorEvents", "()V"); + s_sensor_event_listener_request_unsuspend_sensor = env->GetMethodID( + s_sensor_event_listener_class, "requestUnsuspendSensor", "(Ljava/lang/String;)V"); s_sensor_event_listener_get_axis_names = env->GetMethodID(s_sensor_event_listener_class, "getAxisNames", "()[Ljava/lang/String;"); s_sensor_event_listener_get_negative_axes = @@ -934,7 +971,7 @@ Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_dispatch return last_polled >= Clock::now() - ACTIVE_INPUT_TIMEOUT; } -JNIEXPORT void JNICALL +JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_dispatchSensorEvent( JNIEnv* env, jclass, jstring j_device_qualifier, jstring j_axis_name, jfloat value) { @@ -943,10 +980,12 @@ Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_dispatch const std::shared_ptr<ciface::Core::Device> device = g_controller_interface.FindDevice(device_qualifier); if (!device) - return; + return JNI_FALSE; const std::string axis_name = GetJString(env, j_axis_name); + Clock::time_point last_polled{}; + for (ciface::Core::Device::Input* input : device->Inputs()) { const std::string input_name = input->GetName(); @@ -954,31 +993,34 @@ Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_dispatch { auto casted_input = static_cast<ciface::Android::AndroidInput*>(input); casted_input->SetState(value); + last_polled = std::max(last_polled, casted_input->GetLastPolled()); } } -} -JNIEXPORT void JNICALL -Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_enableSensorEvents( - JNIEnv* env, jclass, jobject j_sensor_event_requester) -{ - for (std::shared_ptr<ciface::Core::Device>& device : g_controller_interface.GetAllDevices()) - { - env->CallVoidMethod( - static_cast<ciface::Android::AndroidDevice*>(device.get())->GetSensorEventListener(), - s_sensor_event_listener_enable_sensor_events, j_sensor_event_requester); - } + return last_polled >= Clock::now() - ACTIVE_INPUT_TIMEOUT; } JNIEXPORT void JNICALL -Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_disableSensorEvents( - JNIEnv* env, jclass) +Java_org_dolphinemu_dolphinemu_features_input_model_ControllerInterface_notifySensorSuspendedState( + JNIEnv* env, jclass, jstring j_device_qualifier, jobjectArray j_axis_names, jboolean suspended) { - for (std::shared_ptr<ciface::Core::Device>& device : g_controller_interface.GetAllDevices()) + ciface::Core::DeviceQualifier device_qualifier; + device_qualifier.FromString(GetJString(env, j_device_qualifier)); + const std::shared_ptr<ciface::Core::Device> device = + g_controller_interface.FindDevice(device_qualifier); + if (!device) + return; + + const std::vector<std::string> axis_names = JStringArrayToVector(env, j_axis_names); + + for (ciface::Core::Device::Input* input : device->Inputs()) { - env->CallVoidMethod( - static_cast<ciface::Android::AndroidDevice*>(device.get())->GetSensorEventListener(), - s_sensor_event_listener_disable_sensor_events); + const std::string input_name = input->GetName(); + if (std::find(axis_names.begin(), axis_names.end(), input_name) != axis_names.end()) + { + auto casted_input = static_cast<ciface::Android::AndroidSensorAxis*>(input); + casted_input->NotifyIsSuspended(static_cast<bool>(suspended)); + } } } |
