Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions backends/platform/android/org/scummvm/scummvm/ScummVMActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ public class ScummVMActivity extends Activity implements OnKeyboardVisibilityLis
private GridLayout _buttonLayout = null;
private ImageView _toggleTouchModeKeyboardBtnIcon = null;
private ImageView _openMenuBtnIcon = null;
private ImageView _toggleSecondScreenBtnIcon = null;
private SecondScreenManager _secondScreenManager = null;
private LedView _ioLed = null;
private int _layoutOrientation;

Expand Down Expand Up @@ -697,6 +699,22 @@ public void run() {
}
};

public final View.OnClickListener secondScreenBtnOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
runOnUiThread(new Runnable() {
public void run() {
if (_secondScreenManager != null) {
boolean enabled = _secondScreenManager.toggle();
if (_toggleSecondScreenBtnIcon != null) {
_toggleSecondScreenBtnIcon.setAlpha(enabled ? 1.0f : 0.4f);
}
}
}
});
}
};

private class MyScummVM extends ScummVM {

public MyScummVM(SurfaceHolder holder, final MyScummVMDestroyedCallback destroyedCallback) {
Expand Down Expand Up @@ -1113,6 +1131,21 @@ public void handle(int exitResult) {
_toggleTouchModeKeyboardBtnIcon.setOnLongClickListener(touchModeKeyboardBtnOnLongClickListener);
_openMenuBtnIcon.setOnClickListener(menuBtnOnClickListener);

// Second screen touchpad support (API 17+)
_toggleSecondScreenBtnIcon = findViewById(R.id.toggle_second_screen_button);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
_secondScreenManager = new SecondScreenManager(this, _scummvm);
_secondScreenManager.start();
if (_secondScreenManager.hasSecondaryDisplay()) {
_toggleSecondScreenBtnIcon.setVisibility(View.VISIBLE);
_toggleSecondScreenBtnIcon.setOnClickListener(secondScreenBtnOnClickListener);
} else {
_toggleSecondScreenBtnIcon.setVisibility(View.GONE);
}
} else {
_toggleSecondScreenBtnIcon.setVisibility(View.GONE);
}

// Keyboard visibility listener - mainly to hide system UI if keyboard is shown and we return from Suspend to the Activity
setKeyboardVisibilityListener(this);

Expand Down Expand Up @@ -1260,6 +1293,11 @@ public void onDestroy() {
hideScreenKeyboard();
}

if (_secondScreenManager != null) {
_secondScreenManager.stop();
_secondScreenManager = null;
}

if (_events != null) {
_finishing = true;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.scummvm.scummvm;

import android.app.Activity;
import android.app.Application;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;

public class SecondScreenHelper {

private static SecondScreenManager sManager;
private static ImageView sToggleBtn;
private static Application.ActivityLifecycleCallbacks sLifecycleCallbacks;

public static void init(Activity activity, ScummVM scummvm) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) return;

DisplayMetrics dm = new DisplayMetrics();
WindowManager wm = (WindowManager) activity.getSystemService(Activity.WINDOW_SERVICE);
if (wm != null) {
wm.getDefaultDisplay().getRealMetrics(dm);
}
int screenW = Math.max(dm.widthPixels, dm.heightPixels);
int screenH = Math.min(dm.widthPixels, dm.heightPixels);

sManager = new SecondScreenManager(activity, scummvm, screenW, screenH);
sManager.start();

int btnId = activity.getResources().getIdentifier(
"toggle_second_screen_button", "id", activity.getPackageName());
if (btnId != 0) {
sToggleBtn = activity.findViewById(btnId);
}

if (sToggleBtn != null && sManager.hasSecondaryDisplay()) {
sToggleBtn.setVisibility(View.VISIBLE);
sToggleBtn.setAlpha(1.0f);
sToggleBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (sManager != null) {
boolean enabled = sManager.toggle();
if (sToggleBtn != null) {
sToggleBtn.setAlpha(enabled ? 1.0f : 0.4f);
}
}
}
});

sManager.toggle();

sLifecycleCallbacks = new Application.ActivityLifecycleCallbacks() {
@Override public void onActivityCreated(Activity a, Bundle s) {}
@Override public void onActivityStarted(Activity a) {}
@Override
public void onActivityResumed(Activity a) {
if (a instanceof ScummVMActivity && sManager != null) {
sManager.onResume();
}
}
@Override
public void onActivityPaused(Activity a) {
if (a instanceof ScummVMActivity && sManager != null) {
sManager.onPause();
}
}
@Override public void onActivityStopped(Activity a) {}
@Override public void onActivitySaveInstanceState(Activity a, Bundle o) {}
@Override public void onActivityDestroyed(Activity a) {}
};
activity.getApplication().registerActivityLifecycleCallbacks(sLifecycleCallbacks);
}
}

public static void destroy() {
if (sManager != null) {
sManager.stop();
sManager = null;
}
sToggleBtn = null;
sLifecycleCallbacks = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.scummvm.scummvm;

import android.app.Activity;
import android.app.Application;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

import androidx.annotation.RequiresApi;

@RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public class SecondScreenInitializer implements Application.ActivityLifecycleCallbacks {

private SecondScreenManager _manager;
private ImageView _toggleBtn;

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (!(activity instanceof ScummVMActivity)) return;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) return;

ScummVMActivity svm = (ScummVMActivity) activity;

try {
java.lang.reflect.Field field = ScummVMActivity.class.getDeclaredField("_scummvm");
field.setAccessible(true);
ScummVM scummvm = (ScummVM) field.get(svm);
if (scummvm == null) return;

_manager = new SecondScreenManager(activity, scummvm);
_manager.start();

_toggleBtn = activity.findViewById(
activity.getResources().getIdentifier(
"toggle_second_screen_button", "id", activity.getPackageName()));

if (_toggleBtn != null && _manager.hasSecondaryDisplay()) {
_toggleBtn.setVisibility(View.VISIBLE);
_toggleBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (_manager != null) {
boolean enabled = _manager.toggle();
_toggleBtn.setAlpha(enabled ? 1.0f : 0.4f);
}
}
});
}
} catch (Exception e) {
// _scummvm field not accessible or not yet initialized
}
}

@Override
public void onActivityStarted(Activity activity) {}

@Override
public void onActivityResumed(Activity activity) {}

@Override
public void onActivityPaused(Activity activity) {}

@Override
public void onActivityStopped(Activity activity) {}

@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}

@Override
public void onActivityDestroyed(Activity activity) {
if (!(activity instanceof ScummVMActivity)) return;
if (_manager != null) {
_manager.stop();
_manager = null;
}
}
}
134 changes: 134 additions & 0 deletions backends/platform/android/org/scummvm/scummvm/SecondScreenManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package org.scummvm.scummvm;

import android.content.Context;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.view.Display;

import androidx.annotation.RequiresApi;

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
public class SecondScreenManager {

private final Context _context;
private final ScummVM _scummvm;
private final DisplayManager _displayManager;
private final int _mainScreenWidth;
private final int _mainScreenHeight;
private SecondScreenPresentation _presentation;
private DisplayManager.DisplayListener _displayListener;
private boolean _enabled = false;

public SecondScreenManager(Context context, ScummVM scummvm, int mainScreenWidth, int mainScreenHeight) {
_context = context;
_scummvm = scummvm;
_displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
_mainScreenWidth = mainScreenWidth;
_mainScreenHeight = mainScreenHeight;
}

public void start() {
if (_displayManager == null) return;

_displayListener = new DisplayManager.DisplayListener() {
@Override
public void onDisplayAdded(int displayId) {
if (_enabled) {
tryShowPresentation();
}
}

@Override
public void onDisplayRemoved(int displayId) {
dismissPresentation();
}

@Override
public void onDisplayChanged(int displayId) {
}
};

_displayManager.registerDisplayListener(_displayListener,
new Handler(Looper.getMainLooper()));
}

public void stop() {
dismissPresentation();
if (_displayManager != null && _displayListener != null) {
_displayManager.unregisterDisplayListener(_displayListener);
_displayListener = null;
}
}

public boolean toggle() {
_enabled = !_enabled;
if (_enabled) {
tryShowPresentation();
} else {
dismissPresentation();
}
return _enabled;
}

public boolean isEnabled() {
return _enabled;
}

public boolean hasSecondaryDisplay() {
return findPresentationDisplay() != null;
}

public void onPause() {
dismissPresentation();
}

public void onResume() {
if (_enabled) {
tryShowPresentation();
}
}

private void tryShowPresentation() {
Display display = findPresentationDisplay();
if (display != null) {
showPresentation(display);
}
}

private void showPresentation(Display display) {
dismissPresentation();
try {
_presentation = new SecondScreenPresentation(
_context, display, _scummvm, _mainScreenWidth, _mainScreenHeight);
_presentation.show();
} catch (Exception e) {
_presentation = null;
}
}

private void dismissPresentation() {
if (_presentation != null) {
try {
_presentation.dismiss();
} catch (Exception ignored) {
}
_presentation = null;
}
}

private Display findPresentationDisplay() {
if (_displayManager == null) return null;

Display[] displays = _displayManager.getDisplays(
DisplayManager.DISPLAY_CATEGORY_PRESENTATION);

for (Display d : displays) {
if (d.getDisplayId() != 0 && !"HiddenDisplay".equals(d.getName())) {
return d;
}
}
return null;
}
}
Loading