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 synchronized (mInstanceState)
219 if (mInstanceState.get(inst,
false))
221 return freerdp_disconnect(inst);
227 private static String addFlag(String name,
boolean enabled)
236 public static boolean setConnectionInfo(Context context,
long inst, BookmarkBase bookmark)
238 BookmarkBase.ScreenSettings screenSettings = bookmark.getActiveScreenSettings();
239 BookmarkBase.AdvancedSettings advanced = bookmark.getAdvancedSettings();
240 BookmarkBase.DebugSettings debug = bookmark.getDebugSettings();
243 ArrayList<String> args =
new ArrayList<>();
248 final String clientName = ApplicationSettingsActivity.getClientName(context);
249 if (!clientName.isEmpty())
251 args.add(
"/client-hostname:" + clientName);
253 String certName =
"";
254 if (bookmark.getType() != BookmarkBase.TYPE_MANUAL)
259 int port = bookmark.<ManualBookmark>
get().getPort();
260 String hostname = bookmark.<ManualBookmark>
get().getHostname();
262 args.add(
"/v:" + hostname);
263 args.add(
"/port:" + port);
265 arg = bookmark.getUsername();
268 args.add(
"/u:" + arg);
270 arg = bookmark.getDomain();
273 args.add(
"/d:" + arg);
275 arg = bookmark.getPassword();
278 args.add(
"/p:" + arg);
282 String.format(
"/size:%dx%d", screenSettings.getWidth(), screenSettings.getHeight()));
283 args.add(
"/bpp:" + screenSettings.getColors());
285 if (advanced.getConsoleMode())
290 switch (advanced.getSecurity())
293 args.add(
"/sec:nla");
296 args.add(
"/sec:tls");
299 args.add(
"/sec:rdp");
305 if (!certName.isEmpty())
307 args.add(
"/cert-name:" + certName);
310 BookmarkBase.PerformanceFlags flags = bookmark.getActivePerformanceFlags();
311 if (flags.getRemoteFX())
314 args.add(
"/network:auto");
320 args.add(
"/network:auto");
323 if (flags.getH264() && mHasH264)
325 args.add(
"/gfx:AVC444");
326 args.add(
"/network:auto");
329 args.add(addFlag(
"wallpaper", flags.getWallpaper()));
330 args.add(addFlag(
"window-drag", flags.getFullWindowDrag()));
331 args.add(addFlag(
"menu-anims", flags.getMenuAnimations()));
332 args.add(addFlag(
"themes", flags.getTheming()));
333 args.add(addFlag(
"fonts", flags.getFontSmoothing()));
334 args.add(addFlag(
"aero", flags.getDesktopComposition()));
336 if (!advanced.getRemoteProgram().isEmpty())
338 args.add(
"/shell:" + advanced.getRemoteProgram());
341 if (!advanced.getWorkDir().isEmpty())
343 args.add(
"/shell-dir:" + advanced.getWorkDir());
346 args.add(addFlag(
"async-channels", debug.getAsyncChannel()));
347 args.add(addFlag(
"async-update", debug.getAsyncUpdate()));
349 if (advanced.getRedirectSDCard())
351 String path = android.os.Environment.getExternalStorageDirectory().getPath();
352 args.add(
"/drive:sdcard," + path);
355 args.add(
"/clipboard");
358 if (bookmark.getType() == BookmarkBase.TYPE_MANUAL &&
359 bookmark.<ManualBookmark>
get().getEnableGatewaySettings())
361 ManualBookmark.GatewaySettings gateway =
362 bookmark.<ManualBookmark>
get().getGatewaySettings();
364 StringBuilder carg =
new StringBuilder();
366 String.format(
"/gateway:g:%s:%d", gateway.getHostname(), gateway.getPort()));
368 arg = gateway.getUsername();
371 carg.append(
",u:" + arg);
373 arg = gateway.getDomain();
376 carg.append(
",d:" + arg);
378 arg = gateway.getPassword();
381 carg.append(
",p:" + arg);
383 args.add(carg.toString());
389 args.add(
"/audio-mode:" + advanced.getRedirectSound());
390 if (advanced.getRedirectSound() == 0)
395 if (advanced.getRedirectMicrophone())
397 args.add(
"/microphone");
400 args.add(
"/kbd:unicode:on");
401 args.add(
"/cert:ignore");
402 args.add(
"/log-level:" + debug.getDebugLevel());
403 String[] arrayArgs = args.toArray(
new String[0]);
404 return freerdp_parse_arguments(inst, arrayArgs);
407 public static boolean setConnectionInfo(Context context,
long inst, Uri openUri)
409 ArrayList<String> args =
new ArrayList<>();
418 final String clientName = ApplicationSettingsActivity.getClientName(context);
419 if (!clientName.isEmpty())
421 args.add(
"/client-hostname:" + clientName);
425 String hostname = openUri.getHost();
426 int port = openUri.getPort();
427 if (hostname !=
null)
429 hostname = hostname + ((port == -1) ?
"" : (
":" + port));
430 args.add(
"/v:" + hostname);
433 String user = openUri.getUserInfo();
436 args.add(
"/u:" + user);
439 for (String key : openUri.getQueryParameterNames())
441 String value = openUri.getQueryParameter(key);
449 else if (value.equals(
"-") || value.equals(
"+"))
453 args.add(value + key);
459 if (key.equals(
"drive") && value.equals(
"sdcard"))
462 String path = android.os.Environment.getExternalStorageDirectory().getPath();
463 value =
"sdcard," + path;
466 args.add(
"/" + key +
":" + value);
470 String[] arrayArgs = args.toArray(
new String[0]);
471 return freerdp_parse_arguments(inst, arrayArgs);
474 public static boolean updateGraphics(
long inst, Bitmap bitmap,
int x,
int y,
int width,
477 return freerdp_update_graphics(inst, bitmap, x, y, width, height);
480 public static boolean sendCursorEvent(
long inst,
int x,
int y,
int flags)
482 return freerdp_send_cursor_event(inst, x, y, flags);
485 public static boolean sendKeyEvent(
long inst,
int keycode,
boolean down)
487 return freerdp_send_key_event(inst, keycode, down);
490 public static boolean sendUnicodeKeyEvent(
long inst,
int keycode,
boolean down)
492 return freerdp_send_unicodekey_event(inst, keycode, down);
495 public static boolean sendClipboardData(
long inst, String data)
497 return freerdp_send_clipboard_data(inst, data);
500 private static void OnConnectionSuccess(
long inst)
502 if (listener !=
null)
503 listener.OnConnectionSuccess(inst);
504 synchronized (mInstanceState)
506 mInstanceState.append(inst,
true);
507 mInstanceState.notifyAll();
511 private static void OnConnectionFailure(
long inst)
513 if (listener !=
null)
514 listener.OnConnectionFailure(inst);
515 synchronized (mInstanceState)
517 mInstanceState.remove(inst);
518 mInstanceState.notifyAll();
522 private static void OnPreConnect(
long inst)
524 if (listener !=
null)
525 listener.OnPreConnect(inst);
528 private static void OnDisconnecting(
long inst)
530 if (listener !=
null)
531 listener.OnDisconnecting(inst);
534 private static void OnDisconnected(
long inst)
536 if (listener !=
null)
537 listener.OnDisconnected(inst);
538 synchronized (mInstanceState)
540 mInstanceState.remove(inst);
541 mInstanceState.notifyAll();
545 private static void OnSettingsChanged(
long inst,
int width,
int height,
int bpp)
547 SessionState s = GlobalApp.getSession(inst);
551 if (uiEventListener !=
null)
552 uiEventListener.OnSettingsChanged(width, height, bpp);
555 private static boolean OnAuthenticate(
long inst, StringBuilder username, StringBuilder domain,
556 StringBuilder password)
558 SessionState s = GlobalApp.getSession(inst);
562 if (uiEventListener !=
null)
563 return uiEventListener.OnAuthenticate(username, domain, password);
567 private static boolean OnGatewayAuthenticate(
long inst, StringBuilder username,
568 StringBuilder domain, StringBuilder password)
570 SessionState s = GlobalApp.getSession(inst);
574 if (uiEventListener !=
null)
575 return uiEventListener.OnGatewayAuthenticate(username, domain, password);
579 private static int OnVerifyCertificateEx(
long inst, String host,
long port, String commonName,
580 String subject, String issuer, String fingerprint,
583 SessionState s = GlobalApp.getSession(inst);
587 if (uiEventListener !=
null)
588 return uiEventListener.OnVerifiyCertificateEx(host, port, commonName, subject, issuer,
593 private static int OnVerifyChangedCertificateEx(
long inst, String host,
long port,
594 String commonName, String subject,
595 String issuer, String fingerprint,
596 String oldSubject, String oldIssuer,
597 String oldFingerprint,
long flags)
599 SessionState s = GlobalApp.getSession(inst);
603 if (uiEventListener !=
null)
604 return uiEventListener.OnVerifyChangedCertificateEx(host, port, commonName, subject,
605 issuer, fingerprint, oldSubject,
606 oldIssuer, oldFingerprint, flags);
610 private static void OnGraphicsUpdate(
long inst,
int x,
int y,
int width,
int height)
612 SessionState s = GlobalApp.getSession(inst);
616 if (uiEventListener !=
null)
617 uiEventListener.OnGraphicsUpdate(x, y, width, height);
620 private static void OnGraphicsResize(
long inst,
int width,
int height,
int bpp)
622 SessionState s = GlobalApp.getSession(inst);
626 if (uiEventListener !=
null)
627 uiEventListener.OnGraphicsResize(width, height, bpp);
630 private static void OnRemoteClipboardChanged(
long inst, String data)
632 SessionState s = GlobalApp.getSession(inst);
636 if (uiEventListener !=
null)
637 uiEventListener.OnRemoteClipboardChanged(data);
640 public static String getVersion()
642 return freerdp_get_version();
647 void OnPreConnect(
long instance);
649 void OnConnectionSuccess(
long instance);
651 void OnConnectionFailure(
long instance);
653 void OnDisconnecting(
long instance);
655 void OnDisconnected(
long instance);
660 void OnSettingsChanged(
int width,
int height,
int bpp);
662 boolean OnAuthenticate(StringBuilder username, StringBuilder domain,
663 StringBuilder password);
665 boolean OnGatewayAuthenticate(StringBuilder username, StringBuilder domain,
666 StringBuilder password);
668 int OnVerifiyCertificateEx(String host,
long port, String commonName, String subject, String issuer,
669 String fingerprint,
long flags);
671 int OnVerifyChangedCertificateEx(String host,
long port, String commonName, String subject, String issuer,
672 String fingerprint, String oldSubject, String oldIssuer,
673 String oldFingerprint,
long flags);
675 void OnGraphicsUpdate(
int x,
int y,
int width,
int height);
677 void OnGraphicsResize(
int width,
int height,
int bpp);
679 void OnRemoteClipboardChanged(String data);