forked from geode-sdk/android-launcher
implement enough to launch 2.2 (#2)
* generic maintenance and allow armv8 * implement missing java functions * Update build.yml * add missing audiodevice code * split apk support * ignore (gitignore) * replace library load with native code * set supported abis again --------- Co-authored-by: alk <45172705+altalk23@users.noreply.github.com>
This commit is contained in:
1 parent
c08ae0ec13
commit
c85470013f
24 files changed
+521
-251
No files matched your search
@@ -3,7 +3,7 @@ name: Build launcher
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
branches: ["main"]
|
branches: '*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|||||||
+1
-6
@@ -1,12 +1,7 @@
|
|||||||
*.iml
|
*.iml
|
||||||
.gradle
|
.gradle
|
||||||
/local.properties
|
/local.properties
|
||||||
/.idea/caches
|
/.idea/*
|
||||||
/.idea/libraries
|
|
||||||
/.idea/modules.xml
|
|
||||||
/.idea/workspace.xml
|
|
||||||
/.idea/navEditor.xml
|
|
||||||
/.idea/assetWizardSettings.xml
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/build
|
/build
|
||||||
/captures
|
/captures
|
||||||
|
|||||||
Generated
-3
@@ -1,3 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
Generated
-1
@@ -1 +0,0 @@
|
|||||||
launcher
|
|
||||||
Generated
-123
@@ -1,123 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<code_scheme name="Project" version="173">
|
|
||||||
<JetCodeStyleSettings>
|
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
|
||||||
</JetCodeStyleSettings>
|
|
||||||
<codeStyleSettings language="XML">
|
|
||||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
|
||||||
<indentOptions>
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
||||||
</indentOptions>
|
|
||||||
<arrangement>
|
|
||||||
<rules>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:android</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:id</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:name</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>name</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>style</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
</rules>
|
|
||||||
</arrangement>
|
|
||||||
</codeStyleSettings>
|
|
||||||
<codeStyleSettings language="kotlin">
|
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
|
||||||
</codeStyleSettings>
|
|
||||||
</code_scheme>
|
|
||||||
</component>
|
|
||||||
Generated
-5
@@ -1,5 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<state>
|
|
||||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
|
||||||
</state>
|
|
||||||
</component>
|
|
||||||
Generated
-6
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompilerConfiguration">
|
|
||||||
<bytecodeTargetLevel target="17" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-20
@@ -1,20 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
|
||||||
<component name="GradleSettings">
|
|
||||||
<option name="linkedExternalProjectsSettings">
|
|
||||||
<GradleProjectSettings>
|
|
||||||
<option name="testRunner" value="GRADLE" />
|
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
|
||||||
<option name="gradleJvm" value="jbr-17" />
|
|
||||||
<option name="modules">
|
|
||||||
<set>
|
|
||||||
<option value="$PROJECT_DIR$" />
|
|
||||||
<option value="$PROJECT_DIR$/app" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</GradleProjectSettings>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
-23
@@ -1,23 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
|
||||||
<option name="previewFile" value="true" />
|
|
||||||
</inspection_tool>
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
||||||
Generated
-6
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="KotlinJpsPluginSettings">
|
|
||||||
<option name="version" value="1.8.21" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-31
@@ -1,31 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DesignSurface">
|
|
||||||
<option name="filePathToZoomLevelMap">
|
|
||||||
<map>
|
|
||||||
<entry key="../../../../layout/compose-model-1653085351752.xml" value="0.375" />
|
|
||||||
<entry key="../../../../layout/compose-model-1653085541745.xml" value="2.0" />
|
|
||||||
<entry key="../../../../layout/compose-model-1653085956106.xml" value="0.33" />
|
|
||||||
<entry key="../../../../layout/compose-model-1653125149886.xml" value="0.33" />
|
|
||||||
<entry key="../../../../layout/compose-model-1653260606908.xml" value="0.2690033783783784" />
|
|
||||||
<entry key="../../../../layout/compose-model-1653262716326.xml" value="0.25" />
|
|
||||||
<entry key="../../../../layout/compose-model-1653262789080.xml" value="0.33" />
|
|
||||||
<entry key="app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.304" />
|
|
||||||
<entry key="app/src/main/res/drawable/ic_launcher_background.xml" value="0.304" />
|
|
||||||
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.3525" />
|
|
||||||
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.3525" />
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="EntryPointsManager">
|
|
||||||
<list size="1">
|
|
||||||
<item index="0" class="java.lang.String" itemvalue="android.annotation.SuppressLint" />
|
|
||||||
</list>
|
|
||||||
</component>
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectType">
|
|
||||||
<option name="id" value="Android" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
-6
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
+7
-8
@@ -9,7 +9,7 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.geode.launcher"
|
applicationId "com.geode.launcher"
|
||||||
minSdk 23
|
minSdk 23
|
||||||
targetSdk 33
|
targetSdk 34
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "0.6.0-alpha.1"
|
versionName "0.6.0-alpha.1"
|
||||||
|
|
||||||
@@ -21,8 +21,8 @@ android {
|
|||||||
arguments "-DDOBBY_DEBUG=OFF"
|
arguments "-DDOBBY_DEBUG=OFF"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// support only armv7 as GD only supports armv7
|
|
||||||
ndkConfig.abiFilters "armeabi-v7a"
|
ndkConfig.abiFilters "arm64-v8a", "armeabi-v7a"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@@ -62,14 +62,13 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation 'androidx.core:core-ktx:1.12.0'
|
implementation 'androidx.core:core-ktx:1.12.0'
|
||||||
implementation "androidx.compose.ui:ui:$compose_version"
|
implementation "androidx.compose.ui:ui:$compose_version"
|
||||||
implementation 'androidx.compose.material3:material3:1.1.1'
|
implementation 'androidx.compose.material3:material3:1.1.2'
|
||||||
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
|
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
|
||||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
|
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
|
||||||
implementation 'androidx.activity:activity-compose:1.7.2'
|
implementation 'androidx.activity:activity-compose:1.8.2'
|
||||||
implementation 'androidx.activity:activity-ktx:1.7.2'
|
implementation 'androidx.activity:activity-ktx:1.8.2'
|
||||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||||
implementation 'com.google.android.material:material:1.9.0'
|
implementation 'com.google.android.material:material:1.11.0'
|
||||||
implementation files('../libs/fmod.jar')
|
|
||||||
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
|
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
|
||||||
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
|
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
|
||||||
}
|
}
|
||||||
@@ -23,3 +23,5 @@ if(NOT dobby_POPULATED)
|
|||||||
target_include_directories(launcherfix PRIVATE ${dobby_SOURCE_DIR}/include)
|
target_include_directories(launcherfix PRIVATE ${dobby_SOURCE_DIR}/include)
|
||||||
target_link_libraries(launcherfix dobby)
|
target_link_libraries(launcherfix dobby)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(launcherfix log)
|
||||||
@@ -1,7 +1,13 @@
|
|||||||
|
#include <android/dlext.h>
|
||||||
|
#include <android/log.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <string>
|
|
||||||
#include <dobby.h>
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
#include <string>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifndef DISABLE_LAUNCHER_FIX
|
||||||
|
#include <dobby.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
class DataPaths {
|
class DataPaths {
|
||||||
public:
|
public:
|
||||||
@@ -27,6 +33,8 @@ JNIEXPORT void JNICALL Java_com_geode_launcher_LauncherFix_setDataPath(
|
|||||||
auto data_path_str = env->GetStringUTFChars(data_path, &is_copy);
|
auto data_path_str = env->GetStringUTFChars(data_path, &is_copy);
|
||||||
|
|
||||||
DataPaths::get_instance().data_path = std::string(data_path_str);
|
DataPaths::get_instance().data_path = std::string(data_path_str);
|
||||||
|
|
||||||
|
env->ReleaseStringUTFChars(data_path, data_path_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
@@ -39,6 +47,38 @@ JNIEXPORT void JNICALL Java_com_geode_launcher_LauncherFix_setOriginalDataPath(
|
|||||||
auto data_path_str = env->GetStringUTFChars(data_path, &is_copy);
|
auto data_path_str = env->GetStringUTFChars(data_path, &is_copy);
|
||||||
|
|
||||||
DataPaths::get_instance().original_data_path = std::string(data_path_str);
|
DataPaths::get_instance().original_data_path = std::string(data_path_str);
|
||||||
|
|
||||||
|
env->ReleaseStringUTFChars(data_path, data_path_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jboolean JNICALL Java_com_geode_launcher_LauncherFix_loadLibraryFromOffset(JNIEnv *env, jobject, jstring library_name, jint fd, jlong offset) {
|
||||||
|
// loads a given library at an offset and file descriptor
|
||||||
|
// assumes we have ownership of the file passed in fd
|
||||||
|
|
||||||
|
auto is_copy = jboolean();
|
||||||
|
auto library_cname = env->GetStringUTFChars(library_name, &is_copy);
|
||||||
|
|
||||||
|
android_dlextinfo ext_info{};
|
||||||
|
ext_info.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
|
||||||
|
ext_info.library_fd = fd;
|
||||||
|
ext_info.library_fd_offset = offset;
|
||||||
|
|
||||||
|
auto handle = android_dlopen_ext(library_cname, RTLD_NOW | RTLD_GLOBAL, &ext_info);
|
||||||
|
env->ReleaseStringUTFChars(library_name, library_cname);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (handle == nullptr) {
|
||||||
|
auto error = dlerror();
|
||||||
|
__android_log_print(ANDROID_LOG_WARN, "GeodeLauncher-Fix", "dlopen_ext failed. given: %s\n", error);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we don't need the library anymore
|
||||||
|
dlclose(handle);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* (*fopen_original)(const char *pathname, const char *mode);
|
FILE* (*fopen_original)(const char *pathname, const char *mode);
|
||||||
@@ -60,6 +100,7 @@ FILE* fopen_hook(const char* pathname, const char* mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[gnu::constructor]] [[gnu::used]] void setup_hooks() {
|
[[gnu::constructor]] [[gnu::used]] void setup_hooks() {
|
||||||
|
#ifndef DISABLE_LAUNCHER_FIX
|
||||||
auto fopen_addr = dlsym(RTLD_NEXT, "fopen");
|
auto fopen_addr = dlsym(RTLD_NEXT, "fopen");
|
||||||
|
|
||||||
DobbyHook(
|
DobbyHook(
|
||||||
@@ -67,4 +108,5 @@ FILE* fopen_hook(const char* pathname, const char* mode) {
|
|||||||
reinterpret_cast<dobby_dummy_func_t>(&fopen_hook),
|
reinterpret_cast<dobby_dummy_func_t>(&fopen_hook),
|
||||||
reinterpret_cast<dobby_dummy_func_t*>(&fopen_original)
|
reinterpret_cast<dobby_dummy_func_t*>(&fopen_original)
|
||||||
);
|
);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@ import android.net.NetworkCapabilities
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.view.WindowManager
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.customRobTop.JniToCpp.resumeSound
|
import com.customRobTop.JniToCpp.resumeSound
|
||||||
import org.cocos2dx.lib.Cocos2dxGLSurfaceView.Companion.closeIMEKeyboard
|
import org.cocos2dx.lib.Cocos2dxGLSurfaceView.Companion.closeIMEKeyboard
|
||||||
@@ -127,6 +128,11 @@ object BaseRobTopActivity {
|
|||||||
isLoaded = true
|
isLoaded = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getDeviceRefreshRate(): Float {
|
||||||
|
return (me.get()?.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay.refreshRate
|
||||||
|
}
|
||||||
|
|
||||||
// Everyplay doesn't even exist anymore lol
|
// Everyplay doesn't even exist anymore lol
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun setupEveryplay() {}
|
fun setupEveryplay() {}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.content.pm.ActivityInfo
|
import android.content.pm.ActivityInfo
|
||||||
|
import android.content.pm.PackageInfo
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
@@ -44,7 +45,6 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
|||||||
private var mHasWindowFocus = false
|
private var mHasWindowFocus = false
|
||||||
private var mReceiver: BroadcastReceiver? = null
|
private var mReceiver: BroadcastReceiver? = null
|
||||||
|
|
||||||
@SuppressLint("UnsafeDynamicallyLoadedCode")
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
setupUIState()
|
setupUIState()
|
||||||
|
|
||||||
@@ -57,7 +57,6 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
|||||||
}
|
}
|
||||||
|
|
||||||
val gdPackageInfo = packageManager.getPackageInfo(Constants.PACKAGE_NAME, 0)
|
val gdPackageInfo = packageManager.getPackageInfo(Constants.PACKAGE_NAME, 0)
|
||||||
val gdNativeLibraryPath = "${gdPackageInfo.applicationInfo.nativeLibraryDir}/"
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
LaunchUtils.addAssetsFromPackage(assets, gdPackageInfo)
|
LaunchUtils.addAssetsFromPackage(assets, gdPackageInfo)
|
||||||
@@ -86,8 +85,8 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
|||||||
Cocos2dxHelper.init(this, this)
|
Cocos2dxHelper.init(this, this)
|
||||||
GeodeUtils.setContext(this)
|
GeodeUtils.setContext(this)
|
||||||
|
|
||||||
System.load("$gdNativeLibraryPath/lib${Constants.FMOD_LIB_NAME}.so")
|
tryLoadLibrary(gdPackageInfo, Constants.FMOD_LIB_NAME)
|
||||||
System.load("$gdNativeLibraryPath/lib${Constants.COCOS_LIB_NAME}.so")
|
tryLoadLibrary(gdPackageInfo, Constants.COCOS_LIB_NAME)
|
||||||
|
|
||||||
if (getLoadTesting()) {
|
if (getLoadTesting()) {
|
||||||
loadTestingLibraries()
|
loadTestingLibraries()
|
||||||
@@ -114,6 +113,44 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("UnsafeDynamicallyLoadedCode")
|
||||||
|
private fun tryLoadLibrary(packageInfo: PackageInfo, libraryName: String) {
|
||||||
|
try {
|
||||||
|
val nativeDir = packageInfo.applicationInfo.nativeLibraryDir
|
||||||
|
System.load("$nativeDir/lib$libraryName.so")
|
||||||
|
} catch (ule: UnsatisfiedLinkError) {
|
||||||
|
loadLibraryFromAssets(libraryName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadLibraryFromAssets(libraryName: String) {
|
||||||
|
// loads a library loaded in assets (which points to the apk + an offset)
|
||||||
|
// these libraries are available to the application after merging
|
||||||
|
|
||||||
|
// find the first instance of the library in preferred abi order
|
||||||
|
val libraryFd = Build.SUPPORTED_ABIS.asSequence()
|
||||||
|
.mapNotNull {
|
||||||
|
try {
|
||||||
|
assets.openNonAssetFd("lib/$it/lib$libraryName.so")
|
||||||
|
} catch (_: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.firstOrNull() ?: throw UnsatisfiedLinkError("Could not find library lib$libraryName.so")
|
||||||
|
|
||||||
|
val fdOffset = libraryFd.startOffset
|
||||||
|
val fdDescriptor = libraryFd.parcelFileDescriptor.detachFd()
|
||||||
|
|
||||||
|
if (!LauncherFix.loadLibraryFromOffset("lib$libraryName.so", fdDescriptor, fdOffset)) {
|
||||||
|
throw UnsatisfiedLinkError("Failed to load asset lib$libraryName.so")
|
||||||
|
}
|
||||||
|
|
||||||
|
// after the library is opened in native code, it should be available for loading
|
||||||
|
// you can read more about the behavior:
|
||||||
|
// https://android.googlesource.com/platform/libcore/+/7f3eb2e0ac87bdea471bc577380cf50025aebde5/ojluni/src/main/java/java/lang/Runtime.java#1060
|
||||||
|
System.loadLibrary(libraryName)
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("UnsafeDynamicallyLoadedCode")
|
@SuppressLint("UnsafeDynamicallyLoadedCode")
|
||||||
private fun loadGeodeLibrary(): Boolean {
|
private fun loadGeodeLibrary(): Boolean {
|
||||||
// Load Geode if exists
|
// Load Geode if exists
|
||||||
|
|||||||
@@ -10,4 +10,6 @@ object LauncherFix {
|
|||||||
external fun setDataPath(dataPath: String)
|
external fun setDataPath(dataPath: String)
|
||||||
|
|
||||||
external fun setOriginalDataPath(dataPath: String)
|
external fun setOriginalDataPath(dataPath: String)
|
||||||
|
|
||||||
|
external fun loadLibraryFromOffset(libraryName: String, fd: Int, offset: Long): Boolean
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,6 @@ import android.content.pm.PackageInfo
|
|||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.res.AssetManager
|
import android.content.res.AssetManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.geode.launcher.utils.Constants
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
object LaunchUtils {
|
object LaunchUtils {
|
||||||
@@ -45,6 +44,10 @@ object LaunchUtils {
|
|||||||
// (the source recommends replacing with AssetManager.setApkAssets(ApkAssets[], boolean) lol)
|
// (the source recommends replacing with AssetManager.setApkAssets(ApkAssets[], boolean) lol)
|
||||||
val clazz = assetManager.javaClass
|
val clazz = assetManager.javaClass
|
||||||
val aspMethod = clazz.getDeclaredMethod("addAssetPath", String::class.java)
|
val aspMethod = clazz.getDeclaredMethod("addAssetPath", String::class.java)
|
||||||
|
|
||||||
aspMethod.invoke(assetManager, packageInfo.applicationInfo.sourceDir)
|
aspMethod.invoke(assetManager, packageInfo.applicationInfo.sourceDir)
|
||||||
|
packageInfo.applicationInfo.splitSourceDirs?.forEach {
|
||||||
|
aspMethod.invoke(assetManager, it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package org.fmod
|
||||||
|
|
||||||
|
import android.media.AudioTrack
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
|
class AudioDevice {
|
||||||
|
private var mTrack: AudioTrack? = null
|
||||||
|
private fun fetchChannelConfigFromCount(i: Int): Int {
|
||||||
|
if (i == 1) {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
if (i == 2) {
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
if (i == 6) {
|
||||||
|
return 252
|
||||||
|
}
|
||||||
|
return if (i == 8) 6396 else 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun init(i: Int, i2: Int, i3: Int, i4: Int): Boolean {
|
||||||
|
val fetchChannelConfigFromCount = fetchChannelConfigFromCount(i)
|
||||||
|
val minBufferSize = AudioTrack.getMinBufferSize(i2, fetchChannelConfigFromCount, 2)
|
||||||
|
if (minBufferSize < 0) {
|
||||||
|
Log.w(
|
||||||
|
"fmod",
|
||||||
|
"AudioDevice::init : Couldn't query minimum buffer size, possibly unsupported sample rate or channel count"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Log.i("fmod", "AudioDevice::init : Min buffer size: $minBufferSize bytes")
|
||||||
|
}
|
||||||
|
val i5 = i3 * i4 * i * 2
|
||||||
|
val i6 = if (i5 > minBufferSize) i5 else minBufferSize
|
||||||
|
Log.i("fmod", "AudioDevice::init : Actual buffer size: $i6 bytes")
|
||||||
|
return try {
|
||||||
|
val audioTrack = AudioTrack(3, i2, fetchChannelConfigFromCount, 2, i6, 1)
|
||||||
|
mTrack = audioTrack
|
||||||
|
try {
|
||||||
|
audioTrack.play()
|
||||||
|
true
|
||||||
|
} catch (unused: IllegalStateException) {
|
||||||
|
Log.e("fmod", "AudioDevice::init : AudioTrack play caused IllegalStateException")
|
||||||
|
mTrack?.release()
|
||||||
|
mTrack = null
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} catch (unused2: IllegalArgumentException) {
|
||||||
|
Log.e("fmod", "AudioDevice::init : AudioTrack creation caused IllegalArgumentException")
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun close() {
|
||||||
|
try {
|
||||||
|
mTrack?.stop()
|
||||||
|
} catch (unused: IllegalStateException) {
|
||||||
|
Log.e("fmod", "AudioDevice::init : AudioTrack stop caused IllegalStateException")
|
||||||
|
}
|
||||||
|
mTrack?.release()
|
||||||
|
mTrack = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun write(sArr: ShortArray?, i: Int) {
|
||||||
|
mTrack!!.write(sArr!!, 0, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
package org.fmod
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.content.res.AssetManager
|
||||||
|
import android.media.AudioManager
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import java.io.FileNotFoundException
|
||||||
|
|
||||||
|
// i never agreed to your licenses! take that
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
object FMOD {
|
||||||
|
private var gContext: Context? = null
|
||||||
|
private val gPluginBroadcastReceiver = PluginBroadcastReceiver()
|
||||||
|
|
||||||
|
external fun OutputAAudioHeadphonesChanged()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun init(context: Context?) {
|
||||||
|
gContext = context
|
||||||
|
if (context != null) {
|
||||||
|
gContext!!.registerReceiver(
|
||||||
|
gPluginBroadcastReceiver,
|
||||||
|
IntentFilter("android.intent.action.HEADSET_PLUG")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun close() {
|
||||||
|
val context = gContext
|
||||||
|
context?.unregisterReceiver(gPluginBroadcastReceiver)
|
||||||
|
gContext = null
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun checkInit(): Boolean {
|
||||||
|
return gContext != null
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getAssetManager(): AssetManager? {
|
||||||
|
val context = gContext
|
||||||
|
return context?.assets
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun supportsLowLatency(): Boolean {
|
||||||
|
val outputBlockSize = getOutputBlockSize()
|
||||||
|
val lowLatencyFlag = lowLatencyFlag()
|
||||||
|
val proAudioFlag = proAudioFlag()
|
||||||
|
val z = outputBlockSize in 1..1024
|
||||||
|
val isBluetoothOn = isBluetoothOn()
|
||||||
|
Log.i(
|
||||||
|
"fmod",
|
||||||
|
"FMOD::supportsLowLatency : Low latency = $lowLatencyFlag, Pro Audio = $proAudioFlag, Bluetooth On = $isBluetoothOn, Acceptable Block Size = $z ($outputBlockSize)"
|
||||||
|
)
|
||||||
|
return z && lowLatencyFlag && !isBluetoothOn
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun lowLatencyFlag(): Boolean {
|
||||||
|
if (Build.VERSION.SDK_INT < 5) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val context = gContext ?: return false
|
||||||
|
return context.packageManager.hasSystemFeature("android.hardware.audio.low_latency")
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun proAudioFlag(): Boolean {
|
||||||
|
if (Build.VERSION.SDK_INT < 5) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val context = gContext ?: return false
|
||||||
|
return context.packageManager.hasSystemFeature("android.hardware.audio.pro")
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun supportsAAudio(): Boolean {
|
||||||
|
return Build.VERSION.SDK_INT >= 27
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getOutputSampleRate(): Int {
|
||||||
|
if (Build.VERSION.SDK_INT < 17) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val context = gContext ?: return 0
|
||||||
|
val audioService = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||||
|
val property = audioService.getProperty("android.media.property.OUTPUT_SAMPLE_RATE")
|
||||||
|
|
||||||
|
return property?.toInt() ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getOutputBlockSize(): Int {
|
||||||
|
if (Build.VERSION.SDK_INT < 17) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val context = gContext ?: return 0
|
||||||
|
val audioService = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||||
|
val property = audioService.getProperty("android.media.property.OUTPUT_FRAMES_PER_BUFFER")
|
||||||
|
|
||||||
|
return property?.toInt() ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun isBluetoothOn(): Boolean {
|
||||||
|
val context = gContext ?: return false
|
||||||
|
val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||||
|
return audioManager.isBluetoothA2dpOn || audioManager.isBluetoothScoOn
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun fileDescriptorFromUri(str: String?): Int {
|
||||||
|
gContext?.apply {
|
||||||
|
try {
|
||||||
|
contentResolver.openFileDescriptor(Uri.parse(str), "r")?.apply {
|
||||||
|
return detachFd()
|
||||||
|
}
|
||||||
|
} catch (_: FileNotFoundException) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class PluginBroadcastReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
OutputAAudioHeadphonesChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
package org.fmod
|
||||||
|
|
||||||
|
import android.media.MediaCrypto
|
||||||
|
import android.media.MediaDataSource
|
||||||
|
import android.media.MediaExtractor
|
||||||
|
import android.media.MediaCodec.BufferInfo
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.Surface
|
||||||
|
import java.io.IOException
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
class MediaCodec {
|
||||||
|
private var channelCount = 0
|
||||||
|
|
||||||
|
var mCodecPtr: Long = 0
|
||||||
|
private var mCurrentOutputBufferIndex = -1
|
||||||
|
private var mDataSourceProxy: Any? = null
|
||||||
|
private var mDecoder: android.media.MediaCodec? = null
|
||||||
|
private var mExtractor: MediaExtractor? = null
|
||||||
|
private var mInputBuffers: Array<ByteBuffer>? = null
|
||||||
|
private var mInputFinished = false
|
||||||
|
private var length: Long = 0
|
||||||
|
private var mOutputBuffers: Array<ByteBuffer>? = null
|
||||||
|
private var mOutputFinished = false
|
||||||
|
private var sampleRate = 0
|
||||||
|
|
||||||
|
fun init(j: Long): Boolean {
|
||||||
|
mCodecPtr = j
|
||||||
|
var i = 0
|
||||||
|
|
||||||
|
try {
|
||||||
|
val mediaExtractor = MediaExtractor()
|
||||||
|
mExtractor = mediaExtractor
|
||||||
|
mediaExtractor.setDataSource(object : MediaDataSource() {
|
||||||
|
override fun close() {}
|
||||||
|
override fun readAt(j: Long, bArr: ByteArray, i: Int, i2: Int): Int {
|
||||||
|
return fmodReadAt(mCodecPtr, j, bArr, i, i2)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSize(): Long {
|
||||||
|
return fmodGetSize(mCodecPtr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (e5: IOException) {
|
||||||
|
Log.w("fmod", "MediaCodec::init : $e5")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val trackCount = mExtractor!!.trackCount
|
||||||
|
var i2 = 0
|
||||||
|
while (i2 < trackCount) {
|
||||||
|
val trackFormat = mExtractor!!.getTrackFormat(i2)
|
||||||
|
val string = trackFormat.getString("mime")
|
||||||
|
Log.d(
|
||||||
|
"fmod",
|
||||||
|
"MediaCodec::init : Format $i2 / $trackCount -- $trackFormat"
|
||||||
|
)
|
||||||
|
if (string == "audio/mp4a-latm") {
|
||||||
|
return try {
|
||||||
|
mDecoder = android.media.MediaCodec.createDecoderByType(string)
|
||||||
|
mExtractor!!.selectTrack(i2)
|
||||||
|
mDecoder!!.configure(trackFormat, null as Surface?, null as MediaCrypto?, 0)
|
||||||
|
mDecoder!!.start()
|
||||||
|
mInputBuffers = mDecoder!!.inputBuffers
|
||||||
|
mOutputBuffers = mDecoder!!.outputBuffers
|
||||||
|
val integer =
|
||||||
|
if (trackFormat.containsKey("encoder-delay")) trackFormat.getInteger("encoder-delay") else 0
|
||||||
|
if (trackFormat.containsKey("encoder-padding")) {
|
||||||
|
i = trackFormat.getInteger("encoder-padding")
|
||||||
|
}
|
||||||
|
val j2 = trackFormat.getLong("durationUs")
|
||||||
|
channelCount = trackFormat.getInteger("channel-count")
|
||||||
|
val integer2 = trackFormat.getInteger("sample-rate")
|
||||||
|
sampleRate = integer2
|
||||||
|
length =
|
||||||
|
(((j2 * integer2.toLong() + 999999) / 1000000).toInt() - integer - i).toLong()
|
||||||
|
true
|
||||||
|
} catch (e6: IOException) {
|
||||||
|
Log.e("fmod", "MediaCodec::init : $e6")
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i2++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun release() {
|
||||||
|
val mediaCodec = mDecoder
|
||||||
|
if (mediaCodec != null) {
|
||||||
|
mediaCodec.stop()
|
||||||
|
mDecoder?.release()
|
||||||
|
mDecoder = null
|
||||||
|
}
|
||||||
|
val mediaExtractor = mExtractor
|
||||||
|
if (mediaExtractor != null) {
|
||||||
|
mediaExtractor.release()
|
||||||
|
mExtractor = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun read(bArr: ByteArray?, i: Int): Int {
|
||||||
|
var dequeueInputBuffer = 0
|
||||||
|
val i2 =
|
||||||
|
if (!mInputFinished || !mOutputFinished || mCurrentOutputBufferIndex != -1) 0 else -1
|
||||||
|
while (!mInputFinished && mDecoder!!.dequeueInputBuffer(0).also {
|
||||||
|
dequeueInputBuffer = it
|
||||||
|
} >= 0) {
|
||||||
|
val readSampleData = mExtractor!!.readSampleData(mInputBuffers!![dequeueInputBuffer], 0)
|
||||||
|
if (readSampleData >= 0) {
|
||||||
|
mDecoder!!.queueInputBuffer(
|
||||||
|
dequeueInputBuffer,
|
||||||
|
0,
|
||||||
|
readSampleData,
|
||||||
|
mExtractor!!.sampleTime,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
mExtractor!!.advance()
|
||||||
|
} else {
|
||||||
|
mDecoder!!.queueInputBuffer(dequeueInputBuffer, 0, 0, 0, 4)
|
||||||
|
mInputFinished = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!mOutputFinished && mCurrentOutputBufferIndex == -1) {
|
||||||
|
val bufferInfo = BufferInfo()
|
||||||
|
val dequeueOutputBuffer = mDecoder!!.dequeueOutputBuffer(bufferInfo, 10000)
|
||||||
|
if (dequeueOutputBuffer >= 0) {
|
||||||
|
mCurrentOutputBufferIndex = dequeueOutputBuffer
|
||||||
|
mOutputBuffers!![dequeueOutputBuffer].limit(bufferInfo.size)
|
||||||
|
mOutputBuffers!![dequeueOutputBuffer].position(bufferInfo.offset)
|
||||||
|
} else if (dequeueOutputBuffer == -3) {
|
||||||
|
mOutputBuffers = mDecoder!!.outputBuffers
|
||||||
|
} else if (dequeueOutputBuffer == -2) {
|
||||||
|
Log.d(
|
||||||
|
"fmod",
|
||||||
|
"MediaCodec::read : MediaCodec::dequeueOutputBuffer returned MediaCodec.INFO_OUTPUT_FORMAT_CHANGED " + mDecoder!!.outputFormat
|
||||||
|
)
|
||||||
|
} else if (dequeueOutputBuffer == -1) {
|
||||||
|
Log.d(
|
||||||
|
"fmod",
|
||||||
|
"MediaCodec::read : MediaCodec::dequeueOutputBuffer returned MediaCodec.INFO_TRY_AGAIN_LATER."
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Log.w(
|
||||||
|
"fmod",
|
||||||
|
"MediaCodec::read : MediaCodec::dequeueOutputBuffer returned $dequeueOutputBuffer"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (bufferInfo.flags and 4 !== 0) {
|
||||||
|
mOutputFinished = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val i3 = mCurrentOutputBufferIndex
|
||||||
|
if (i3 == -1) {
|
||||||
|
return i2
|
||||||
|
}
|
||||||
|
val byteBuffer = mOutputBuffers!![i3]
|
||||||
|
val min = byteBuffer.remaining().coerceAtMost(i)
|
||||||
|
byteBuffer[bArr, 0, min]
|
||||||
|
if (!byteBuffer.hasRemaining()) {
|
||||||
|
byteBuffer.clear()
|
||||||
|
mDecoder!!.releaseOutputBuffer(mCurrentOutputBufferIndex, false)
|
||||||
|
mCurrentOutputBufferIndex = -1
|
||||||
|
}
|
||||||
|
return min
|
||||||
|
}
|
||||||
|
|
||||||
|
fun seek(i: Int) {
|
||||||
|
val i2 = mCurrentOutputBufferIndex
|
||||||
|
if (i2 != -1) {
|
||||||
|
mOutputBuffers!![i2].clear()
|
||||||
|
mCurrentOutputBufferIndex = -1
|
||||||
|
}
|
||||||
|
mInputFinished = false
|
||||||
|
mOutputFinished = false
|
||||||
|
mDecoder!!.flush()
|
||||||
|
val j = i.toLong()
|
||||||
|
mExtractor!!.seekTo(j * 1000000 / sampleRate.toLong(), MediaExtractor.SEEK_TO_PREVIOUS_SYNC)
|
||||||
|
val sampleTime = (mExtractor!!.sampleTime * sampleRate.toLong() + 999999) / 1000000
|
||||||
|
var i3 = ((j - sampleTime) * channelCount.toLong() * 2).toInt()
|
||||||
|
if (i3 < 0) {
|
||||||
|
Log.w(
|
||||||
|
"fmod",
|
||||||
|
"MediaCodec::seek : Seek to $i resulted in position $sampleTime"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val bArr = ByteArray(1024)
|
||||||
|
while (i3 > 0) {
|
||||||
|
i3 -= read(bArr, Math.min(1024, i3))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
external fun fmodGetSize(j: Long): Long
|
||||||
|
|
||||||
|
external fun fmodReadAt(j: Long, j2: Long, bArr: ByteArray?, i: Int, i2: Int): Int
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-5
@@ -1,13 +1,13 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
compose_version = '1.5.1'
|
compose_version = '1.5.4'
|
||||||
compose_compiler = '1.4.7'
|
compose_compiler = '1.5.7'
|
||||||
}
|
}
|
||||||
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application' version '8.1.1' apply false
|
id 'com.android.application' version '8.2.0' apply false
|
||||||
id 'com.android.library' version '8.1.1' apply false
|
id 'com.android.library' version '8.2.0' apply false
|
||||||
id 'org.jetbrains.kotlin.android' version '1.8.21' apply false
|
id 'org.jetbrains.kotlin.android' version '1.9.21' apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('clean', Delete) {
|
tasks.register('clean', Delete) {
|
||||||
|
|||||||
Binary file not shown.
Reference in new issue
Block a user