Files
i-want-to-heal/android/app/src/main/java/com/warren/iwanttoheal/DualScreenPlugin.java
T

317 lines
12 KiB
Java

package com.warren.iwanttoheal;
import android.app.Presentation;
import android.content.Context;
import android.graphics.Color;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import com.getcapacitor.JSArray;
import com.getcapacitor.JSObject;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;
@CapacitorPlugin(name = "DualScreen")
public class DualScreenPlugin extends Plugin {
private TopDisplayPresentation presentation;
@PluginMethod
public void getDisplays(PluginCall call) {
DisplayManager displayManager =
(DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
Display currentDisplay = getActivity().getDisplay();
JSArray displays = new JSArray();
for (Display display : displayManager.getDisplays()) {
displays.put(describeDisplay(display, currentDisplay));
}
JSObject result = new JSObject();
result.put("currentDisplayId", currentDisplay == null ? -1 : currentDisplay.getDisplayId());
result.put("displays", displays);
call.resolve(result);
}
@PluginMethod
public void openTopDisplay(PluginCall call) {
getActivity().runOnUiThread(() -> {
try {
DisplayLaunchPlan launchPlan = createLaunchPlan(call.getInt("displayId"));
if (launchPlan.targetDisplay == null) {
call.reject("No secondary Android display is available.");
return;
}
Display currentDisplay = getActivity().getDisplay();
if (
currentDisplay != null
&& currentDisplay.getDisplayId() == launchPlan.targetDisplay.getDisplayId()
) {
JSObject result = describeDisplay(currentDisplay, currentDisplay);
result.put("opened", true);
result.put("alreadyOnMainDisplay", true);
call.resolve(result);
return;
}
String gameUrl = bridge.getLocalUrl();
String topGameUrl = gameUrl + "/?display=top";
String controlsUrl = gameUrl + "/?display=bottom";
String targetUrl = launchPlan.targetIsTopDisplay ? topGameUrl : controlsUrl;
String currentUrl = launchPlan.currentIsTopDisplay ? topGameUrl : controlsUrl;
closePresentation();
presentation = new TopDisplayPresentation(
getActivity(),
launchPlan.targetDisplay,
targetUrl
);
presentation.setOnDismissListener(dialog -> {
presentation = null;
notifyListeners("displayDisconnected", new JSObject());
});
presentation.show();
bridge.getWebView().loadUrl(currentUrl);
JSObject result = describeDisplay(launchPlan.targetDisplay, getActivity().getDisplay());
result.put("opened", true);
result.put("presentationMode", true);
result.put("targetIsTopDisplay", launchPlan.targetIsTopDisplay);
result.put("currentIsTopDisplay", launchPlan.currentIsTopDisplay);
call.resolve(result);
} catch (Exception exception) {
closePresentation();
call.reject("Unable to open the upper display.", exception);
}
});
}
@PluginMethod
public void closeTopDisplay(PluginCall call) {
getActivity().runOnUiThread(() -> {
closePresentation();
call.resolve();
});
}
@Override
protected void handleOnDestroy() {
closePresentation();
}
private DisplayLaunchPlan createLaunchPlan(Integer requestedDisplayId) {
DisplayManager displayManager =
(DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
Display currentDisplay = getActivity().getDisplay();
int currentDisplayId = currentDisplay == null ? -1 : currentDisplay.getDisplayId();
Display topDisplay = largestDisplay(displayManager.getDisplays());
boolean currentIsTopDisplay =
topDisplay != null && topDisplay.getDisplayId() == currentDisplayId;
Display targetDisplay = null;
if (requestedDisplayId != null) {
Display requested = displayManager.getDisplay(requestedDisplayId);
if (
requested != null
&& requested.getDisplayId() != currentDisplayId
&& requested.getState() != Display.STATE_OFF
) {
targetDisplay = requested;
}
}
if (targetDisplay == null && currentIsTopDisplay) {
targetDisplay = smallestOtherDisplay(displayManager.getDisplays(), currentDisplayId);
}
if (targetDisplay == null && topDisplay != null && topDisplay.getDisplayId() != currentDisplayId) {
targetDisplay = topDisplay;
}
if (targetDisplay == null) {
targetDisplay = largestOtherDisplay(
displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION),
currentDisplayId
);
}
if (targetDisplay == null) {
targetDisplay = largestOtherDisplay(displayManager.getDisplays(), currentDisplayId);
}
boolean targetIsTopDisplay =
topDisplay != null && targetDisplay != null
&& targetDisplay.getDisplayId() == topDisplay.getDisplayId();
return new DisplayLaunchPlan(targetDisplay, targetIsTopDisplay, currentIsTopDisplay);
}
private Display largestDisplay(Display[] displays) {
Display selected = null;
long selectedPixels = -1;
for (Display display : displays) {
if (display.getState() == Display.STATE_OFF) continue;
long pixels = pixelCount(display);
if (pixels > selectedPixels) {
selected = display;
selectedPixels = pixels;
}
}
return selected;
}
private Display largestOtherDisplay(Display[] displays, int currentDisplayId) {
Display selected = null;
long selectedPixels = -1;
for (Display display : displays) {
if (
display.getDisplayId() == currentDisplayId
|| display.getState() == Display.STATE_OFF
) {
continue;
}
long pixels = pixelCount(display);
if (pixels > selectedPixels) {
selected = display;
selectedPixels = pixels;
}
}
return selected;
}
private Display smallestOtherDisplay(Display[] displays, int currentDisplayId) {
Display selected = null;
long selectedPixels = Long.MAX_VALUE;
for (Display display : displays) {
if (
display.getDisplayId() == currentDisplayId
|| display.getState() == Display.STATE_OFF
) {
continue;
}
long pixels = pixelCount(display);
if (pixels < selectedPixels) {
selected = display;
selectedPixels = pixels;
}
}
return selected;
}
private long pixelCount(Display display) {
Display.Mode mode = display.getMode();
return (long) mode.getPhysicalWidth() * mode.getPhysicalHeight();
}
private JSObject describeDisplay(Display display, Display currentDisplay) {
Display.Mode mode = display.getMode();
JSObject result = new JSObject();
result.put("id", display.getDisplayId());
result.put("name", display.getName());
result.put("width", mode.getPhysicalWidth());
result.put("height", mode.getPhysicalHeight());
result.put("refreshRate", mode.getRefreshRate());
result.put(
"isCurrent",
currentDisplay != null && currentDisplay.getDisplayId() == display.getDisplayId()
);
result.put(
"isPresentation",
(display.getFlags() & Display.FLAG_PRESENTATION) == Display.FLAG_PRESENTATION
);
return result;
}
private void closePresentation() {
if (presentation == null) return;
presentation.setOnDismissListener(null);
presentation.dismiss();
presentation = null;
}
private final class DisplayLaunchPlan {
private final Display targetDisplay;
private final boolean targetIsTopDisplay;
private final boolean currentIsTopDisplay;
DisplayLaunchPlan(
Display targetDisplay,
boolean targetIsTopDisplay,
boolean currentIsTopDisplay
) {
this.targetDisplay = targetDisplay;
this.targetIsTopDisplay = targetIsTopDisplay;
this.currentIsTopDisplay = currentIsTopDisplay;
}
}
private final class TopDisplayPresentation extends Presentation {
private final String initialUrl;
TopDisplayPresentation(Context context, Display display, String initialUrl) {
super(context, display);
this.initialUrl = initialUrl;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setBackgroundDrawableResource(android.R.color.black);
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
);
FrameLayout container = new FrameLayout(getContext());
container.setBackgroundColor(Color.BLACK);
WebView webView = new WebView(getContext());
configureWebView(webView);
container.addView(
webView,
new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
);
setContentView(container);
webView.loadUrl(initialUrl);
}
}
private void configureWebView(WebView webView) {
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);
settings.setDatabaseEnabled(true);
settings.setMediaPlaybackRequiresUserGesture(false);
settings.setAllowFileAccess(true);
settings.setAllowContentAccess(true);
webView.setBackgroundColor(Color.BLACK);
webView.setWebViewClient(new WebViewClient() {
@Override
public WebResourceResponse shouldInterceptRequest(
WebView view,
WebResourceRequest request
) {
return bridge.getLocalServer().shouldInterceptRequest(request);
}
});
}
}