diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 0e3e11f574..36b75c1a75 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -3,7 +3,9 @@ package org.dolphinemu.dolphinemu.activities; import android.app.Activity; import android.app.ActivityOptions; import android.app.Fragment; +import android.content.Context; import android.content.Intent; +import android.hardware.usb.UsbManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -30,6 +32,7 @@ import org.dolphinemu.dolphinemu.fragments.MenuFragment; import org.dolphinemu.dolphinemu.fragments.SaveStateFragment; import org.dolphinemu.dolphinemu.ui.main.MainPresenter; import org.dolphinemu.dolphinemu.utils.Animations; +import org.dolphinemu.dolphinemu.utils.Java_GCAdapter; import org.dolphinemu.dolphinemu.utils.Log; import java.util.List; @@ -115,6 +118,8 @@ public final class EmulationActivity extends AppCompatActivity setTheme(themeId); super.onCreate(savedInstanceState); + Java_GCAdapter.our_activity = this; + Java_GCAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE); // Picasso will take a while to load these big-ass screenshots. So don't run // the animation until we say so. diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/USBPermService.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/USBPermService.java new file mode 100644 index 0000000000..490504c167 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/USBPermService.java @@ -0,0 +1,14 @@ +package org.dolphinemu.dolphinemu.services; + +import android.app.IntentService; +import android.content.Intent; + +public final class USBPermService extends IntentService +{ + public USBPermService() { super("USBPermService"); } + + // Needed when extending IntentService. + // We don't care about the results of the intent handler for this. + @Override + protected void onHandleIntent(Intent intent) {} +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java index 51d00ad348..2b2286d5c7 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java @@ -1,6 +1,9 @@ package org.dolphinemu.dolphinemu.utils; import android.app.Activity; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; import android.hardware.usb.UsbConfiguration; import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbDevice; @@ -9,8 +12,11 @@ import android.hardware.usb.UsbEndpoint; import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; +import org.dolphinemu.dolphinemu.services.USBPermService; + import java.util.HashMap; import java.util.Iterator; +import java.util.Map; public class Java_GCAdapter { public static UsbManager manager; @@ -23,6 +29,26 @@ public class Java_GCAdapter { static UsbEndpoint usb_in; static UsbEndpoint usb_out; + private static void RequestPermission() + { + HashMap devices = manager.getDeviceList(); + for (Map.Entry pair : devices.entrySet()) + { + UsbDevice dev = (UsbDevice) pair.getValue(); + if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) + { + if (!manager.hasPermission(dev)) + { + Intent intent = new Intent(); + PendingIntent pend_intent; + intent.setClass(our_activity, USBPermService.class); + pend_intent = PendingIntent.getService(our_activity, 0, intent, 0); + manager.requestPermission(dev, pend_intent); + } + } + } + } + public static void Shutdown() { usb_con.close(); @@ -32,14 +58,16 @@ public class Java_GCAdapter { public static boolean QueryAdapter() { HashMap devices = manager.getDeviceList(); - Iterator it = devices.entrySet().iterator(); - while (it.hasNext()) + for (Map.Entry pair : devices.entrySet()) { - HashMap.Entry pair = (HashMap.Entry) it.next(); UsbDevice dev = (UsbDevice) pair.getValue(); if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) + { if (manager.hasPermission(dev)) return true; + else + RequestPermission(); + } } return false; } diff --git a/Source/Core/InputCommon/GCAdapter_Android.cpp b/Source/Core/InputCommon/GCAdapter_Android.cpp index 6e638e2a72..4fa887cd23 100644 --- a/Source/Core/InputCommon/GCAdapter_Android.cpp +++ b/Source/Core/InputCommon/GCAdapter_Android.cpp @@ -35,7 +35,7 @@ static u8 s_controller_rumble[4]; // Input handling static std::mutex s_read_mutex; static u8 s_controller_payload[37]; -static int s_controller_payload_size = 0; +static std::atomic s_controller_payload_size{0}; // Output handling static std::mutex s_write_mutex; @@ -102,12 +102,13 @@ static void Read() while (s_read_adapter_thread_running.IsSet()) { - s_controller_payload_size = env->CallStaticIntMethod(s_adapter_class, input_func); + int read_size = env->CallStaticIntMethod(s_adapter_class, input_func); jbyte* java_data = env->GetByteArrayElements(*java_controller_payload, nullptr); { std::lock_guard lk(s_read_mutex); memcpy(s_controller_payload, java_data, 0x37); + s_controller_payload_size.store(read_size); } env->ReleaseByteArrayElements(*java_controller_payload, java_data, 0); @@ -187,6 +188,8 @@ void Init() void Setup() { + s_fd = 0; + s_read_adapter_thread_running.Set(true); s_read_adapter_thread = std::thread(Read); @@ -244,16 +247,18 @@ void Input(int chan, GCPadStatus* pad) if (!UseAdapter() || !s_detected || !s_fd) return; + int payload_size = 0; u8 controller_payload_copy[37]; { std::lock_guard lk(s_read_mutex); std::copy(std::begin(s_controller_payload), std::end(s_controller_payload), std::begin(controller_payload_copy)); + payload_size = s_controller_payload_size.load(); } - if (s_controller_payload_size != sizeof(controller_payload_copy)) + if (payload_size != sizeof(controller_payload_copy)) { - ERROR_LOG(SERIALINTERFACE, "error reading payload (size: %d, type: %02x)", s_controller_payload_size, controller_payload_copy[0]); + ERROR_LOG(SERIALINTERFACE, "error reading payload (size: %d, type: %02x)", payload_size, controller_payload_copy[0]); Reset(); } else