From cd9275ee3777223d3aac5f22255fdb03741b6df8 Mon Sep 17 00:00:00 2001 From: Christian Beier Date: Wed, 1 Nov 2023 12:09:55 +0100 Subject: [PATCH] Android: split VNCConn connection callback into int && disconnect callbacks re #226 actually to be in line with the desktop VNCConn. --- .../dontmind/multivnc/VNCConn.java | 37 +++-- .../multivnc/ui/VncCanvasActivity.java | 135 +++++++++--------- 2 files changed, 95 insertions(+), 77 deletions(-) diff --git a/android/app/src/main/java/com/coboltforge/dontmind/multivnc/VNCConn.java b/android/app/src/main/java/com/coboltforge/dontmind/multivnc/VNCConn.java index cfe86338..a9332732 100644 --- a/android/app/src/main/java/com/coboltforge/dontmind/multivnc/VNCConn.java +++ b/android/app/src/main/java/com/coboltforge/dontmind/multivnc/VNCConn.java @@ -25,11 +25,16 @@ public class VNCConn { - public interface OnConnectionEventListener { + + public interface OnInitListener { /** - * Fired when a connection was successfully made. + * Fired on connection init. + * @param error Null on successful connection init (i.e. connected), non-null on failure. */ - void onConnected(); + void onInit(Throwable error); + } + + public interface OnDisconnectListener { /** * Fired on disconnect, either orderly or with error * @param err Null on orderly disconnect, non-null on failure. @@ -166,10 +171,12 @@ private class ClientCutText { private class ServerToClientThread extends Thread { - private final OnConnectionEventListener connectionEventCallback; + private final OnInitListener initCallback; + private final OnDisconnectListener disconnectCallback; - public ServerToClientThread(OnConnectionEventListener connectionEventCallback) { - this.connectionEventCallback = connectionEventCallback; + public ServerToClientThread(OnInitListener initCallback, OnDisconnectListener disconnectCallback) { + this.initCallback = initCallback; + this.disconnectCallback = disconnectCallback; } @@ -222,7 +229,7 @@ public void run() { connSettings.sshPrivkeyPassword )) { unlockFramebuffer(); - throw new Exception(); //TODO add some error reoprting here + throw new Exception(); //TODO add some error reoprting here, e.g. if auth fail or not } colorModel = pendingColorModel; unlockFramebuffer(); @@ -235,7 +242,7 @@ public void run() { outputThread = new ClientToServerThread(); outputThread.start(); - connectionEventCallback.onConnected(); + initCallback.onInit(null); // main loop while (maintainConnection) { @@ -258,7 +265,12 @@ public void run() { rfbShutdown(); unlockFramebuffer(); - connectionEventCallback.onDisconnected(maybeError); + if(outputThread == null) { + // if outputThread is still unset, we were in init + initCallback.onInit(maybeError); + } else { + disconnectCallback.onDisconnected(maybeError); + } if(Utils.DEBUG()) Log.d(TAG, "ServerToClientThread done!"); } @@ -409,16 +421,17 @@ protected void finalize() { /** * Initialise a VNC connection * @param bean Connection settings - * @param connectionEventCallback Callback that's called after connection is set up + * @param initCallback Callback that's called after init has succeeded or failed + * @param disconnectCallback Callback that's called when an established connection disconnects */ - public void init(ConnectionBean bean, OnConnectionEventListener connectionEventCallback) { + public void init(ConnectionBean bean, OnInitListener initCallback, OnDisconnectListener disconnectCallback) { Log.d(TAG, "initializing"); connSettings = bean; this.pendingColorModel = COLORMODEL.valueOf(bean.colorModel); - inputThread = new ServerToClientThread(connectionEventCallback); + inputThread = new ServerToClientThread(initCallback, disconnectCallback); inputThread.start(); } diff --git a/android/app/src/main/java/com/coboltforge/dontmind/multivnc/ui/VncCanvasActivity.java b/android/app/src/main/java/com/coboltforge/dontmind/multivnc/ui/VncCanvasActivity.java index 8cfa7223..d7af3878 100644 --- a/android/app/src/main/java/com/coboltforge/dontmind/multivnc/ui/VncCanvasActivity.java +++ b/android/app/src/main/java/com/coboltforge/dontmind/multivnc/ui/VncCanvasActivity.java @@ -261,80 +261,85 @@ public void onSystemUiVisibilityChange(int visibility) { pd.show(); firstFrameWaitDialog = pd; vncCanvas.initializeVncCanvas(pd, inputHandler, conn); // add conn to canvas - conn.init(connection, new VNCConn.OnConnectionEventListener() { - @Override - public void onConnected() { - runOnUiThread(() -> { - - if (Build.VERSION.SDK_INT < 33) { - /* - * Show all the on-connect UI directly - */ + conn.init(connection, + // onInit + initError -> runOnUiThread(() -> { + if(initError == null) { + // init success! + if (Build.VERSION.SDK_INT < 33) { + /* + * Show all the on-connect UI directly + */ + showHelpDialog(); + VNCConnService.register(VncCanvasActivity.this, conn); + vncCanvas.showConnectionInfo(); + } else { + /* + permission asking according to the book https://developer.android.com/training/permissions/requesting + */ + // the permission asking logic as per the book https://developer.android.com/training/permissions/requesting + if (checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) { showHelpDialog(); VNCConnService.register(VncCanvasActivity.this, conn); vncCanvas.showConnectionInfo(); + } else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) { + new AlertDialog.Builder(VncCanvasActivity.this) + .setCancelable(false) + .setTitle(R.string.notification_title) + .setMessage(R.string.notification_msg) + .setPositiveButton(android.R.string.ok, (dialog, which) -> { + requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS); + }) + .setCancelable(false) + .show(); } else { - /* - permission asking according to the book https://developer.android.com/training/permissions/requesting - */ - // the permission asking logic as per the book https://developer.android.com/training/permissions/requesting - if (checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) { - showHelpDialog(); - VNCConnService.register(VncCanvasActivity.this, conn); - vncCanvas.showConnectionInfo(); - } else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) { - new AlertDialog.Builder(VncCanvasActivity.this) - .setCancelable(false) - .setTitle(R.string.notification_title) - .setMessage(R.string.notification_msg) - .setPositiveButton(android.R.string.ok, (dialog, which) -> { - requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS); - }) - .setCancelable(false) - .show(); - } else { - // You can directly ask for the permission. - // The registered ActivityResultCallback gets the result of this request. - requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS); - } + // You can directly ask for the permission. + // The registered ActivityResultCallback gets the result of this request. + requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS); } + } - setTitle(conn.getDesktopName()); - // actually set scale type with this, otherwise no scaling - setModes(); - firstFrameWaitDialog.setMessage("Downloading first frame.\nPlease wait..."); - // center pointer - vncCanvas.mouseX = conn.getFramebufferWidth() / 2; - vncCanvas.mouseY = conn.getFramebufferHeight() / 2; - }); + setTitle(conn.getDesktopName()); + // actually set scale type with this, otherwise no scaling + setModes(); + firstFrameWaitDialog.setMessage("Downloading first frame.\nPlease wait..."); + // center pointer + vncCanvas.mouseX = conn.getFramebufferWidth() / 2; + vncCanvas.mouseY = conn.getFramebufferHeight() / 2; + } else { + // init fail + try { + firstFrameWaitDialog.dismiss(); + } catch (Exception ignored) { + } + String error = "VNC connection setup failed!"; + if (initError.getMessage() != null && (initError.getMessage().contains("authentication"))) { + error = "VNC authentication failed!"; + } + final String error_ = error + "
" + ((initError.getLocalizedMessage() != null) ? initError.getLocalizedMessage() : ""); + Utils.showFatalErrorMessage(VncCanvasActivity.this, error_); + } + }), + // onDisconnect + disconnectError -> runOnUiThread(() -> { + try { + // Ensure we dismiss the progress dialog + // before we fatal error finish + if (firstFrameWaitDialog.isShowing()) + firstFrameWaitDialog.dismiss(); + } catch (Exception e) { + //unused } - @Override - public void onDisconnected(Throwable err) { - runOnUiThread(() -> { - try { - // Ensure we dismiss the progress dialog - // before we fatal error finish - if (firstFrameWaitDialog.isShowing()) - firstFrameWaitDialog.dismiss(); - } catch (Exception e) { - //unused - } - - if(err != null) { - String error = "VNC connection failed!"; - if (err.getMessage() != null && (err.getMessage().indexOf("authentication") > -1)) { - error = "VNC authentication failed!"; - } - final String error_ = error + "
" + ((err.getLocalizedMessage() != null) ? err.getLocalizedMessage() : ""); - Utils.showFatalErrorMessage(VncCanvasActivity.this, error_); - } - - // deregister connection - VNCConnService.deregister(VncCanvasActivity.this, conn); - }); + if(disconnectError != null) { + String error = "VNC connection failed!"; + final String error_ = error + "
" + ((disconnectError.getLocalizedMessage() != null) ? disconnectError.getLocalizedMessage() : ""); + Utils.showFatalErrorMessage(VncCanvasActivity.this, error_); } - }); + + // deregister connection + VNCConnService.deregister(VncCanvasActivity.this, conn); + })); zoomer.setOnZoomInClickListener(new View.OnClickListener() {