Skip to content

Commit

Permalink
Merge branch 'v3_openjdk' into feat/quick_settings
Browse files Browse the repository at this point in the history
  • Loading branch information
artdeell authored Nov 26, 2024
2 parents 03eaf12 + a5d02c1 commit eb6b23c
Show file tree
Hide file tree
Showing 20 changed files with 325 additions and 149 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![Android CI](https://github.com/PojavLauncherTeam/PojavLauncher/workflows/Android%20CI/badge.svg)](https://github.com/PojavLauncherTeam/PojavLauncher/actions)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/PojavLauncherTeam/PojavLauncher)](https://github.com/PojavLauncherTeam/PojavLauncher/actions)
[![Crowdin](https://badges.crowdin.net/pojavlauncher/localized.svg)](https://crowdin.com/project/pojavlauncher)
[![Discord](https://img.shields.io/discord/724163890803638273.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.com/invite/pojavlauncher-724163890803638273)
[![Discord](https://img.shields.io/discord/724163890803638273.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.com/invite/aenk3EUvER)
[![Twitter Follow](https://img.shields.io/twitter/follow/plaunchteam?color=blue&style=flat-square)](https://twitter.com/PLaunchTeam)

* From [Boardwalk](https://github.com/zhuowei/Boardwalk)'s ashes here comes PojavLauncher!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,38 +442,20 @@ public static void switchKeyboardState() {
if(touchCharInput != null) touchCharInput.switchKeyboardState();
}

private static void setUri(Context context, String input, Intent intent) {
if(input.startsWith("file:")) {
int truncLength = 5;
if(input.startsWith("file://")) truncLength = 7;
input = input.substring(truncLength);
Log.i("MainActivity", input);
boolean isDirectory = new File(input).isDirectory();
if(isDirectory) {
intent.setType(DocumentsContract.Document.MIME_TYPE_DIR);
}else{
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(input);
if(extension != null) type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if(type == null) type = "*/*";
intent.setType(type);
}
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.setData(DocumentsContract.buildDocumentUri(
context.getString(R.string.storageProviderAuthorities), input
));
return;
}
intent.setDataAndType(Uri.parse(input), "*/*");
}

public static void openLink(String link) {
Context ctx = touchpad.getContext(); // no more better way to obtain a context statically
((Activity)ctx).runOnUiThread(() -> {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
setUri(ctx, link, intent);
ctx.startActivity(intent);
if(link.startsWith("file:")) {
int truncLength = 5;
if(link.startsWith("file://")) truncLength = 7;
String path = link.substring(truncLength);
Tools.openPath(ctx, new File(path), false);
}else {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(link), "*/*");
ctx.startActivity(intent);
}
} catch (Throwable th) {
Tools.showError(ctx, th);
}
Expand All @@ -484,9 +466,7 @@ public static void openPath(String path) {
Context ctx = touchpad.getContext(); // no more better way to obtain a context statically
((Activity)ctx).runOnUiThread(() -> {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(DocumentsContract.buildDocumentUri(ctx.getString(R.string.storageProviderAuthorities), path), "*/*");
ctx.startActivity(intent);
Tools.openPath(ctx, new File(path), false);
} catch (Throwable th) {
Tools.showError(ctx, th);
}
Expand Down
58 changes: 49 additions & 9 deletions app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
import org.apache.commons.io.IOUtils;
import org.lwjgl.glfw.CallbackBridge;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
Expand All @@ -88,6 +89,7 @@
import java.io.StringWriter;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.ArrayList;
Expand Down Expand Up @@ -1192,17 +1194,55 @@ public static void runOnUiThread(Runnable runnable) {

/** Triggers the share intent chooser, with the latestlog file attached to it */
public static void shareLog(Context context){
Uri contentUri = DocumentsContract.buildDocumentUri(context.getString(R.string.storageProviderAuthorities), Tools.DIR_GAME_HOME + "/latestlog.txt");
openPath(context, new File(Tools.DIR_GAME_HOME, "latestlog.txt"), true);
}

Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
shareIntent.setType("text/plain");
/**
* Determine the MIME type of a File.
* @param file The file to determine the type of
* @return the type, or the default value *slash* if cannot be determined
*/
public static String getMimeType(File file) {
if(file.isDirectory()) return DocumentsContract.Document.MIME_TYPE_DIR;
String mimeType = null;
try (FileInputStream fileInputStream = new FileInputStream(file)){
// Theoretically we don't even need the buffer since we don't care about the
// contents of the file after the guess, but mark-supported streams
// are a requirement of URLConnection.guessContentTypeFromStream()
try(BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream)) {
mimeType = URLConnection.guessContentTypeFromStream(bufferedInputStream);
}
}catch (IOException e) {
Log.w("FileMimeType", "Failed to determine MIME type by stream", e);
}
if(mimeType != null) return mimeType;
mimeType = URLConnection.guessContentTypeFromName(file.getName());
if(mimeType != null) return mimeType;
return "*/*";
}

Intent sendIntent = Intent.createChooser(shareIntent, "latestlog.txt");
context.startActivity(sendIntent);
/**
* Open the path specified by a File in a file explorer or in a relevant application.
* @param context the current Context
* @param file the File to open
* @param share whether to open a "Share" or an "Open" dialog.
*/
public static void openPath(Context context, File file, boolean share) {
Uri contentUri = DocumentsContract.buildDocumentUri(context.getString(R.string.storageProviderAuthorities), file.getAbsolutePath());
String mimeType = getMimeType(file);
Intent intent = new Intent();
if(share) {
intent.setAction(Intent.ACTION_SEND);
intent.setType(getMimeType(file));
intent.putExtra(Intent.EXTRA_STREAM, contentUri);
}else {
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(contentUri, mimeType);
}
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent chooserIntent = Intent.createChooser(intent, file.getName());
context.startActivity(chooserIntent);
}

/** Mesure the textview height, given its current parameters */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.kdt.pojavlaunch.fragments;

import static net.kdt.pojavlaunch.Tools.openPath;
import static net.kdt.pojavlaunch.Tools.shareLog;

import android.content.Intent;
Expand All @@ -20,7 +21,12 @@
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.extra.ExtraConstants;
import net.kdt.pojavlaunch.extra.ExtraCore;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
import net.kdt.pojavlaunch.value.launcherprofiles.LauncherProfiles;
import net.kdt.pojavlaunch.value.launcherprofiles.MinecraftProfile;

import java.io.File;

public class MainMenuFragment extends Fragment {
public static final String TAG = "MainMenuFragment";
Expand All @@ -38,6 +44,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
Button mCustomControlButton = view.findViewById(R.id.custom_control_button);
Button mInstallJarButton = view.findViewById(R.id.install_jar_button);
Button mShareLogsButton = view.findViewById(R.id.share_logs_button);
Button mOpenDirectoryButton = view.findViewById(R.id.open_files_button);

ImageButton mEditProfileButton = view.findViewById(R.id.edit_profile_button);
Button mPlayButton = view.findViewById(R.id.play_button);
Expand All @@ -57,12 +64,24 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat

mShareLogsButton.setOnClickListener((v) -> shareLog(requireContext()));

mOpenDirectoryButton.setOnClickListener((v)-> openPath(v.getContext(), getCurrentProfileDirectory(), false));


mNewsButton.setOnLongClickListener((v)->{
Tools.swapFragment(requireActivity(), GamepadMapperFragment.class, GamepadMapperFragment.TAG, null);
return true;
});
}

private File getCurrentProfileDirectory() {
String currentProfile = LauncherPreferences.DEFAULT_PREF.getString(LauncherPreferences.PREF_KEY_CURRENT_PROFILE, null);
if(!Tools.isValidString(currentProfile)) return new File(Tools.DIR_GAME_NEW);
LauncherProfiles.load();
MinecraftProfile profileObject = LauncherProfiles.mainProfileJson.profiles.get(currentProfile);
if(profileObject == null) return new File(Tools.DIR_GAME_NEW);
return Tools.getGameDirPath(profileObject);
}

@Override
public void onResume() {
super.onResume();
Expand Down
1 change: 1 addition & 0 deletions app_pojavlauncher/src/main/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ LOCAL_SHARED_LIBRARIES := bytehook
LOCAL_SRC_FILES := \
bigcoreaffinity.c \
egl_bridge.c \
ctxbridges/loader_dlopen.c \
ctxbridges/gl_bridge.c \
ctxbridges/osm_bridge.c \
ctxbridges/egl_loader.c \
Expand Down
57 changes: 34 additions & 23 deletions app_pojavlauncher/src/main/jni/ctxbridges/egl_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <stdlib.h>
#include <dlfcn.h>
#include "egl_loader.h"
#include "loader_dlopen.h"

EGLBoolean (*eglMakeCurrent_p) (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
EGLBoolean (*eglDestroyContext_p) (EGLDisplay dpy, EGLContext ctx);
Expand All @@ -24,28 +25,38 @@ EGLint (*eglGetError_p) (void);
EGLContext (*eglCreateContext_p) (EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list);
EGLBoolean (*eglSwapInterval_p) (EGLDisplay dpy, EGLint interval);
EGLSurface (*eglGetCurrentSurface_p) (EGLint readdraw);
EGLBoolean (*eglQuerySurface_p)( EGLDisplay display,
EGLSurface surface,
EGLint attribute,
EGLint * value);
__eglMustCastToProperFunctionPointerType (*eglGetProcAddress_p) (const char *procname);

void dlsym_EGL() {
void* dl_handle = NULL;
if(getenv("POJAVEXEC_EGL")) dl_handle = dlopen(getenv("POJAVEXEC_EGL"), RTLD_LAZY);
if(dl_handle == NULL) dl_handle = dlopen("libEGL.so", RTLD_LAZY);
if(dl_handle == NULL) abort();
eglBindAPI_p = dlsym(dl_handle,"eglBindAPI");
eglChooseConfig_p = dlsym(dl_handle, "eglChooseConfig");
eglCreateContext_p = dlsym(dl_handle, "eglCreateContext");
eglCreatePbufferSurface_p = dlsym(dl_handle, "eglCreatePbufferSurface");
eglCreateWindowSurface_p = dlsym(dl_handle, "eglCreateWindowSurface");
eglDestroyContext_p = dlsym(dl_handle, "eglDestroyContext");
eglDestroySurface_p = dlsym(dl_handle, "eglDestroySurface");
eglGetConfigAttrib_p = dlsym(dl_handle, "eglGetConfigAttrib");
eglGetCurrentContext_p = dlsym(dl_handle, "eglGetCurrentContext");
eglGetDisplay_p = dlsym(dl_handle, "eglGetDisplay");
eglGetError_p = dlsym(dl_handle, "eglGetError");
eglInitialize_p = dlsym(dl_handle, "eglInitialize");
eglMakeCurrent_p = dlsym(dl_handle, "eglMakeCurrent");
eglSwapBuffers_p = dlsym(dl_handle, "eglSwapBuffers");
eglReleaseThread_p = dlsym(dl_handle, "eglReleaseThread");
eglSwapInterval_p = dlsym(dl_handle, "eglSwapInterval");
eglTerminate_p = dlsym(dl_handle, "eglTerminate");
eglGetCurrentSurface_p = dlsym(dl_handle,"eglGetCurrentSurface");
bool dlsym_EGL() {
void* dl_handle = loader_dlopen(getenv("POJAVEXEC_EGL"),"libEGL.so", RTLD_LOCAL|RTLD_LAZY);
if(dl_handle == NULL) return false;
eglGetProcAddress_p = dlsym(dl_handle, "eglGetProcAddress");
if(eglGetProcAddress_p == NULL) {
printf("%s\n", dlerror());
return false;
}
eglBindAPI_p = (void*) eglGetProcAddress_p("eglBindAPI");
eglChooseConfig_p = (void*) eglGetProcAddress_p("eglChooseConfig");
eglCreateContext_p = (void*) eglGetProcAddress_p("eglCreateContext");
eglCreatePbufferSurface_p = (void*) eglGetProcAddress_p("eglCreatePbufferSurface");
eglCreateWindowSurface_p = (void*) eglGetProcAddress_p("eglCreateWindowSurface");
eglDestroyContext_p = (void*) eglGetProcAddress_p("eglDestroyContext");
eglDestroySurface_p = (void*) eglGetProcAddress_p("eglDestroySurface");
eglGetConfigAttrib_p = (void*) eglGetProcAddress_p("eglGetConfigAttrib");
eglGetCurrentContext_p = (void*) eglGetProcAddress_p("eglGetCurrentContext");
eglGetDisplay_p = (void*) eglGetProcAddress_p("eglGetDisplay");
eglGetError_p = (void*) eglGetProcAddress_p("eglGetError");
eglInitialize_p = (void*) eglGetProcAddress_p("eglInitialize");
eglMakeCurrent_p = (void*) eglGetProcAddress_p("eglMakeCurrent");
eglSwapBuffers_p = (void*) eglGetProcAddress_p("eglSwapBuffers");
eglReleaseThread_p = (void*) eglGetProcAddress_p("eglReleaseThread");
eglSwapInterval_p = (void*) eglGetProcAddress_p("eglSwapInterval");
eglTerminate_p = (void*) eglGetProcAddress_p("eglTerminate");
eglGetCurrentSurface_p = (void*) eglGetProcAddress_p("eglGetCurrentSurface");
eglQuerySurface_p = (void*) eglGetProcAddress_p("eglQuerySurface");
return true;
}
8 changes: 7 additions & 1 deletion app_pojavlauncher/src/main/jni/ctxbridges/egl_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Created by maks on 21.09.2022.
//
#include <EGL/egl.h>
#include <stdbool.h>
#ifndef POJAVLAUNCHER_EGL_LOADER_H
#define POJAVLAUNCHER_EGL_LOADER_H

Expand All @@ -23,7 +24,12 @@ extern EGLint (*eglGetError_p) (void);
extern EGLContext (*eglCreateContext_p) (EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list);
extern EGLBoolean (*eglSwapInterval_p) (EGLDisplay dpy, EGLint interval);
extern EGLSurface (*eglGetCurrentSurface_p) (EGLint readdraw);
extern EGLBoolean (*eglQuerySurface_p)( EGLDisplay display,
EGLSurface surface,
EGLint attribute,
EGLint * value);
extern __eglMustCastToProperFunctionPointerType (*eglGetProcAddress_p) (const char *procname);

void dlsym_EGL();
bool dlsym_EGL();

#endif //POJAVLAUNCHER_EGL_LOADER_H
42 changes: 41 additions & 1 deletion app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ static __thread gl_render_window_t* currentBundle;
static EGLDisplay g_EglDisplay;

bool gl_init() {
dlsym_EGL();
if(!dlsym_EGL()) return false;
g_EglDisplay = eglGetDisplay_p(EGL_DEFAULT_DISPLAY);
if (g_EglDisplay == EGL_NO_DISPLAY) {
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s",
Expand All @@ -39,6 +39,41 @@ gl_render_window_t* gl_get_current() {
return currentBundle;
}

static void gl4esi_get_display_dimensions(int* width, int* height) {
if(currentBundle == NULL) goto zero;
EGLSurface surface = currentBundle->surface;
// Fetch dimensions from the EGL surface - the most reliable way
EGLBoolean result_width = eglQuerySurface_p(g_EglDisplay, surface, EGL_WIDTH, width);
EGLBoolean result_height = eglQuerySurface_p(g_EglDisplay, surface, EGL_HEIGHT, height);
if(!result_width || !result_height) goto zero;
return;

zero:
// No idea what to do, but feeding gl4es incorrect or non-initialized dimensions may be
// a bad idea. Set to zero in case of errors.
*width = 0;
*height = 0;
}

static bool already_initialized = false;
static void gl_init_gl4es_internals() {
if(already_initialized) return;
already_initialized = true;
void* gl4es = dlopen("libgl4es_114.so", RTLD_NOLOAD);
if(gl4es == NULL) return;
void (*set_getmainfbsize)(void (*new_getMainFBSize)(int* width, int* height));
set_getmainfbsize = dlsym(gl4es, "set_getmainfbsize");
if(set_getmainfbsize == NULL) goto warn;
set_getmainfbsize(gl4esi_get_display_dimensions);
goto cleanup;

warn:
printf("gl4esinternals warning: gl4es was found but internals not initialized. expect rendering issues.\n");
cleanup:
// dlclose just decreases a ref counter, so this is fine
dlclose(gl4es);
}

gl_render_window_t* gl_init_context(gl_render_window_t *share) {
gl_render_window_t* bundle = malloc(sizeof(gl_render_window_t));
memset(bundle, 0, sizeof(gl_render_window_t));
Expand Down Expand Up @@ -110,6 +145,11 @@ void gl_swap_surface(gl_render_window_t* bundle) {
}

void gl_make_current(gl_render_window_t* bundle) {
// Perform initialization here as the renderer may not be loaded when gl_init or gl_init_context is called.
// Yes, even though it is dlopened on MC startup by Pojav, due to linker namespacing weirdness
// on API 29/MIUI it may not be loaded at the point of the gl_init call in the current namespace.
gl_init_gl4es_internals();

if(bundle == NULL) {
if(eglMakeCurrent_p(g_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
currentBundle = NULL;
Expand Down
24 changes: 24 additions & 0 deletions app_pojavlauncher/src/main/jni/ctxbridges/loader_dlopen.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// Created by maks on 26.10.2024.
//
#include <string.h>
#include <stdio.h>
#include <dlfcn.h>
#include <linux/limits.h>
void* loader_dlopen(char* primaryName, char* secondaryName, int flags) {
void* dl_handle;
if(primaryName == NULL) goto secondary;

dl_handle = dlopen(primaryName, flags);
if(dl_handle != NULL) return dl_handle;
if(secondaryName == NULL) goto dl_error;

secondary:
dl_handle = dlopen(secondaryName, flags);
if(dl_handle == NULL) goto dl_error;
return dl_handle;

dl_error:
printf("%s", dlerror());
return NULL;
}
Loading

0 comments on commit eb6b23c

Please sign in to comment.