33 private static final String TAG =
"LibFreeRDP";
35 private static boolean mHasH264 =
false;
37 private static final LongSparseArray<Boolean> mInstanceState =
new LongSparseArray<>();
39 public static final long VERIFY_CERT_FLAG_NONE = 0x00;
40 public static final long VERIFY_CERT_FLAG_LEGACY = 0x02;
41 public static final long VERIFY_CERT_FLAG_REDIRECT = 0x10;
42 public static final long VERIFY_CERT_FLAG_GATEWAY = 0x20;
43 public static final long VERIFY_CERT_FLAG_CHANGED = 0x40;
44 public static final long VERIFY_CERT_FLAG_MISMATCH = 0x80;
45 public static final long VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1 = 0x100;
46 public static final long VERIFY_CERT_FLAG_FP_IS_PEM = 0x200;
48 private static boolean tryLoad(String[] libraries)
50 boolean success =
false;
51 final String LD_PATH = System.getProperty(
"java.library.path");
52 for (String lib : libraries)
56 Log.v(TAG,
"Trying to load library " + lib +
" from LD_PATH: " + LD_PATH);
57 System.loadLibrary(lib);
60 catch (UnsatisfiedLinkError e)
62 Log.e(TAG,
"Failed to load library " + lib +
": " + e);
71 private static boolean tryLoad(String library)
73 return tryLoad(
new String[] { library });
80 System.loadLibrary(
"freerdp-android");
83 String version = freerdp_get_jni_version();
84 String[] versions = version.split(
"[\\.-]");
85 if (versions.length > 0)
87 System.loadLibrary(
"freerdp-client" + versions[0]);
88 System.loadLibrary(
"freerdp" + versions[0]);
89 System.loadLibrary(
"winpr" + versions[0]);
91 Pattern pattern = Pattern.compile(
"^(\\d+)\\.(\\d+)\\.(\\d+).*");
92 Matcher matcher = pattern.matcher(version);
93 if (!matcher.matches() || (matcher.groupCount() < 3))
94 throw new RuntimeException(
"APK broken: native library version " + version +
95 " does not meet requirements!");
96 int major = Integer.parseInt(Objects.requireNonNull(matcher.group(1)));
97 int minor = Integer.parseInt(Objects.requireNonNull(matcher.group(2)));
98 int patch = Integer.parseInt(Objects.requireNonNull(matcher.group(3)));
101 mHasH264 = freerdp_has_h264();
103 mHasH264 = freerdp_has_h264();
104 else if ((minor == 5) && (patch >= 1))
105 mHasH264 = freerdp_has_h264();
107 throw new RuntimeException(
"APK broken: native library version " + version +
108 " does not meet requirements!");
109 Log.i(TAG,
"Successfully loaded native library. H264 is " +
110 (mHasH264 ?
"supported" :
"not available"));
112 catch (UnsatisfiedLinkError e)
114 Log.e(TAG,
"Failed to load library: " + e);
119 public static boolean hasH264Support()
124 private static native
boolean freerdp_has_h264();
126 private static native String freerdp_get_jni_version();
128 private static native String freerdp_get_version();
130 private static native String freerdp_get_build_revision();
132 private static native String freerdp_get_build_config();
134 private static native
long freerdp_new(Context context);
136 private static native
void freerdp_free(
long inst);
138 private static native
boolean freerdp_parse_arguments(
long inst, String[] args);
140 private static native
boolean freerdp_connect(
long inst);
142 private static native
boolean freerdp_disconnect(
long inst);
144 private static native
boolean freerdp_update_graphics(
long inst, Bitmap bitmap,
int x,
int y,
145 int width,
int height);
147 private static native
boolean freerdp_send_cursor_event(
long inst,
int x,
int y,
int flags);
149 private static native
boolean freerdp_send_key_event(
long inst,
int keycode,
boolean down);
151 private static native
boolean freerdp_send_unicodekey_event(
long inst,
int keycode,
154 private static native
boolean freerdp_send_clipboard_data(
long inst, String data);
156 private static native String freerdp_get_last_error_string(
long inst);
163 public static long newInstance(Context context)
165 return freerdp_new(context);
168 public static void freeInstance(
long inst)
170 synchronized (mInstanceState)
172 if (mInstanceState.get(inst,
false))
174 freerdp_disconnect(inst);
176 while (mInstanceState.get(inst,
false))
180 mInstanceState.wait();
182 catch (InterruptedException e)
184 throw new RuntimeException();
191 public static boolean connect(
long inst)
193 synchronized (mInstanceState)
195 if (mInstanceState.get(inst,
false))
197 throw new RuntimeException(
"instance already connected");
200 return freerdp_connect(inst);
203 public static boolean disconnect(
long inst)
205 synchronized (mInstanceState)
207 if (mInstanceState.get(inst,
false))
209 return freerdp_disconnect(inst);
215 public static boolean cancelConnection(
long inst)
217 return freerdp_disconnect(inst);
220 private static String addFlag(String name,
boolean enabled)
229 public static boolean setConnectionInfo(Context context,
long inst, BookmarkBase bookmark)
231 BookmarkBase.ScreenSettings screenSettings = bookmark.getActiveScreenSettings();
232 BookmarkBase.AdvancedSettings advanced = bookmark.getAdvancedSettings();
233 BookmarkBase.DebugSettings debug = bookmark.getDebugSettings();
236 ArrayList<String> args =
new ArrayList<>();
241 final String clientName = ApplicationSettingsActivity.getClientName(context);
242 if (!clientName.isEmpty())
244 args.add(
"/client-hostname:" + clientName);
246 String certName =
"";
247 if (bookmark.getType() != BookmarkBase.TYPE_MANUAL)
252 int port = bookmark.getPort();
253 String hostname = bookmark.getHostname();
255 args.add(
"/v:" + hostname);
256 args.add(
"/port:" + port);
258 final int level = advanced.getTlsSecLevel();
259 List<String> tls =
new ArrayList<>();
263 tls.add(
"seclevel:" + level);
266 final int tlsMinLevel = advanced.getTlsMinLevel();
267 if (tlsMinLevel >= 0)
269 tls.add(
"enforce:" + tlsMinLevel);
274 StringBuilder sb =
new StringBuilder();
283 args.add(
"/tls:" + sb);
286 arg = bookmark.getUsername();
289 args.add(
"/u:" + arg);
291 arg = bookmark.getDomain();
294 args.add(
"/d:" + arg);
296 arg = bookmark.getPassword();
299 args.add(
"/p:" + arg);
303 String.format(
"/size:%dx%d", screenSettings.getWidth(), screenSettings.getHeight()));
304 args.add(
"/bpp:" + screenSettings.getColors());
306 if (advanced.getConsoleMode())
311 switch (advanced.getSecurity())
314 args.add(
"/sec:nla");
317 args.add(
"/sec:tls");
320 args.add(
"/sec:rdp");
326 if (!certName.isEmpty())
328 args.add(
"/cert-name:" + certName);
331 BookmarkBase.PerformanceFlags flags = bookmark.getActivePerformanceFlags();
332 if (flags.getRemoteFX())
335 args.add(
"/network:auto");
341 args.add(
"/network:auto");
344 if (flags.getH264() && mHasH264)
346 args.add(
"/gfx:AVC444");
347 args.add(
"/network:auto");
350 args.add(addFlag(
"wallpaper", flags.getWallpaper()));
351 args.add(addFlag(
"window-drag", flags.getFullWindowDrag()));
352 args.add(addFlag(
"menu-anims", flags.getMenuAnimations()));
353 args.add(addFlag(
"themes", flags.getTheming()));
354 args.add(addFlag(
"fonts", flags.getFontSmoothing()));
355 args.add(addFlag(
"aero", flags.getDesktopComposition()));
357 if (!advanced.getRemoteProgram().isEmpty())
359 args.add(
"/shell:" + advanced.getRemoteProgram());
362 if (!advanced.getWorkDir().isEmpty())
364 args.add(
"/shell-dir:" + advanced.getWorkDir());
367 args.add(addFlag(
"async-channels", debug.getAsyncChannel()));
368 args.add(addFlag(
"async-update", debug.getAsyncUpdate()));
370 if (advanced.getRedirectSDCard())
372 String path = android.os.Environment.getExternalStorageDirectory().getPath();
373 args.add(
"/drive:sdcard," + path);
376 args.add(
"/clipboard");
379 if (bookmark.getType() == BookmarkBase.TYPE_MANUAL && bookmark.getEnableGatewaySettings())
381 BookmarkBase.GatewaySettings gateway = bookmark.getGatewaySettings();
383 StringBuilder carg =
new StringBuilder();
385 String.format(
"/gateway:g:%s:%d", gateway.getHostname(), gateway.getPort()));
387 arg = gateway.getUsername();
390 carg.append(
",u:" + arg);
392 arg = gateway.getDomain();
395 carg.append(
",d:" + arg);
397 arg = gateway.getPassword();
400 carg.append(
",p:" + arg);
402 args.add(carg.toString());
408 args.add(
"/audio-mode:" + advanced.getRedirectSound());
409 if (advanced.getRedirectSound() == 0)
414 if (advanced.getRedirectMicrophone())
416 args.add(
"/microphone");
419 args.add(
"/kbd:unicode:on");
420 args.add(
"/cert:ignore");
421 args.add(
"/log-level:" + debug.getDebugLevel());
422 String[] arrayArgs = args.toArray(
new String[0]);
423 return freerdp_parse_arguments(inst, arrayArgs);
426 public static boolean setConnectionInfo(Context context,
long inst, Uri openUri)
428 ArrayList<String> args =
new ArrayList<>();
437 final String clientName = ApplicationSettingsActivity.getClientName(context);
438 if (!clientName.isEmpty())
440 args.add(
"/client-hostname:" + clientName);
444 String hostname = openUri.getHost();
445 int port = openUri.getPort();
446 if (hostname !=
null)
448 hostname = hostname + ((port == -1) ?
"" : (
":" + port));
449 args.add(
"/v:" + hostname);
452 String user = openUri.getUserInfo();
455 args.add(
"/u:" + user);
458 for (String key : openUri.getQueryParameterNames())
460 String value = openUri.getQueryParameter(key);
468 else if (value.equals(
"-") || value.equals(
"+"))
472 args.add(value + key);
478 if (key.equals(
"drive") && value.equals(
"sdcard"))
481 String path = android.os.Environment.getExternalStorageDirectory().getPath();
482 value =
"sdcard," + path;
485 args.add(
"/" + key +
":" + value);
489 String[] arrayArgs = args.toArray(
new String[0]);
490 return freerdp_parse_arguments(inst, arrayArgs);
493 public static boolean updateGraphics(
long inst, Bitmap bitmap,
int x,
int y,
int width,
496 return freerdp_update_graphics(inst, bitmap, x, y, width, height);
499 public static boolean sendCursorEvent(
long inst,
int x,
int y,
int flags)
501 return freerdp_send_cursor_event(inst, x, y, flags);
504 public static boolean sendKeyEvent(
long inst,
int keycode,
boolean down)
506 return freerdp_send_key_event(inst, keycode, down);
509 public static boolean sendUnicodeKeyEvent(
long inst,
int keycode,
boolean down)
511 return freerdp_send_unicodekey_event(inst, keycode, down);
514 public static boolean sendClipboardData(
long inst, String data)
516 return freerdp_send_clipboard_data(inst, data);
519 private static void OnConnectionSuccess(
long inst)
521 if (listener !=
null)
522 listener.OnConnectionSuccess(inst);
523 synchronized (mInstanceState)
525 mInstanceState.append(inst,
true);
526 mInstanceState.notifyAll();
530 private static void OnConnectionFailure(
long inst)
532 if (listener !=
null)
533 listener.OnConnectionFailure(inst);
534 synchronized (mInstanceState)
536 mInstanceState.remove(inst);
537 mInstanceState.notifyAll();
541 private static void OnPreConnect(
long inst)
543 if (listener !=
null)
544 listener.OnPreConnect(inst);
547 private static void OnDisconnecting(
long inst)
549 if (listener !=
null)
550 listener.OnDisconnecting(inst);
553 private static void OnDisconnected(
long inst)
555 if (listener !=
null)
556 listener.OnDisconnected(inst);
557 synchronized (mInstanceState)
559 mInstanceState.remove(inst);
560 mInstanceState.notifyAll();
564 private static void OnSettingsChanged(
long inst,
int width,
int height,
int bpp)
566 SessionState s = GlobalApp.getSession(inst);
570 if (uiEventListener !=
null)
571 uiEventListener.OnSettingsChanged(width, height, bpp);
574 private static boolean OnAuthenticate(
long inst, StringBuilder username, StringBuilder domain,
575 StringBuilder password)
577 SessionState s = GlobalApp.getSession(inst);
581 if (uiEventListener !=
null)
582 return uiEventListener.OnAuthenticate(username, domain, password);
586 private static boolean OnGatewayAuthenticate(
long inst, StringBuilder username,
587 StringBuilder domain, StringBuilder password)
589 SessionState s = GlobalApp.getSession(inst);
593 if (uiEventListener !=
null)
594 return uiEventListener.OnGatewayAuthenticate(username, domain, password);
598 private static int OnVerifyCertificateEx(
long inst, String host,
long port, String commonName,
599 String subject, String issuer, String fingerprint,
602 SessionState s = GlobalApp.getSession(inst);
606 if (uiEventListener !=
null)
607 return uiEventListener.OnVerifiyCertificateEx(host, port, commonName, subject, issuer,
612 private static int OnVerifyChangedCertificateEx(
long inst, String host,
long port,
613 String commonName, String subject,
614 String issuer, String fingerprint,
615 String oldSubject, String oldIssuer,
616 String oldFingerprint,
long flags)
618 SessionState s = GlobalApp.getSession(inst);
622 if (uiEventListener !=
null)
623 return uiEventListener.OnVerifyChangedCertificateEx(host, port, commonName, subject,
624 issuer, fingerprint, oldSubject,
625 oldIssuer, oldFingerprint, flags);
629 private static void OnGraphicsUpdate(
long inst,
int x,
int y,
int width,
int height)
631 SessionState s = GlobalApp.getSession(inst);
635 if (uiEventListener !=
null)
636 uiEventListener.OnGraphicsUpdate(x, y, width, height);
639 private static void OnGraphicsResize(
long inst,
int width,
int height,
int bpp)
641 SessionState s = GlobalApp.getSession(inst);
645 if (uiEventListener !=
null)
646 uiEventListener.OnGraphicsResize(width, height, bpp);
649 private static void OnRemoteClipboardChanged(
long inst, String data)
651 SessionState s = GlobalApp.getSession(inst);
655 if (uiEventListener !=
null)
656 uiEventListener.OnRemoteClipboardChanged(data);
659 public static String getVersion()
661 return freerdp_get_version();
666 void OnPreConnect(
long instance);
668 void OnConnectionSuccess(
long instance);
670 void OnConnectionFailure(
long instance);
672 void OnDisconnecting(
long instance);
674 void OnDisconnected(
long instance);
679 void OnSettingsChanged(
int width,
int height,
int bpp);
681 boolean OnAuthenticate(StringBuilder username, StringBuilder domain,
682 StringBuilder password);
684 boolean OnGatewayAuthenticate(StringBuilder username, StringBuilder domain,
685 StringBuilder password);
687 int OnVerifiyCertificateEx(String host,
long port, String commonName, String subject, String issuer,
688 String fingerprint,
long flags);
690 int OnVerifyChangedCertificateEx(String host,
long port, String commonName, String subject, String issuer,
691 String fingerprint, String oldSubject, String oldIssuer,
692 String oldFingerprint,
long flags);
694 void OnGraphicsUpdate(
int x,
int y,
int width,
int height);
696 void OnGraphicsResize(
int width,
int height,
int bpp);
698 void OnRemoteClipboardChanged(String data);