Home | History | Annotate | Download | only in gamepad
      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 
      5 #include "content/browser/gamepad/gamepad_platform_data_fetcher_android.h"
      6 
      7 #include "base/android/jni_android.h"
      8 #include "base/android/jni_array.h"
      9 #include "base/android/jni_string.h"
     10 #include "base/debug/trace_event.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 
     15 #include "jni/GamepadList_jni.h"
     16 
     17 #include "third_party/WebKit/public/platform/WebGamepads.h"
     18 
     19 using base::android::AttachCurrentThread;
     20 using base::android::CheckException;
     21 using base::android::ClearException;
     22 using base::android::ConvertJavaStringToUTF8;
     23 using base::android::ScopedJavaLocalRef;
     24 using blink::WebGamepad;
     25 using blink::WebGamepads;
     26 
     27 namespace content {
     28 
     29 bool
     30 GamepadPlatformDataFetcherAndroid::RegisterGamepadPlatformDataFetcherAndroid(
     31     JNIEnv* env) {
     32   return RegisterNativesImpl(env);
     33 }
     34 
     35 GamepadPlatformDataFetcherAndroid::GamepadPlatformDataFetcherAndroid() {
     36   PauseHint(false);
     37 }
     38 
     39 GamepadPlatformDataFetcherAndroid::~GamepadPlatformDataFetcherAndroid() {
     40   PauseHint(true);
     41 }
     42 
     43 void GamepadPlatformDataFetcherAndroid::GetGamepadData(
     44     blink::WebGamepads* pads,
     45     bool devices_changed_hint) {
     46   TRACE_EVENT0("GAMEPAD", "GetGamepadData");
     47 
     48   pads->length = 0;
     49 
     50   JNIEnv* env = AttachCurrentThread();
     51   if (!env)
     52     return;
     53 
     54   Java_GamepadList_updateGamepadData(env, reinterpret_cast<intptr_t>(pads));
     55 }
     56 
     57 void GamepadPlatformDataFetcherAndroid::PauseHint(bool paused) {
     58   JNIEnv* env = AttachCurrentThread();
     59   if (!env)
     60     return;
     61 
     62   Java_GamepadList_notifyForGamepadsAccess(env, paused);
     63 }
     64 
     65 static void SetGamepadData(JNIEnv* env,
     66                            jobject obj,
     67                            jlong gamepads,
     68                            jint index,
     69                            jboolean mapping,
     70                            jboolean connected,
     71                            jstring devicename,
     72                            jlong timestamp,
     73                            jfloatArray jaxes,
     74                            jfloatArray jbuttons) {
     75   DCHECK(gamepads);
     76   blink::WebGamepads* pads = reinterpret_cast<WebGamepads*>(gamepads);
     77   DCHECK_EQ(pads->length, unsigned(index));
     78   DCHECK_LT(index, static_cast<int>(blink::WebGamepads::itemsLengthCap));
     79 
     80   ++pads->length;
     81 
     82   blink::WebGamepad& pad = pads->items[index];
     83 
     84   pad.connected = connected;
     85 
     86   pad.timestamp = timestamp;
     87 
     88   // Do not set gamepad parameters for all the gamepad devices that are not
     89   // attached.
     90   if (!connected)
     91     return;
     92 
     93   // Map the Gamepad DeviceName String to the WebGamepad Id. Ideally it should
     94   // be mapped to vendor and product information but it is only available at
     95   // kernel level and it can not be queried using class
     96   // android.hardware.input.InputManager.
     97   // TODO(SaurabhK): Store a cached WebGamePad object in
     98   // GamepadPlatformDataFetcherAndroid and only update constant WebGamepad
     99   // values when a device has changed.
    100   base::string16 device_name;
    101   base::android::ConvertJavaStringToUTF16(env, devicename, &device_name);
    102   const size_t name_to_copy =
    103       std::min(device_name.size(), WebGamepad::idLengthCap - 1);
    104   memcpy(pad.id,
    105          device_name.data(),
    106          name_to_copy * sizeof(base::string16::value_type));
    107   pad.id[name_to_copy] = 0;
    108 
    109   base::string16 mapping_name = base::UTF8ToUTF16(mapping ? "standard" : "");
    110   const size_t mapping_to_copy =
    111       std::min(mapping_name.size(), WebGamepad::mappingLengthCap - 1);
    112   memcpy(pad.mapping,
    113          mapping_name.data(),
    114          mapping_to_copy * sizeof(base::string16::value_type));
    115   pad.mapping[mapping_to_copy] = 0;
    116 
    117   pad.timestamp = timestamp;
    118 
    119   std::vector<float> axes;
    120   base::android::JavaFloatArrayToFloatVector(env, jaxes, &axes);
    121 
    122   // Set WebGamepad axeslength to total number of axes on the gamepad device.
    123   // Only return the first axesLengthCap if axeslength captured by GamepadList
    124   // is larger than axesLengthCap.
    125   pad.axesLength = std::min(static_cast<int>(axes.size()),
    126                             static_cast<int>(WebGamepad::axesLengthCap));
    127 
    128   // Copy axes state to the WebGamepad axes[].
    129   for (unsigned int i = 0; i < pad.axesLength; i++) {
    130     pad.axes[i] = static_cast<double>(axes[i]);
    131   }
    132 
    133   std::vector<float> buttons;
    134   base::android::JavaFloatArrayToFloatVector(env, jbuttons, &buttons);
    135 
    136   // Set WebGamepad buttonslength to total number of axes on the gamepad
    137   // device. Only return the first buttonsLengthCap if axeslength captured by
    138   // GamepadList is larger than buttonsLengthCap.
    139   pad.buttonsLength = std::min(static_cast<int>(buttons.size()),
    140                                static_cast<int>(WebGamepad::buttonsLengthCap));
    141 
    142   // Copy buttons state to the WebGamepad buttons[].
    143   for (unsigned int j = 0; j < pad.buttonsLength; j++) {
    144     pad.buttons[j].pressed = buttons[j];
    145     pad.buttons[j].value = buttons[j];
    146   }
    147 }
    148 
    149 }  // namespace content
    150