Prevent PiP entry while the USB permission dialog is open

This commit is contained in:
Cameron Gutman
2022-06-13 19:23:03 -05:00
parent 982b36cf98
commit 529a2f7bf8
2 changed files with 89 additions and 18 deletions

View File

@@ -87,7 +87,7 @@ import java.util.Locale;
public class Game extends Activity implements SurfaceHolder.Callback, public class Game extends Activity implements SurfaceHolder.Callback,
OnGenericMotionListener, OnTouchListener, NvConnectionListener, EvdevListener, OnGenericMotionListener, OnTouchListener, NvConnectionListener, EvdevListener,
OnSystemUiVisibilityChangeListener, GameGestures, StreamView.InputCallbacks, OnSystemUiVisibilityChangeListener, GameGestures, StreamView.InputCallbacks,
PerfOverlayListener PerfOverlayListener, UsbDriverService.UsbDriverStateListener
{ {
private int lastButtonState = 0; private int lastButtonState = 0;
@@ -121,6 +121,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
private boolean autoEnterPip = false; private boolean autoEnterPip = false;
private boolean surfaceCreated = false; private boolean surfaceCreated = false;
private boolean attemptedConnection = false; private boolean attemptedConnection = false;
private int suppressPipRefCount = 0;
private String pcName; private String pcName;
private String appName; private String appName;
@@ -153,6 +154,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
public void onServiceConnected(ComponentName componentName, IBinder iBinder) { public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
UsbDriverService.UsbDriverBinder binder = (UsbDriverService.UsbDriverBinder) iBinder; UsbDriverService.UsbDriverBinder binder = (UsbDriverService.UsbDriverBinder) iBinder;
binder.setListener(controllerHandler); binder.setListener(controllerHandler);
binder.setStateListener(Game.this);
binder.start();
connectedToUsbDriverService = true; connectedToUsbDriverService = true;
} }
@@ -573,11 +576,13 @@ public class Game extends Activity implements SurfaceHolder.Callback,
return builder.build(); return builder.build();
} }
private void setPipAutoEnter(boolean autoEnter) { private void updatePipAutoEnter() {
if (!prefConfig.enablePip) { if (!prefConfig.enablePip) {
return; return;
} }
boolean autoEnter = connected && suppressPipRefCount == 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
setPictureInPictureParams(getPictureInPictureParams(autoEnter)); setPictureInPictureParams(getPictureInPictureParams(autoEnter));
} }
@@ -1608,8 +1613,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
private void stopConnection() { private void stopConnection() {
if (connecting || connected) { if (connecting || connected) {
setPipAutoEnter(false);
connecting = connected = false; connecting = connected = false;
updatePipAutoEnter();
controllerHandler.stop(); controllerHandler.stop();
@@ -1776,9 +1781,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
spinner = null; spinner = null;
} }
setPipAutoEnter(true);
connected = true; connected = true;
connecting = false; connecting = false;
updatePipAutoEnter();
// Hide the mouse cursor now after a short delay. // Hide the mouse cursor now after a short delay.
// Doing it before dismissing the spinner seems to be undone // Doing it before dismissing the spinner seems to be undone
@@ -1976,4 +1981,18 @@ public class Game extends Activity implements SurfaceHolder.Callback,
} }
}); });
} }
@Override
public void onUsbPermissionPromptStarting() {
// Disable PiP auto-enter while the USB permission prompt is on-screen. This prevents
// us from entering PiP while the user is interacting with the OS permission dialog.
suppressPipRefCount++;
updatePipAutoEnter();
}
@Override
public void onUsbPermissionPromptCompleted() {
suppressPipRefCount--;
updatePipAutoEnter();
}
} }

View File

@@ -29,6 +29,7 @@ public class UsbDriverService extends Service implements UsbDriverListener {
private UsbManager usbManager; private UsbManager usbManager;
private PreferenceConfiguration prefConfig; private PreferenceConfiguration prefConfig;
private boolean started;
private final UsbEventReceiver receiver = new UsbEventReceiver(); private final UsbEventReceiver receiver = new UsbEventReceiver();
private final UsbDriverBinder binder = new UsbDriverBinder(); private final UsbDriverBinder binder = new UsbDriverBinder();
@@ -36,6 +37,7 @@ public class UsbDriverService extends Service implements UsbDriverListener {
private final ArrayList<AbstractController> controllers = new ArrayList<>(); private final ArrayList<AbstractController> controllers = new ArrayList<>();
private UsbDriverListener listener; private UsbDriverListener listener;
private UsbDriverStateListener stateListener;
private int nextDeviceId; private int nextDeviceId;
@Override @Override
@@ -93,6 +95,11 @@ public class UsbDriverService extends Service implements UsbDriverListener {
else if (action.equals(ACTION_USB_PERMISSION)) { else if (action.equals(ACTION_USB_PERMISSION)) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
// Permission dialog is now closed
if (stateListener != null) {
stateListener.onUsbPermissionPromptCompleted();
}
// If we got this far, we've already found we're able to handle this device // If we got this far, we've already found we're able to handle this device
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
handleUsbDeviceState(device); handleUsbDeviceState(device);
@@ -112,6 +119,18 @@ public class UsbDriverService extends Service implements UsbDriverListener {
} }
} }
} }
public void setStateListener(UsbDriverStateListener stateListener) {
UsbDriverService.this.stateListener = stateListener;
}
public void start() {
UsbDriverService.this.start();
}
public void stop() {
UsbDriverService.this.stop();
}
} }
private void handleUsbDeviceState(UsbDevice device) { private void handleUsbDeviceState(UsbDevice device) {
@@ -121,20 +140,29 @@ public class UsbDriverService extends Service implements UsbDriverListener {
if (!usbManager.hasPermission(device)) { if (!usbManager.hasPermission(device)) {
// Let's ask for permission // Let's ask for permission
try { try {
// Tell the state listener that we're about to display a permission dialog
if (stateListener != null) {
stateListener.onUsbPermissionPromptStarting();
}
int intentFlags = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// This PendingIntent must be mutable to allow the framework to populate EXTRA_DEVICE and EXTRA_PERMISSION_GRANTED.
intentFlags |= PendingIntent.FLAG_MUTABLE;
}
// This function is not documented as throwing any exceptions (denying access // This function is not documented as throwing any exceptions (denying access
// is indicated by calling the PendingIntent with a false result). However, // is indicated by calling the PendingIntent with a false result). However,
// Samsung Knox has some policies which block this request, but rather than // Samsung Knox has some policies which block this request, but rather than
// just returning a false result or returning 0 enumerated devices, // just returning a false result or returning 0 enumerated devices,
// they throw an undocumented SecurityException from this call, crashing // they throw an undocumented SecurityException from this call, crashing
// the whole app. :( // the whole app. :(
int intentFlags = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// This PendingIntent must be mutable to allow the framework to populate EXTRA_DEVICE and EXTRA_PERMISSION_GRANTED.
intentFlags |= PendingIntent.FLAG_MUTABLE;
}
usbManager.requestPermission(device, PendingIntent.getBroadcast(UsbDriverService.this, 0, new Intent(ACTION_USB_PERMISSION), intentFlags)); usbManager.requestPermission(device, PendingIntent.getBroadcast(UsbDriverService.this, 0, new Intent(ACTION_USB_PERMISSION), intentFlags));
} catch (SecurityException e) { } catch (SecurityException e) {
Toast.makeText(this, this.getText(R.string.error_usb_prohibited), Toast.LENGTH_LONG).show(); Toast.makeText(this, this.getText(R.string.error_usb_prohibited), Toast.LENGTH_LONG).show();
if (stateListener != null) {
stateListener.onUsbPermissionPromptCompleted();
}
} }
return; return;
} }
@@ -225,10 +253,12 @@ public class UsbDriverService extends Service implements UsbDriverListener {
((!isRecognizedInputDevice(device) || claimAllAvailable) && Xbox360Controller.canClaimDevice(device)); ((!isRecognizedInputDevice(device) || claimAllAvailable) && Xbox360Controller.canClaimDevice(device));
} }
@Override private void start() {
public void onCreate() { if (started) {
this.usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); return;
this.prefConfig = PreferenceConfiguration.readPreferences(this); }
started = true;
// Register for USB attach broadcasts and permission completions // Register for USB attach broadcasts and permission completions
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
@@ -250,14 +280,16 @@ public class UsbDriverService extends Service implements UsbDriverListener {
} }
} }
@Override private void stop() {
public void onDestroy() { if (!started) {
return;
}
started = false;
// Stop the attachment receiver // Stop the attachment receiver
unregisterReceiver(receiver); unregisterReceiver(receiver);
// Remove listeners
listener = null;
// Stop all controllers // Stop all controllers
while (controllers.size() > 0) { while (controllers.size() > 0) {
// Stop and remove the controller // Stop and remove the controller
@@ -265,8 +297,28 @@ public class UsbDriverService extends Service implements UsbDriverListener {
} }
} }
@Override
public void onCreate() {
this.usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
this.prefConfig = PreferenceConfiguration.readPreferences(this);
}
@Override
public void onDestroy() {
stop();
// Remove listeners
listener = null;
stateListener = null;
}
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
return binder; return binder;
} }
public interface UsbDriverStateListener {
void onUsbPermissionPromptStarting();
void onUsbPermissionPromptCompleted();
}
} }