gamepad_platform_data_fetcher_android.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "device/gamepad/gamepad_platform_data_fetcher_android.h"
  5. #include <stddef.h>
  6. #include "base/android/build_info.h"
  7. #include "base/android/jni_android.h"
  8. #include "base/android/jni_array.h"
  9. #include "base/android/jni_string.h"
  10. #include "base/containers/flat_map.h"
  11. #include "base/feature_list.h"
  12. #include "base/strings/string_number_conversions.h"
  13. #include "base/strings/string_util.h"
  14. #include "base/strings/utf_string_conversions.h"
  15. #include "base/trace_event/trace_event.h"
  16. #include "device/gamepad/gamepad_id_list.h"
  17. #include "device/gamepad/haptic_gamepad_android.h"
  18. #include "device/gamepad/jni_headers/GamepadList_jni.h"
  19. #include "device/gamepad/public/cpp/gamepad_features.h"
  20. using base::android::AttachCurrentThread;
  21. using base::android::CheckException;
  22. using base::android::ClearException;
  23. using base::android::ConvertJavaStringToUTF8;
  24. using base::android::JavaParamRef;
  25. using base::android::ScopedJavaLocalRef;
  26. namespace device {
  27. namespace {
  28. // Returns true if |gamepad_id| identifies a gamepad known to be mapped
  29. // correctly on this version of Android. |x_input_type| identifies the flavor of
  30. // XInput used by the gamepad, or kXInputTypeNone if the gamepad is not XInput.
  31. bool HasStandardMappingOnAndroid(GamepadId gamepad_id,
  32. XInputType x_input_type) {
  33. // Gamepads that are mapped correctly on Android do not require a mapping
  34. // function to comply with the Standard Gamepad. Entries in this map
  35. // represent gamepads that have been manually tested and are known to
  36. // work correctly on recent versions of Android. The key is a GamepadId to
  37. // identify the gamepad and the value is the earliest
  38. // base::android::SdkVersion where the gamepad is known to be mapped
  39. // correctly.
  40. const base::flat_map<GamepadId, base::android::SdkVersion>
  41. kManualAssessmentResult = {
  42. // Stadia Controller USB
  43. {GamepadId::kGoogleProduct9400,
  44. base::android::SdkVersion::SDK_VERSION_OREO},
  45. // Xbox 360 wireless
  46. {GamepadId::kMicrosoftProduct02a1,
  47. base::android::SdkVersion::SDK_VERSION_R},
  48. // Xbox One USB (2015 firmware)
  49. {GamepadId::kMicrosoftProduct02dd,
  50. base::android::SdkVersion::SDK_VERSION_R},
  51. // Xbox One S USB
  52. {GamepadId::kMicrosoftProduct02ea,
  53. base::android::SdkVersion::SDK_VERSION_Q},
  54. // Xbox One S Bluetooth
  55. {GamepadId::kMicrosoftProduct02fd,
  56. base::android::SdkVersion::SDK_VERSION_R},
  57. // Xbox Series X USB
  58. {GamepadId::kMicrosoftProduct0b12,
  59. base::android::SdkVersion::SDK_VERSION_R},
  60. // Xbox Series X Bluetooth
  61. {GamepadId::kMicrosoftProduct0b13,
  62. base::android::SdkVersion::SDK_VERSION_Q},
  63. // Xbox One S Bluetooth (2021 firmware)
  64. {GamepadId::kMicrosoftProduct0b20,
  65. base::android::SdkVersion::SDK_VERSION_Q},
  66. // Xbox Adaptive (2021 firmware)
  67. {GamepadId::kMicrosoftProduct0b21,
  68. base::android::SdkVersion::SDK_VERSION_Q},
  69. // Xbox Elite Series 2 (2021 firmware)
  70. {GamepadId::kMicrosoftProduct0b22,
  71. base::android::SdkVersion::SDK_VERSION_Q},
  72. // Switch Pro Controller
  73. {GamepadId::kNintendoProduct2009,
  74. base::android::SdkVersion::SDK_VERSION_R},
  75. };
  76. auto find_it = kManualAssessmentResult.find(gamepad_id);
  77. if (find_it != kManualAssessmentResult.end()) {
  78. return find_it->second <=
  79. base::android::BuildInfo::GetInstance()->sdk_int();
  80. }
  81. // Assume XInput gamepads are always correctly mapped.
  82. return x_input_type == kXInputTypeXbox360 ||
  83. x_input_type == kXInputTypeXboxOne;
  84. }
  85. } // namespace
  86. GamepadPlatformDataFetcherAndroid::GamepadPlatformDataFetcherAndroid() =
  87. default;
  88. GamepadPlatformDataFetcherAndroid::~GamepadPlatformDataFetcherAndroid() {
  89. PauseHint(true);
  90. for (const auto& pair : vibration_actuators_) {
  91. pair.second->Shutdown();
  92. }
  93. }
  94. GamepadSource GamepadPlatformDataFetcherAndroid::source() {
  95. return Factory::static_source();
  96. }
  97. void GamepadPlatformDataFetcherAndroid::OnAddedToProvider() {
  98. PauseHint(false);
  99. }
  100. void GamepadPlatformDataFetcherAndroid::SetDualRumbleVibrationActuator(
  101. int source_id) {
  102. DCHECK(!base::Contains(vibration_actuators_, source_id));
  103. vibration_actuators_.emplace(
  104. source_id, std::make_unique<HapticGamepadAndroid>(source_id));
  105. }
  106. void GamepadPlatformDataFetcherAndroid::TryShutdownDualRumbleVibrationActuator(
  107. int source_id) {
  108. auto find_it = vibration_actuators_.find(source_id);
  109. if (find_it != vibration_actuators_.end()) {
  110. find_it->second->Shutdown();
  111. vibration_actuators_.erase(find_it);
  112. }
  113. }
  114. void GamepadPlatformDataFetcherAndroid::SetVibration(int device_index,
  115. double strong_magnitude,
  116. double weak_magnitude) {
  117. Java_GamepadList_setVibration(base::android::AttachCurrentThread(),
  118. device_index, strong_magnitude, weak_magnitude);
  119. }
  120. void GamepadPlatformDataFetcherAndroid::SetZeroVibration(int device_index) {
  121. Java_GamepadList_setZeroVibration(base::android::AttachCurrentThread(),
  122. device_index);
  123. }
  124. void GamepadPlatformDataFetcherAndroid::GetGamepadData(
  125. bool devices_changed_hint) {
  126. TRACE_EVENT0("GAMEPAD", "GetGamepadData");
  127. JNIEnv* env = AttachCurrentThread();
  128. if (!env)
  129. return;
  130. Java_GamepadList_updateGamepadData(env, reinterpret_cast<intptr_t>(this));
  131. }
  132. void GamepadPlatformDataFetcherAndroid::PauseHint(bool paused) {
  133. JNIEnv* env = AttachCurrentThread();
  134. if (!env)
  135. return;
  136. Java_GamepadList_setGamepadAPIActive(env, !paused);
  137. }
  138. void GamepadPlatformDataFetcherAndroid::PlayEffect(
  139. int source_id,
  140. mojom::GamepadHapticEffectType type,
  141. mojom::GamepadEffectParametersPtr params,
  142. mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback,
  143. scoped_refptr<base::SequencedTaskRunner> callback_runner) {
  144. auto find_it = vibration_actuators_.find(source_id);
  145. if (find_it == vibration_actuators_.end()) {
  146. LOG(ERROR) << "Failed to play vibration effect on a gamepad with no "
  147. "vibration actuator";
  148. RunVibrationCallback(
  149. std::move(callback), std::move(callback_runner),
  150. mojom::GamepadHapticsResult::GamepadHapticsResultError);
  151. return;
  152. }
  153. find_it->second->PlayEffect(type, std::move(params), std::move(callback),
  154. std::move(callback_runner));
  155. }
  156. void GamepadPlatformDataFetcherAndroid::ResetVibration(
  157. int source_id,
  158. mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback,
  159. scoped_refptr<base::SequencedTaskRunner> callback_runner) {
  160. auto find_it = vibration_actuators_.find(source_id);
  161. if (find_it == vibration_actuators_.end()) {
  162. LOG(ERROR) << "Failed to reset vibration effect on a gamepad with no "
  163. "vibration actuator";
  164. RunVibrationCallback(
  165. std::move(callback), std::move(callback_runner),
  166. mojom::GamepadHapticsResult::GamepadHapticsResultError);
  167. return;
  168. }
  169. find_it->second->ResetVibration(std::move(callback),
  170. std::move(callback_runner));
  171. }
  172. static void JNI_GamepadList_SetGamepadData(
  173. JNIEnv* env,
  174. const JavaParamRef<jobject>& obj,
  175. jlong data_fetcher,
  176. jint index,
  177. jboolean mapping,
  178. jboolean connected,
  179. const JavaParamRef<jstring>& devicename,
  180. jint vendor_id,
  181. jint product_id,
  182. jlong timestamp,
  183. const JavaParamRef<jfloatArray>& jaxes,
  184. const JavaParamRef<jfloatArray>& jbuttons,
  185. jint buttons_length,
  186. jboolean supports_dual_rumble) {
  187. DCHECK(data_fetcher);
  188. GamepadPlatformDataFetcherAndroid* fetcher =
  189. reinterpret_cast<GamepadPlatformDataFetcherAndroid*>(data_fetcher);
  190. DCHECK_LT(index, static_cast<int>(Gamepads::kItemsLengthCap));
  191. // Do not set gamepad parameters for all the gamepad devices that are not
  192. // attached.
  193. if (!connected) {
  194. fetcher->TryShutdownDualRumbleVibrationActuator(index);
  195. return;
  196. }
  197. PadState* state = fetcher->GetPadState(index);
  198. if (!state)
  199. return;
  200. Gamepad& pad = state->data;
  201. // Is this the first time we've seen this device?
  202. if (!state->is_initialized) {
  203. state->is_initialized = true;
  204. std::string product_name =
  205. base::android::ConvertJavaStringToUTF8(env, devicename);
  206. if (!mapping) {
  207. // The gamepad was assigned the default mapping function. Check if it is
  208. // known to be mapped correctly with the default mapping function on this
  209. // version of Android.
  210. auto gamepad_id = GamepadIdList::Get().GetGamepadId(
  211. product_name, vendor_id, product_id);
  212. auto x_input_type =
  213. GamepadIdList::Get().GetXInputType(vendor_id, product_id);
  214. mapping = HasStandardMappingOnAndroid(gamepad_id, x_input_type);
  215. }
  216. GamepadDataFetcher::UpdateGamepadStrings(product_name, vendor_id,
  217. product_id, mapping, pad);
  218. if (base::FeatureList::IsEnabled(
  219. features::kEnableAndroidGamepadVibration)) {
  220. pad.vibration_actuator.type = GamepadHapticActuatorType::kDualRumble;
  221. pad.vibration_actuator.not_null = supports_dual_rumble;
  222. if (supports_dual_rumble) {
  223. fetcher->SetDualRumbleVibrationActuator(state->source_id);
  224. }
  225. }
  226. }
  227. pad.connected = true;
  228. pad.timestamp = GamepadDataFetcher::CurrentTimeInMicroseconds();
  229. std::vector<float> axes;
  230. base::android::JavaFloatArrayToFloatVector(env, jaxes, &axes);
  231. // Set Gamepad::axes_length to the total number of axes on the gamepad device.
  232. // Only return the first kAxesLengthCap if the axes size captured by
  233. // GamepadList is larger than kAxesLengthCap.
  234. pad.axes_length = std::min(static_cast<int>(axes.size()),
  235. static_cast<int>(Gamepad::kAxesLengthCap));
  236. // Copy axes state to the Gamepad axes[].
  237. for (unsigned int i = 0; i < pad.axes_length; i++) {
  238. pad.axes[i] = static_cast<double>(axes[i]);
  239. }
  240. std::vector<float> buttons;
  241. base::android::JavaFloatArrayToFloatVector(env, jbuttons, &buttons);
  242. // Set Gamepad::buttons_length to the total number of buttons on the gamepad
  243. // device. Only return the first kButtonsLengthCap if buttons_length captured
  244. // by GamepadList is larger than kButtonsLengthCap.
  245. pad.buttons_length =
  246. std::min({static_cast<int>(buttons.size()), buttons_length,
  247. static_cast<int>(Gamepad::kButtonsLengthCap)});
  248. // Copy buttons state to the Gamepad buttons[].
  249. for (unsigned int j = 0; j < pad.buttons_length; j++) {
  250. pad.buttons[j].pressed =
  251. buttons[j] > GamepadButton::kDefaultButtonPressedThreshold;
  252. pad.buttons[j].touched = buttons[j] > 0.0f;
  253. pad.buttons[j].value = buttons[j];
  254. }
  255. }
  256. } // namespace device