You've already forked android_translation_layer
mirror of
https://gitlab.com/android_translation_layer/android_translation_layer.git
synced 2025-10-27 11:48:10 -07:00
implement passing a URI to open inside the application
Supported URI schemes will also be added to the .desktop file for --install The URI is passed as named parameter --uri. This allows us to use unnamed parameters for split APK apps in the future
This commit is contained in:
@@ -50,11 +50,13 @@ public class Activity extends ContextThemeWrapper implements Window.Callback {
|
||||
* @return instance of main activity class
|
||||
* @throws Exception
|
||||
*/
|
||||
private static Activity createMainActivity(String className, long native_window) throws Exception {
|
||||
private static Activity createMainActivity(String className, long native_window, String uriString) throws Exception {
|
||||
Uri uri = uriString != null ? Uri.parse(uriString) : null;
|
||||
if (className == null) {
|
||||
for (PackageParser.Activity activity: pkg.activities) {
|
||||
for (PackageParser.IntentInfo intent: activity.intents) {
|
||||
if (intent.hasCategory("android.intent.category.LAUNCHER")) {
|
||||
if ((uri == null && intent.hasCategory("android.intent.category.LAUNCHER")) ||
|
||||
(uri != null && intent.hasDataScheme(uri.getScheme()))) {
|
||||
className = activity.className;
|
||||
break;
|
||||
}
|
||||
@@ -65,10 +67,16 @@ public class Activity extends ContextThemeWrapper implements Window.Callback {
|
||||
} else {
|
||||
className = className.replace('/', '.');
|
||||
}
|
||||
if (className == null) {
|
||||
System.err.println("Failed to find Activity to launch URI: " + uri);
|
||||
System.exit(1);
|
||||
}
|
||||
Class<? extends Activity> cls = Class.forName(className).asSubclass(Activity.class);
|
||||
Constructor<? extends Activity> constructor = cls.getConstructor();
|
||||
Activity activity = constructor.newInstance();
|
||||
activity.window.native_window = native_window;
|
||||
if (uri != null)
|
||||
activity.setIntent(new Intent("android.intent.action.VIEW", uri));
|
||||
return activity;
|
||||
}
|
||||
|
||||
@@ -467,7 +475,9 @@ public class Activity extends ContextThemeWrapper implements Window.Callback {
|
||||
finish();
|
||||
}
|
||||
|
||||
public void setIntent(Intent newIntent) {}
|
||||
public void setIntent(Intent newIntent) {
|
||||
this.intent = newIntent;
|
||||
}
|
||||
|
||||
public void unregisterReceiver(BroadcastReceiver receiver) {}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.os.Bundle;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.pm.PackageParser;
|
||||
|
||||
public class Application extends ContextWrapper {
|
||||
public long native_window;
|
||||
@@ -16,6 +17,21 @@ public class Application extends ContextWrapper {
|
||||
return getString(pkg.applicationInfo.labelRes);
|
||||
}
|
||||
|
||||
String get_supported_mime_types() {
|
||||
String mimeTypes = "";
|
||||
for (PackageParser.Activity activity: pkg.activities) {
|
||||
for (PackageParser.IntentInfo intent: activity.intents) {
|
||||
for (int i = 0; i < intent.countDataSchemes(); i++) {
|
||||
String scheme = intent.getDataScheme(i);
|
||||
// ignore http and https, as there is no way to only handle specific hosts in a .desktop file
|
||||
if (!"http".equals(scheme) && !"https".equals(scheme))
|
||||
mimeTypes += "x-scheme-handler/" + intent.getDataScheme(i) + ";";
|
||||
}
|
||||
}
|
||||
}
|
||||
return "".equals(mimeTypes) ? null : mimeTypes;
|
||||
}
|
||||
|
||||
public interface ActivityLifecycleCallbacks {
|
||||
void onActivityCreated(Activity activity, Bundle savedInstanceState);
|
||||
void onActivityStarted(Activity activity);
|
||||
|
||||
@@ -9,6 +9,7 @@ public class IntentFilter {
|
||||
|
||||
private List<String> actions = new ArrayList<>();
|
||||
private Set<String> categories = new HashSet<>();
|
||||
private List<String> dataSchemes = new ArrayList<>();
|
||||
|
||||
public IntentFilter() {}
|
||||
public IntentFilter(String action) {
|
||||
@@ -42,4 +43,20 @@ public class IntentFilter {
|
||||
}
|
||||
|
||||
public void setPriority(int priority) {}
|
||||
|
||||
public void addDataScheme(String dataScheme) {
|
||||
dataSchemes.add(dataScheme);
|
||||
}
|
||||
|
||||
public boolean hasDataScheme(String dataScheme) {
|
||||
return dataSchemes.contains(dataScheme);
|
||||
}
|
||||
|
||||
public int countDataSchemes() {
|
||||
return dataSchemes.size();
|
||||
}
|
||||
|
||||
public String getDataScheme(int index) {
|
||||
return dataSchemes.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.PatternMatcher;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Base64;
|
||||
import android.util.DisplayMetrics;
|
||||
@@ -2247,6 +2248,10 @@ public class PackageParser {
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
outInfo.addCategory(value);
|
||||
} else if (nodeName.equals("data")) {
|
||||
String scheme = parser.getAttributeValue(
|
||||
ANDROID_RESOURCES, "scheme");
|
||||
if (!TextUtils.isEmpty(scheme))
|
||||
outInfo.addDataScheme(scheme);
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
} else if (!RIGID_PARSER) {
|
||||
Slog.w(TAG, "Unknown element under <intent-filter>: "
|
||||
|
||||
@@ -198,6 +198,8 @@ struct jni_callback_data {
|
||||
char **extra_string_keys;
|
||||
};
|
||||
|
||||
static char *uri_option = NULL;
|
||||
|
||||
static void open(GtkApplication *app, GFile **files, gint nfiles, const gchar *hint, struct jni_callback_data *d)
|
||||
{
|
||||
// TODO: pass all files to classpath
|
||||
@@ -428,10 +430,12 @@ static void open(GtkApplication *app, GFile **files, gint nfiles, const gchar *h
|
||||
|
||||
// construct main Activity
|
||||
activity_object = (*env)->CallStaticObjectMethod(env, handle_cache.activity.class,
|
||||
_STATIC_METHOD(handle_cache.activity.class, "createMainActivity", "(Ljava/lang/String;J)Landroid/app/Activity;"),
|
||||
_JSTRING(d->apk_main_activity_class), _INTPTR(window));
|
||||
_STATIC_METHOD(handle_cache.activity.class, "createMainActivity", "(Ljava/lang/String;JLjava/lang/String;)Landroid/app/Activity;"),
|
||||
_JSTRING(d->apk_main_activity_class), _INTPTR(window), uri_option ? _JSTRING(uri_option) : NULL);
|
||||
if ((*env)->ExceptionCheck(env))
|
||||
(*env)->ExceptionDescribe(env);
|
||||
if (uri_option)
|
||||
g_free(uri_option);
|
||||
|
||||
if (d->extra_string_keys) {
|
||||
GError *error = NULL;
|
||||
@@ -493,6 +497,12 @@ static void open(GtkApplication *app, GFile **files, gint nfiles, const gchar *h
|
||||
g_file_make_directory(g_file_get_parent(dest), NULL, NULL);
|
||||
g_file_copy(files[0], dest, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, NULL);
|
||||
|
||||
jmethodID get_supported_mime_types = _METHOD(handle_cache.application.class, "get_supported_mime_types", "()Ljava/lang/String;");
|
||||
jstring supported_mime_types_jstr = (*env)->CallObjectMethod(env, application_object, get_supported_mime_types);
|
||||
const char *supported_mime_types = supported_mime_types_jstr ? _CSTRING(supported_mime_types_jstr) : NULL;
|
||||
if ((*env)->ExceptionCheck(env))
|
||||
(*env)->ExceptionDescribe(env);
|
||||
|
||||
GString *desktop_entry = g_string_new("[Desktop Entry]\n"
|
||||
"Type=Application\n"
|
||||
"Exec=env ");
|
||||
@@ -514,7 +524,9 @@ static void open(GtkApplication *app, GFile **files, gint nfiles, const gchar *h
|
||||
g_string_append_printf(desktop_entry, "-w %d ", d->window_width);
|
||||
if (d->window_height)
|
||||
g_string_append_printf(desktop_entry, "-h %d ", d->window_height);
|
||||
g_string_append_printf(desktop_entry, "%s\n", g_file_get_path(dest));
|
||||
g_string_append_printf(desktop_entry, "%s --uri %%u\n", g_file_get_path(dest));
|
||||
if (supported_mime_types)
|
||||
g_string_append_printf(desktop_entry, "MimeType=%s\n", supported_mime_types);
|
||||
struct dynamic_launcher_callback_data *cb_data = g_new(struct dynamic_launcher_callback_data, 1);
|
||||
cb_data->desktop_file_id = g_strdup_printf("%s.desktop", package_name);
|
||||
cb_data->desktop_entry = g_string_free(desktop_entry, FALSE);
|
||||
@@ -573,6 +585,13 @@ static void activate(GtkApplication *app, struct jni_callback_data *d)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static gboolean option_uri_cb(const gchar* option_name, const gchar* value, gpointer data, GError** error)
|
||||
{
|
||||
printf("option_uri_cb: %s %s, %p, %p\n", option_name, value, data, error);
|
||||
uri_option = g_strdup(value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void init_cmd_parameters(GApplication *app, struct jni_callback_data *d)
|
||||
{
|
||||
const GOptionEntry cmd_params[] = {
|
||||
@@ -583,6 +602,7 @@ void init_cmd_parameters(GApplication *app, struct jni_callback_data *d)
|
||||
{ "install", 'i', 0, G_OPTION_ARG_NONE, &d->install, "install .desktop file for the given apk", NULL },
|
||||
{ "extra-jvm-option", 'X', 0, G_OPTION_ARG_STRING_ARRAY, &d->extra_jvm_options, "pass an additional option directly to art (e.g -X \"-verbose:jni\")", "\"OPTION\"" },
|
||||
{ "extra-string-key", 'e', 0, G_OPTION_ARG_STRING_ARRAY, &d->extra_string_keys, "pass a string extra (-e key=value)", "\"KEY=VALUE\"" },
|
||||
{ "uri", 'u', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, option_uri_cb, "open the given URI inside the application", "URI" },
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user