33 private static final String TAG =
"LibFreeRDP";
35 private static boolean mHasH264 =
false;
36 private static boolean mHasCameraRedirection =
false;
38 private static final LongSparseArray<Boolean> mInstanceState =
new LongSparseArray<>();
40 public static final long VERIFY_CERT_FLAG_NONE = 0x00;
41 public static final long VERIFY_CERT_FLAG_LEGACY = 0x02;
42 public static final long VERIFY_CERT_FLAG_REDIRECT = 0x10;
43 public static final long VERIFY_CERT_FLAG_GATEWAY = 0x20;
44 public static final long VERIFY_CERT_FLAG_CHANGED = 0x40;
45 public static final long VERIFY_CERT_FLAG_MISMATCH = 0x80;
46 public static final long VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1 = 0x100;
47 public static final long VERIFY_CERT_FLAG_FP_IS_PEM = 0x200;
50 public static final int EXPERIMENTAL_REMOTEAPP = 0;
51 public static final int EXPERIMENTAL_CAMERA = 1;
53 private static boolean tryLoad(String[] libraries)
55 boolean success =
false;
56 final String LD_PATH = System.getProperty(
"java.library.path");
57 for (String lib : libraries)
61 Log.v(TAG,
"Trying to load library " + lib +
" from LD_PATH: " + LD_PATH);
62 System.loadLibrary(lib);
65 catch (UnsatisfiedLinkError e)
67 Log.e(TAG,
"Failed to load library " + lib +
": " + e);
76 private static boolean tryLoad(String library)
78 return tryLoad(
new String[] { library });
85 System.loadLibrary(
"freerdp-android");
88 String version = freerdp_get_jni_version();
89 String[] versions = version.split(
"[\\.-]");
90 if (versions.length > 0)
92 System.loadLibrary(
"freerdp-client" + versions[0]);
93 System.loadLibrary(
"freerdp" + versions[0]);
94 System.loadLibrary(
"winpr" + versions[0]);
96 Pattern pattern = Pattern.compile(
"^(\\d+)\\.(\\d+)\\.(\\d+).*");
97 Matcher matcher = pattern.matcher(version);
98 if (!matcher.matches() || (matcher.groupCount() < 3))
99 throw new RuntimeException(
"APK broken: native library version " + version +
100 " does not meet requirements!");
101 int major = Integer.parseInt(Objects.requireNonNull(matcher.group(1)));
102 int minor = Integer.parseInt(Objects.requireNonNull(matcher.group(2)));
103 int patch = Integer.parseInt(Objects.requireNonNull(matcher.group(3)));
106 mHasH264 = freerdp_has_h264();
108 mHasH264 = freerdp_has_h264();
109 else if ((minor == 5) && (patch >= 1))
110 mHasH264 = freerdp_has_h264();
112 throw new RuntimeException(
"APK broken: native library version " + version +
113 " does not meet requirements!");
114 mHasCameraRedirection = freerdp_has_camera_redirection();
115 Log.i(TAG,
"Successfully loaded native library. H264 is " +
116 (mHasH264 ?
"supported" :
"not available") +
", camera redirection is " +
117 (mHasCameraRedirection ?
"supported" :
"not available"));
119 catch (UnsatisfiedLinkError e)
121 Log.e(TAG,
"Failed to load library: " + e);
126 public static boolean hasH264Support()
131 public static boolean hasCameraRedirectionSupport()
133 return mHasCameraRedirection;
136 private static native
boolean freerdp_has_h264();
138 private static native
boolean freerdp_has_camera_redirection();
140 private static native String freerdp_get_jni_version();
142 private static native String freerdp_get_version();
144 private static native String freerdp_get_build_revision();
146 private static native String freerdp_get_build_config();
148 private static native
long freerdp_new(Context context);
150 private static native
void freerdp_free(
long inst);
152 private static native
boolean freerdp_parse_arguments(
long inst, String[] args);
154 private static native
boolean freerdp_connect(
long inst);
156 private static native
boolean freerdp_disconnect(
long inst);
158 private static native
boolean freerdp_update_graphics(
long inst, Bitmap bitmap,
int x,
int y,
159 int width,
int height);
161 private static native
boolean freerdp_send_cursor_event(
long inst,
int x,
int y,
int flags);
163 private static native
boolean freerdp_send_key_event(
long inst,
int keycode,
boolean down);
165 private static native
boolean freerdp_send_unicodekey_event(
long inst,
int keycode,
168 private static native
boolean freerdp_is_unicode_input_supported(
long inst);
170 private static native
boolean freerdp_send_clipboard_data(
long inst, String data);
172 private static native
boolean freerdp_send_clipboard_image_data(
long inst,
byte[] data,
175 private static native
boolean freerdp_send_monitor_layout(
long inst,
int width,
int height);
177 private static native String freerdp_get_last_error_string(
long inst);
184 public static long newInstance(Context context)
186 return freerdp_new(context);
189 public static void freeInstance(
long inst)
191 synchronized (mInstanceState)
193 if (mInstanceState.get(inst,
false))
195 freerdp_disconnect(inst);
197 while (mInstanceState.get(inst,
false))
201 mInstanceState.wait();
203 catch (InterruptedException e)
205 throw new RuntimeException();
212 public static boolean connect(
long inst)
214 synchronized (mInstanceState)
216 if (mInstanceState.get(inst,
false))
218 throw new RuntimeException(
"instance already connected");
221 return freerdp_connect(inst);
224 public static boolean disconnect(
long inst)
226 synchronized (mInstanceState)
228 if (mInstanceState.get(inst,
false))
230 return freerdp_disconnect(inst);
236 public static boolean cancelConnection(
long inst)
238 return freerdp_disconnect(inst);
241 private static String addFlag(String name,
boolean enabled)
250 public static boolean setConnectionInfo(Context context,
long inst, BookmarkBase bookmark)
252 BookmarkBase.ScreenSettings screenSettings = bookmark.getActiveScreenSettings();
253 BookmarkBase.AdvancedSettings advanced = bookmark.getAdvancedSettings();
254 BookmarkBase.DebugSettings debug = bookmark.getDebugSettings();
257 ArrayList<String> args =
new ArrayList<>();
262 final String clientName = ApplicationSettingsActivity.getClientName(context);
263 if (!clientName.isEmpty())
265 args.add(
"/client-hostname:" + clientName);
267 String certName =
"";
268 if (bookmark.getType() != BookmarkBase.TYPE_MANUAL)
273 int port = bookmark.getPort();
274 String hostname = bookmark.getHostname();
276 args.add(
"/v:" + hostname);
277 args.add(
"/port:" + port);
279 final int level = advanced.getTlsSecLevel();
280 List<String> tls =
new ArrayList<>();
284 tls.add(
"seclevel:" + level);
287 final int tlsMinLevel = advanced.getTlsMinLevel();
288 if (tlsMinLevel >= 0)
290 tls.add(
"enforce:" + tlsMinLevel);
295 StringBuilder sb =
new StringBuilder();
304 args.add(
"/tls:" + sb);
307 arg = bookmark.getUsername();
310 args.add(
"/u:" + arg);
312 arg = bookmark.getDomain();
315 args.add(
"/d:" + arg);
317 arg = bookmark.getPassword();
320 args.add(
"/p:" + arg);
323 args.add(String.format(java.util.Locale.US,
"/size:%dx%d", screenSettings.getWidth(),
324 screenSettings.getHeight()));
325 args.add(
"/bpp:" + screenSettings.getColors());
327 if (screenSettings.isCustomScale())
329 args.add(
"/scale-desktop:" + screenSettings.getScaleDesktop());
330 args.add(
"/scale-device:" + screenSettings.getScaleDevice());
334 args.add(
"/scale:" + screenSettings.getScalePreset());
337 if (advanced.getConsoleMode())
342 if (advanced.getVmConnectMode())
344 String guid = advanced.getVmConnectGuid();
346 args.add(
"/vmconnect:" + guid);
348 args.add(
"/vmconnect");
351 switch (advanced.getSecurity())
354 args.add(
"/sec:nla");
357 args.add(
"/sec:tls");
360 args.add(
"/sec:rdp");
366 if (!certName.isEmpty())
368 args.add(
"/cert-name:" + certName);
371 BookmarkBase.PerformanceFlags flags = bookmark.getActivePerformanceFlags();
372 if (flags.getRemoteFX())
375 args.add(
"/network:auto");
381 args.add(
"/network:auto");
384 if (flags.getH264() && mHasH264)
386 args.add(
"/gfx:AVC444");
387 args.add(
"/network:auto");
390 args.add(addFlag(
"wallpaper", flags.getWallpaper()));
391 args.add(addFlag(
"window-drag", flags.getFullWindowDrag()));
392 args.add(addFlag(
"menu-anims", flags.getMenuAnimations()));
393 args.add(addFlag(
"themes", flags.getTheming()));
394 args.add(addFlag(
"fonts", flags.getFontSmoothing()));
395 args.add(addFlag(
"aero", flags.getDesktopComposition()));
397 if (!advanced.getRemoteProgram().isEmpty())
399 args.add(
"/app:program:" + advanced.getRemoteProgram());
400 if (!advanced.getWorkDir().isEmpty())
401 args.add(
"/app:workdir:" + advanced.getWorkDir());
405 if (!advanced.getAlternateShell().isEmpty())
406 args.add(
"/shell:" + advanced.getAlternateShell());
407 if (!advanced.getWorkDir().isEmpty())
408 args.add(
"/shell-dir:" + advanced.getWorkDir());
411 args.add(addFlag(
"async-channels", debug.getAsyncChannel()));
412 args.add(addFlag(
"async-update", debug.getAsyncUpdate()));
414 if (advanced.getRedirectSDCard())
416 String path = android.os.Environment.getExternalStorageDirectory().getPath();
417 args.add(
"/drive:sdcard," + path);
420 String info = advanced.getLoadBalanceInfo();
423 args.add(
"/load-balance-info:" + info);
425 args.add(
"/clipboard");
428 if (advanced.getRedirectPrinter())
429 args.add(
"/printer:aFreeRDP Print,Microsoft Print to PDF,default");
432 if (bookmark.getType() == BookmarkBase.TYPE_MANUAL && bookmark.getEnableGatewaySettings())
434 BookmarkBase.GatewaySettings gateway = bookmark.getGatewaySettings();
436 StringBuilder carg =
new StringBuilder();
437 carg.append(String.format(java.util.Locale.US,
"/gateway:g:%s:%d",
438 gateway.getHostname(), gateway.getPort()));
440 arg = gateway.getUsername();
443 carg.append(
",u:" + arg);
445 arg = gateway.getDomain();
448 carg.append(
",d:" + arg);
450 arg = gateway.getPassword();
453 carg.append(
",p:" + arg);
455 args.add(carg.toString());
461 args.add(
"/audio-mode:" + advanced.getRedirectSound());
462 if (advanced.getRedirectSound() == 0)
467 if (advanced.getRedirectMicrophone())
469 args.add(
"/microphone");
472 if (advanced.getRedirectCamera() && mHasCameraRedirection)
474 args.add(
"/dvc:rdpecam");
477 args.add(
"/kbd:unicode:on");
478 args.add(
"/cert:ignore");
479 args.add(
"/log-level:" + debug.getDebugLevel());
480 String[] arrayArgs = args.toArray(
new String[0]);
481 return freerdp_parse_arguments(inst, arrayArgs);
484 public static boolean setConnectionInfo(Context context,
long inst, Uri openUri)
486 ArrayList<String> args =
new ArrayList<>();
495 final String clientName = ApplicationSettingsActivity.getClientName(context);
496 if (!clientName.isEmpty())
498 args.add(
"/client-hostname:" + clientName);
502 String hostname = openUri.getHost();
503 int port = openUri.getPort();
504 if (hostname !=
null)
506 hostname = hostname + ((port == -1) ?
"" : (
":" + port));
507 args.add(
"/v:" + hostname);
510 String user = openUri.getUserInfo();
513 args.add(
"/u:" + user);
516 for (String key : openUri.getQueryParameterNames())
518 String value = openUri.getQueryParameter(key);
526 else if (value.equals(
"-") || value.equals(
"+"))
530 args.add(value + key);
536 if (key.equals(
"drive") && value.equals(
"sdcard"))
539 String path = android.os.Environment.getExternalStorageDirectory().getPath();
540 value =
"sdcard," + path;
543 args.add(
"/" + key +
":" + value);
547 String[] arrayArgs = args.toArray(
new String[0]);
548 return freerdp_parse_arguments(inst, arrayArgs);
551 public static boolean updateGraphics(
long inst, Bitmap bitmap,
int x,
int y,
int width,
554 return freerdp_update_graphics(inst, bitmap, x, y, width, height);
557 public static boolean sendCursorEvent(
long inst,
int x,
int y,
int flags)
559 return freerdp_send_cursor_event(inst, x, y, flags);
562 public static boolean sendKeyEvent(
long inst,
int keycode,
boolean down)
564 return freerdp_send_key_event(inst, keycode, down);
567 public static boolean sendUnicodeKeyEvent(
long inst,
int keycode,
boolean down)
569 return freerdp_send_unicodekey_event(inst, keycode, down);
572 public static boolean isUnicodeInputSupported(
long inst)
574 return freerdp_is_unicode_input_supported(inst);
577 public static boolean sendClipboardData(
long inst, String data)
579 return freerdp_send_clipboard_data(inst, data);
582 public static boolean sendClipboardImageData(
long inst,
byte[] data, String mimeType)
584 return freerdp_send_clipboard_image_data(inst, data, mimeType);
587 public static boolean sendMonitorLayout(
long inst,
int width,
int height)
589 return freerdp_send_monitor_layout(inst, width, height);
592 private static void OnConnectionSuccess(
long inst)
594 if (listener !=
null)
595 listener.OnConnectionSuccess(inst);
596 synchronized (mInstanceState)
598 mInstanceState.append(inst,
true);
599 mInstanceState.notifyAll();
603 private static void OnConnectionFailure(
long inst)
605 if (listener !=
null)
606 listener.OnConnectionFailure(inst);
607 synchronized (mInstanceState)
609 mInstanceState.remove(inst);
610 mInstanceState.notifyAll();
614 private static void OnPreConnect(
long inst)
616 if (listener !=
null)
617 listener.OnPreConnect(inst);
620 private static void OnDisconnecting(
long inst)
622 if (listener !=
null)
623 listener.OnDisconnecting(inst);
626 private static void OnDisconnected(
long inst)
628 if (listener !=
null)
629 listener.OnDisconnected(inst);
630 synchronized (mInstanceState)
632 mInstanceState.remove(inst);
633 mInstanceState.notifyAll();
637 private static void OnSettingsChanged(
long inst,
int width,
int height,
int bpp)
639 SessionState s = GlobalApp.getSession(inst);
643 if (uiEventListener !=
null)
644 uiEventListener.OnSettingsChanged(width, height, bpp);
647 private static boolean OnAuthenticate(
long inst, StringBuilder username, StringBuilder domain,
648 StringBuilder password)
650 SessionState s = GlobalApp.getSession(inst);
654 if (uiEventListener !=
null)
655 return uiEventListener.OnAuthenticate(username, domain, password);
659 private static boolean OnGatewayAuthenticate(
long inst, StringBuilder username,
660 StringBuilder domain, StringBuilder password)
662 SessionState s = GlobalApp.getSession(inst);
666 if (uiEventListener !=
null)
667 return uiEventListener.OnGatewayAuthenticate(username, domain, password);
671 private static int OnVerifyCertificateEx(
long inst, String host,
long port, String commonName,
672 String subject, String issuer, String fingerprint,
675 SessionState s = GlobalApp.getSession(inst);
679 if (uiEventListener !=
null)
680 return uiEventListener.OnVerifiyCertificateEx(host, port, commonName, subject, issuer,
685 private static int OnVerifyChangedCertificateEx(
long inst, String host,
long port,
686 String commonName, String subject,
687 String issuer, String fingerprint,
688 String oldSubject, String oldIssuer,
689 String oldFingerprint,
long flags)
691 SessionState s = GlobalApp.getSession(inst);
695 if (uiEventListener !=
null)
696 return uiEventListener.OnVerifyChangedCertificateEx(host, port, commonName, subject,
697 issuer, fingerprint, oldSubject,
698 oldIssuer, oldFingerprint, flags);
702 private static boolean OnExperimentalFeature(
long inst,
int feature)
704 SessionState s = GlobalApp.getSession(inst);
708 if (uiEventListener ==
null)
710 return uiEventListener.OnExperimentalFeature(feature);
713 private static void OnGraphicsUpdate(
long inst,
int x,
int y,
int width,
int height)
715 SessionState s = GlobalApp.getSession(inst);
719 if (uiEventListener !=
null)
720 uiEventListener.OnGraphicsUpdate(x, y, width, height);
723 private static void OnGraphicsResize(
long inst,
int width,
int height,
int bpp)
725 SessionState s = GlobalApp.getSession(inst);
729 if (uiEventListener !=
null)
730 uiEventListener.OnGraphicsResize(width, height, bpp);
733 private static void OnRemoteClipboardChanged(
long inst, String data)
735 SessionState s = GlobalApp.getSession(inst);
739 if (uiEventListener !=
null)
740 uiEventListener.OnRemoteClipboardChanged(data);
743 private static void OnRemoteClipboardImageChanged(
long inst,
byte[] data)
745 SessionState s = GlobalApp.getSession(inst);
749 if (uiEventListener !=
null)
750 uiEventListener.OnRemoteClipboardImageChanged(data);
753 private static void OnPointerSet(
long inst,
int[] pixels,
int width,
int height,
int hotX,
756 SessionState s = GlobalApp.getSession(inst);
760 if (uiEventListener !=
null)
761 uiEventListener.OnPointerSet(pixels, width, height, hotX, hotY);
764 private static void OnPointerSetNull(
long inst)
766 SessionState s = GlobalApp.getSession(inst);
770 if (uiEventListener !=
null)
771 uiEventListener.OnPointerSetNull();
774 private static void OnPointerSetDefault(
long inst)
776 SessionState s = GlobalApp.getSession(inst);
780 if (uiEventListener !=
null)
781 uiEventListener.OnPointerSetDefault();
784 private static void OnRailWindowUpdate(
long inst,
long windowId,
int width,
int height,
787 SessionState s = GlobalApp.getSession(inst);
791 if (uiEventListener !=
null)
792 uiEventListener.OnRailWindowUpdate(windowId, width, height, pixels);
795 private static void OnRailWindowMove(
long inst,
long windowId,
int x,
int y,
int w,
int h)
797 SessionState s = GlobalApp.getSession(inst);
801 if (uiEventListener !=
null)
802 uiEventListener.OnRailWindowMove(windowId, x, y, w, h);
805 private static void OnRailWindowHide(
long inst,
long windowId)
807 SessionState s = GlobalApp.getSession(inst);
811 if (uiEventListener !=
null)
812 uiEventListener.OnRailWindowHide(windowId);
815 private static void OnRailWindowDestroy(
long inst,
long windowId)
817 SessionState s = GlobalApp.getSession(inst);
821 if (uiEventListener !=
null)
822 uiEventListener.OnRailWindowDestroy(windowId);
825 private static void OnRailSessionEnd(
long inst)
827 SessionState s = GlobalApp.getSession(inst);
831 if (uiEventListener !=
null)
832 uiEventListener.OnRailSessionEnd();
835 private static void OnRailMonitoredDesktop(
long inst,
long[] windowIds,
long activeWindowId)
837 SessionState s = GlobalApp.getSession(inst);
841 if (uiEventListener !=
null)
842 uiEventListener.OnRailMonitoredDesktop(windowIds, activeWindowId);
845 public static String getVersion()
847 return freerdp_get_version();
852 void OnPreConnect(
long instance);
854 void OnConnectionSuccess(
long instance);
856 void OnConnectionFailure(
long instance);
858 void OnDisconnecting(
long instance);
860 void OnDisconnected(
long instance);
865 void OnSettingsChanged(
int width,
int height,
int bpp);
867 boolean OnAuthenticate(StringBuilder username, StringBuilder domain,
868 StringBuilder password);
870 boolean OnGatewayAuthenticate(StringBuilder username, StringBuilder domain,
871 StringBuilder password);
873 int OnVerifiyCertificateEx(String host,
long port, String commonName, String subject, String issuer,
874 String fingerprint,
long flags);
876 int OnVerifyChangedCertificateEx(String host,
long port, String commonName, String subject, String issuer,
877 String fingerprint, String oldSubject, String oldIssuer,
878 String oldFingerprint,
long flags);
880 boolean OnExperimentalFeature(
int feature);
882 void OnGraphicsUpdate(
int x,
int y,
int width,
int height);
884 void OnGraphicsResize(
int width,
int height,
int bpp);
886 void OnRemoteClipboardChanged(String data);
888 void OnRemoteClipboardImageChanged(
byte[] data);
890 void OnPointerSet(
int[] pixels,
int width,
int height,
int hotX,
int hotY);
892 void OnPointerSetNull();
894 void OnPointerSetDefault();
896 void OnRailWindowUpdate(
long windowId,
int width,
int height,
int[] pixels);
898 void OnRailWindowMove(
long windowId,
int x,
int y,
int w,
int h);
900 void OnRailWindowHide(
long windowId);
902 void OnRailWindowDestroy(
long windowId);
904 void OnRailSessionEnd();
906 void OnRailMonitoredDesktop(
long[] windowIds,
long activeWindowId);