It would be good if we have a easy way to call aFreeRDP in another Android APP (Requirement also mentioned in #2720)
We can define a scheme (freerdp://) as unified way to launch FreeRDP from another APP or browser and connect to compatible RDP server
1. Define scheme freerdp://
2. General form could be freerdp://user@hostname:port/connect?key1=value&key2=-&key3=%2b&key4=
3. [user] part would be translated to /u:
4. [hostname:port] would be translated to /v:
5. The [user@hostname:port] part would be used as app title, currently it's just the progress dialog title
6. query parameters would be translated to command line arguments. Later same arguments will overwrite the formers:
a. key1=value: => /key1:value
b. key2=-: => -key2
c. key3=%2b => +key3 (%2b is url encoded +)
d. key4= => /key4
e. Especially, drive=sdcard will be properly handled with local sdcard path. On my device it will be translated to /drive:sdcard,/storage/emulated/0
Owing to the refactor work in PR #3097, we now pass same command line argument to JNI for freerdp settings.
We just need to make the SessionActivity accept freerdp scheme and translate argument from URI form to command line form.
android:theme="@style/Theme.Main"
android:configChanges="orientation|keyboardHidden|keyboard"
android:windowSoftInputMode="adjustResize">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="freerdp" android:host="*" />
+ </intent-filter>
</activity>
<activity android:name=".presentation.AboutActivity"
android:label="@string/title_about"
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.Uri;
import android.util.Log;
import java.util.*;
sessionMap.put(Integer.valueOf(session.getInstance()), session);
return session;
}
+
+ static public SessionState createSession(Uri openUri, Context context) {
+ SessionState session = new SessionState(LibFreeRDP.newInstance(context), openUri);
+ sessionMap.put(Integer.valueOf(session.getInstance()), session);
+ return session;
+ }
static public SessionState getSession(int instance) {
return sessionMap.get(instance);
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
{
private int instance;
private BookmarkBase bookmark;
+ private Uri openUri;
private BitmapDrawable surface;
private LibFreeRDP.UIEventListener uiEventListener;
{
instance = parcel.readInt();
bookmark = parcel.readParcelable(null);
+ openUri = parcel.readParcelable(null);
Bitmap bitmap = parcel.readParcelable(null);
surface = new BitmapDrawable(bitmap);
{
this.instance = instance;
this.bookmark = bookmark;
+ this.openUri = null;
+ this.uiEventListener = null;
+ }
+
+ public SessionState(int instance, Uri openUri)
+ {
+ this.instance = instance;
+ this.bookmark = null;
+ this.openUri = openUri;
this.uiEventListener = null;
}
public void connect() {
- LibFreeRDP.setConnectionInfo(instance, bookmark);
+ if (bookmark != null) {
+ LibFreeRDP.setConnectionInfo(instance, bookmark);
+ } else {
+ LibFreeRDP.setConnectionInfo(instance, openUri);
+ }
LibFreeRDP.connect(instance);
}
return bookmark;
}
+ public Uri getOpenUri() {
+ return openUri;
+ }
+
public LibFreeRDP.UIEventListener getUIEventListener() {
return uiEventListener;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(instance);
out.writeParcelable(bookmark, flags);
+ out.writeParcelable(openUri, flags);
out.writeParcelable(surface.getBitmap(), flags);
}
}
import android.graphics.drawable.BitmapDrawable;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
progressDialog = null;
}
+ if (session.getBookmark() == null) {
+ // Return immediately if we launch from URI
+ return;
+ }
+
// add hostname to history if quick connect was used
Bundle bundle = getIntent().getExtras();
if (bundle != null
}
private void processIntent(Intent intent) {
- // get either session instance or create one from a bookmark
+ // get either session instance or create one from a bookmark/uri
Bundle bundle = intent.getExtras();
- if (bundle.containsKey(PARAM_INSTANCE)) {
+ Uri openUri = intent.getData();
+ if (openUri != null) {
+ // Launched from URI, e.g:
+ // freerdp://user@ip:port/connect?sound=&rfx=&p=password&clipboard=%2b&themes=-
+ connect(openUri);
+ } else if (bundle.containsKey(PARAM_INSTANCE)) {
int inst = bundle.getInt(PARAM_INSTANCE);
session = GlobalApp.getSession(inst);
bitmap = session.getSurface().getBitmap();
private void connect(BookmarkBase bookmark) {
session = GlobalApp.createSession(bookmark, getApplicationContext());
- session.setUIEventListener(this);
BookmarkBase.ScreenSettings screenSettings = session.getBookmark()
.getActiveScreenSettings();
screenSettings.setWidth(screen_width);
}
+ connectWithTitle(bookmark.getLabel());
+ }
+
+ private void connect(Uri openUri) {
+ session = GlobalApp.createSession(openUri, getApplicationContext());
+
+ connectWithTitle(openUri.getAuthority());
+ }
+
+ private void connectWithTitle(String title) {
+ session.setUIEventListener(this);
+
progressDialog = new ProgressDialog(this);
- progressDialog.setTitle(bookmark.getLabel());
+ progressDialog.setTitle(title);
progressDialog.setMessage(getResources().getText(
R.string.dlg_msg_connecting));
progressDialog.setButton(ProgressDialog.BUTTON_NEGATIVE, "Cancel",
// binds the current session to the activity by wiring it up with the
// sessionView and updating all internal objects accordingly
private void bindSession() {
- Log.v("SessionActivity", "bindSession called");
+ Log.v(TAG, "bindSession called");
session.setUIEventListener(this);
sessionView.onSurfaceChange(session);
scrollView.requestLayout();
session.setSurface(new BitmapDrawable(bitmap));
+ if (session.getBookmark() == null) {
+ // Return immediately if we launch from URI
+ return;
+ }
+
// check this settings and initial settings - if they are not equal the
// server doesn't support our settings
// FIXME: the additional check (settings.getWidth() != width + 1) is for
import android.content.Context;
import android.graphics.Bitmap;
+import android.net.Uri;
import android.util.Log;
import java.util.ArrayList;
args.add("/gfx");
}
- if (flags.getH264()) {
- args.add("/h264");
- }
+ args.add(addFlag("gfx-h264", flags.getH264()));
args.add(addFlag("wallpaper", flags.getWallpaper()));
args.add(addFlag("window-drag", flags.getFullWindowDrag()));
String[] arrayArgs = args.toArray(new String[args.size()]);
return freerdp_parse_arguments(inst, arrayArgs);
}
+
+ public static boolean setConnectionInfo(int inst, Uri openUri) {
+ ArrayList<String> args = new ArrayList<String>();
+
+ // Parse URI from query string. Same key overwrite previous one
+ // freerdp://user@ip:port/connect?sound=&rfx=&p=password&clipboard=%2b&themes=-
+
+ // Now we only support Software GDI
+ args.add(TAG);
+ args.add("/gdi:sw");
+
+ // Parse hostname and port. Set to 'v' argument
+ String hostname = openUri.getHost();
+ int port = openUri.getPort();
+ if (hostname != null) {
+ hostname = hostname + ((port == -1) ? "" : (":" + String.valueOf(port)));
+ args.add("/v:" + hostname);
+ }
+
+ String user = openUri.getUserInfo();
+ if (user != null) {
+ args.add("/u:" + user);
+ }
+
+ for (String key: openUri.getQueryParameterNames()) {
+ String value = openUri.getQueryParameter(key);
+
+ if (value.isEmpty()) {
+ // Query: key=
+ // To freerdp argument: /key
+ args.add("/" + key);
+ } else if (value.equals("-") || value.equals("+")) {
+ // Query: key=- or key=+
+ // To freerdp argument: -key or +key
+ args.add(value+key);
+ } else {
+ // Query: key=value
+ // To freerdp argument: /key:value
+ if (key.equals("drive") && value.equals("sdcard")) {
+ // Special for sdcard redirect
+ String path = android.os.Environment.getExternalStorageDirectory().getPath();
+ value = "sdcard," + path;
+ }
+
+ args.add("/" + key + ":" + value);
+ }
+ }
+
+ String[] arrayArgs = args.toArray(new String[args.size()]);
+ return freerdp_parse_arguments(inst, arrayArgs);
+ }
public static boolean updateGraphics(int inst, Bitmap bitmap, int x, int y, int width, int height) {
return freerdp_update_graphics(inst, bitmap, x, y, width, height);