From d130fc94651161312cf3381b851428f8f68c37cc Mon Sep 17 00:00:00 2001
From: Connor McLaughlin <stenzek@gmail.com>
Date: Tue, 22 Dec 2020 02:15:55 +1000
Subject: [PATCH] Android: Possible fix for white overlay with controller

---
 .../duckstation/EmulationActivity.java        | 28 +++++++++++
 .../duckstation/EmulationSurfaceView.java     | 46 ++++++++++++++-----
 .../TouchscreenControllerView.java            |  2 +
 3 files changed, 64 insertions(+), 12 deletions(-)

diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java
index 3bd9b6704..dea4fbe0a 100644
--- a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java
+++ b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java
@@ -7,9 +7,12 @@ import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.hardware.input.InputManager;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Vibrator;
 import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
 import android.view.SurfaceHolder;
 import android.view.View;
 import android.widget.FrameLayout;
@@ -209,7 +212,11 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
 
         mContentView = findViewById(R.id.fullscreen_content);
         mContentView.getHolder().addCallback(this);
+        mContentView.setFocusableInTouchMode(true);
         mContentView.setFocusable(true);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            mContentView.setFocusedByDefault(true);
+        }
         mContentView.requestFocus();
 
         // Hook up controller input.
@@ -265,6 +272,27 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
         showMenu();
     }
 
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            if (mContentView.onKeyDown(event.getKeyCode(), event))
+                return true;
+        } else if (event.getAction() == KeyEvent.ACTION_UP) {
+            if (mContentView.onKeyUp(event.getKeyCode(), event))
+                return true;
+        }
+
+        return super.dispatchKeyEvent(event);
+    }
+
+    @Override
+    public boolean dispatchGenericMotionEvent(MotionEvent ev) {
+        if (mContentView.onGenericMotionEvent(ev))
+            return true;
+
+        return super.dispatchGenericMotionEvent(ev);
+    }
+
     @Override
     public void onConfigurationChanged(@NonNull Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationSurfaceView.java b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationSurfaceView.java
index f121a7d1a..dae19de45 100644
--- a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationSurfaceView.java
+++ b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationSurfaceView.java
@@ -31,31 +31,53 @@ public class EmulationSurfaceView extends SurfaceView {
                 (source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK;
     }
 
+    private boolean isExternalKeyCode(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_BACK:
+            case KeyEvent.KEYCODE_HOME:
+            case KeyEvent.KEYCODE_MENU:
+            case KeyEvent.KEYCODE_VOLUME_UP:
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_MUTE:
+            case KeyEvent.KEYCODE_POWER:
+            case KeyEvent.KEYCODE_CAMERA:
+            case KeyEvent.KEYCODE_CALL:
+            case KeyEvent.KEYCODE_ENDCALL:
+            case KeyEvent.KEYCODE_VOICE_ASSIST:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (isDPadOrButtonEvent(event) && event.getRepeatCount() == 0 &&
-                handleControllerKey(event.getDeviceId(), keyCode, true)) {
-            return true;
-        }
+        if (!isDPadOrButtonEvent(event) || isExternalKeyCode(keyCode))
+            return false;
 
-        return super.onKeyDown(keyCode, event);
+        if (event.getRepeatCount() == 0)
+            handleControllerKey(event.getDeviceId(), keyCode, true);
+
+        return true;
     }
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (isDPadOrButtonEvent(event) && event.getRepeatCount() == 0 &&
-                handleControllerKey(event.getDeviceId(), keyCode, false)) {
-            return true;
-        }
+        if (!isDPadOrButtonEvent(event) || isExternalKeyCode(keyCode))
+            return false;
 
-        return super.onKeyDown(keyCode, event);
+        if (event.getRepeatCount() == 0)
+            handleControllerKey(event.getDeviceId(), keyCode, false);
+
+        return true;
     }
 
     @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
         final int source = event.getSource();
-        if ((source & InputDevice.SOURCE_JOYSTICK) == 0)
-            return super.onGenericMotionEvent(event);
+        if ((source & (InputDevice.SOURCE_JOYSTICK | InputDevice.SOURCE_GAMEPAD | InputDevice.SOURCE_DPAD)) == 0)
+            return false;
 
         final int deviceId = event.getDeviceId();
         for (AxisMapping mapping : mControllerAxisMapping) {
diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerView.java b/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerView.java
index 19b7961f0..6ac5a724f 100644
--- a/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerView.java
+++ b/android/app/src/main/java/com/github/stenzek/duckstation/TouchscreenControllerView.java
@@ -41,6 +41,8 @@ public class TouchscreenControllerView extends FrameLayout {
 
     public TouchscreenControllerView(Context context) {
         super(context);
+        setFocusable(false);
+        setFocusableInTouchMode(false);
     }
 
     public TouchscreenControllerView(Context context, AttributeSet attrs) {