Initial I Want to Heal app
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
package com.warren.iwanttoheal;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import com.getcapacitor.BridgeActivity;
|
||||
|
||||
public abstract class ControllerBridgeActivity extends BridgeActivity {
|
||||
|
||||
public static final String EXTRA_INITIAL_URL = "com.warren.iwanttoheal.INITIAL_URL";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
loadIntentUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
setIntent(intent);
|
||||
loadIntentUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus) enableImmersiveMode();
|
||||
}
|
||||
|
||||
private void loadIntentUrl() {
|
||||
if (bridge == null || getIntent() == null) return;
|
||||
String initialUrl = getIntent().getStringExtra(EXTRA_INITIAL_URL);
|
||||
if (initialUrl == null || initialUrl.isEmpty()) return;
|
||||
bridge.getWebView().post(() -> bridge.getWebView().loadUrl(initialUrl));
|
||||
}
|
||||
|
||||
private void enableImmersiveMode() {
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
String token = controllerToken(event.getKeyCode());
|
||||
if (token == null || bridge == null) return super.dispatchKeyEvent(event);
|
||||
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
boolean repeat = event.getRepeatCount() > 0;
|
||||
String script =
|
||||
"window.dispatchEvent(new CustomEvent('ashen-halls-native-controller',"
|
||||
+ "{detail:{token:'" + token + "',repeat:" + repeat + "}}));";
|
||||
bridge.getWebView().post(
|
||||
() -> bridge.getWebView().evaluateJavascript(script, null)
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String controllerToken(int keyCode) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_BUTTON_A:
|
||||
case KeyEvent.KEYCODE_ENTER:
|
||||
return "Button0";
|
||||
case KeyEvent.KEYCODE_BUTTON_B:
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
return "Button1";
|
||||
case KeyEvent.KEYCODE_BUTTON_X:
|
||||
return "Button2";
|
||||
case KeyEvent.KEYCODE_BUTTON_Y:
|
||||
return "Button3";
|
||||
case KeyEvent.KEYCODE_BUTTON_L1:
|
||||
return "Button4";
|
||||
case KeyEvent.KEYCODE_BUTTON_R1:
|
||||
return "Button5";
|
||||
case KeyEvent.KEYCODE_BUTTON_L2:
|
||||
return "Button6";
|
||||
case KeyEvent.KEYCODE_BUTTON_R2:
|
||||
return "Button7";
|
||||
case KeyEvent.KEYCODE_BUTTON_SELECT:
|
||||
return "Button8";
|
||||
case KeyEvent.KEYCODE_BUTTON_START:
|
||||
return "Button9";
|
||||
case KeyEvent.KEYCODE_BUTTON_THUMBL:
|
||||
return "Button10";
|
||||
case KeyEvent.KEYCODE_BUTTON_THUMBR:
|
||||
return "Button11";
|
||||
case KeyEvent.KEYCODE_DPAD_UP:
|
||||
return "Button12";
|
||||
case KeyEvent.KEYCODE_DPAD_DOWN:
|
||||
return "Button13";
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||
return "Button14";
|
||||
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
||||
return "Button15";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
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 controlsUrl = gameUrl + "/?display=bottom";
|
||||
String targetUrl = launchPlan.targetIsTopDisplay ? gameUrl : controlsUrl;
|
||||
String currentUrl = launchPlan.currentIsTopDisplay ? gameUrl : 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.warren.iwanttoheal;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class GameActivity extends ControllerBridgeActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
registerPlugin(DualScreenPlugin.class);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.warren.iwanttoheal;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class MainActivity extends ControllerBridgeActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
registerPlugin(DualScreenPlugin.class);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user