change package name

This commit is contained in:
qimiko committed 2022-10-29 16:57:28 -07:00
1 parent 824f7de329
commit 7a509fd02a
9 files changed
+18 -17

No files matched your search

@@ -0,0 +1,311 @@
package com.geode.geodelauncher
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.ActivityInfo
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.os.FileUtils
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import com.customRobTop.BaseRobTopActivity
import com.customRobTop.JniToCpp
import com.geode.geodelauncher.utils.GJConstants
import com.geode.geodelauncher.utils.LaunchUtils
import org.cocos2dx.lib.Cocos2dxEditText
import org.cocos2dx.lib.Cocos2dxGLSurfaceView
import org.cocos2dx.lib.Cocos2dxHelper
import org.cocos2dx.lib.Cocos2dxRenderer
import org.fmod.FMOD
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.InputStream
import java.io.OutputStream
class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperListener {
private var mGLSurfaceView: Cocos2dxGLSurfaceView? = null
private val sTag = GeometryDashActivity::class.simpleName
private var mIsRunning = false
private var mIsOnPause = false
private var mHasWindowFocus = false
private var mReceiver: BroadcastReceiver? = null
@SuppressLint("UnsafeDynamicallyLoadedCode")
override fun onCreate(savedInstanceState: Bundle?) {
setupUIState()
// return back to main if Geometry Dash isn't found
if (!LaunchUtils.isGeometryDashInstalled(packageManager)) {
val launchIntent = Intent(this, MainActivity::class.java)
launchIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(launchIntent)
}
val gdPackageInfo = packageManager.getPackageInfo(GJConstants.PACKAGE_NAME, 0)
val gdNativeLibraryPath = "${gdPackageInfo.applicationInfo.nativeLibraryDir}/"
try {
LaunchUtils.addAssetsFromPackage(assets, gdPackageInfo)
} catch (e: NoSuchMethodException) {
e.printStackTrace()
}
try {
// fixes bugs specific to the new app directory, such as package name
LauncherFix.loadLibrary()
LauncherFix.setOriginalDataPath(GJConstants.GJ_DATA_DIR)
LauncherFix.setDataPath(filesDir.path)
} catch (e: UnsatisfiedLinkError) {
e.printStackTrace()
}
System.load("$gdNativeLibraryPath/lib${GJConstants.FMOD_LIB_NAME}.so")
System.load("$gdNativeLibraryPath/lib${GJConstants.COCOS_LIB_NAME}.so")
if (getLoadTesting()) {
loadTestingLibraries()
}
FMOD.init(this)
super.onCreate(savedInstanceState)
setContentView(createView())
Cocos2dxHelper.init(this, this)
JniToCpp.setupHSSAssets(
gdPackageInfo.applicationInfo.sourceDir,
Environment.getExternalStorageDirectory().absolutePath
)
Cocos2dxHelper.nativeSetApkPath(gdPackageInfo.applicationInfo.sourceDir)
BaseRobTopActivity.setCurrentActivity(this)
registerReceiver()
}
private fun createView(): FrameLayout {
val frameLayoutParams = ViewGroup.LayoutParams(-1, -1)
val frameLayout = FrameLayout(this)
frameLayout.layoutParams = frameLayoutParams
val editTextLayoutParams = ViewGroup.LayoutParams(-1, -2)
val editText = Cocos2dxEditText(this)
editText.layoutParams = editTextLayoutParams
frameLayout.addView(editText)
val glSurfaceView = Cocos2dxGLSurfaceView(this)
this.mGLSurfaceView = glSurfaceView
frameLayout.addView(this.mGLSurfaceView)
glSurfaceView.setEGLConfigChooser(5, 6, 5, 0, 16, 8)
if (isAndroidEmulator()) {
glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0)
}
glSurfaceView.initView()
glSurfaceView.setCocos2dxRenderer(Cocos2dxRenderer())
editText.inputType = 145
glSurfaceView.cocos2dxEditText = editText
return frameLayout
}
private fun setupUIState() {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
hideSystemUi()
}
private fun hideSystemUi() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
// window compat is dumb!!
setLegacyVisibility()
window.decorView.setOnSystemUiVisibilityChangeListener { visibility ->
if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
setLegacyVisibility()
}
}
}
WindowCompat.getInsetsController(window, window.decorView).apply {
systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
hide(WindowInsetsCompat.Type.systemBars())
}
}
private fun setLegacyVisibility() {
// setDecorFitsSystemWindows doesn't hide anything
window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
}
override fun onDestroy() {
super.onDestroy()
unregisterReceivers()
FMOD.close()
}
private fun resumeGame() {
mIsRunning = true
// Cocos2dxHelper.onResume()
mGLSurfaceView?.onResume()
}
private fun pauseGame() {
mIsRunning = false
// Cocos2dxHelper.onPause()
mGLSurfaceView?.onPause()
}
override fun onResume() {
super.onResume()
mIsOnPause = false
BaseRobTopActivity.isPaused = false
if (mHasWindowFocus && !this.mIsRunning) {
resumeGame()
}
}
override fun onPause() {
super.onPause()
mIsOnPause = true
BaseRobTopActivity.isPaused = true
if (mIsRunning) {
pauseGame()
}
}
private fun registerReceiver() {
unregisterReceivers()
try {
val filter = IntentFilter(Intent.ACTION_SCREEN_ON)
filter.addAction(Intent.ACTION_SCREEN_OFF)
filter.addAction(Intent.ACTION_USER_PRESENT)
mReceiver = BaseRobTopActivity.ReceiverScreen()
registerReceiver(mReceiver, filter)
} catch (_: Exception) {
}
}
private fun unregisterReceivers() {
if (mReceiver != null) {
unregisterReceiver(mReceiver)
mReceiver = null
}
}
override fun onWindowFocusChanged(hasWindowFocus: Boolean) {
super.onWindowFocusChanged(hasWindowFocus)
mHasWindowFocus = hasWindowFocus
if (hasWindowFocus && !mIsOnPause) {
resumeGame()
}
}
override fun runOnGLThread(runnable: Runnable) {
mGLSurfaceView?.queueEvent(runnable)
}
override fun showDialog(title: String, message: String) {
TODO("Not yet implemented")
}
override fun showEditTextDialog(
title: String,
message: String,
inputMode: Int,
inputFlag: Int,
returnType: Int,
maxLength: Int
) {
TODO("Not yet implemented")
}
private fun isAndroidEmulator(): Boolean {
Log.d(sTag, "model=" + Build.MODEL)
val product = Build.PRODUCT
Log.d(sTag, "product=$product")
var isEmulator = false
if (product != null) {
isEmulator = product == "sdk" || product.contains("_sdk") || product.contains("sdk_")
}
Log.d(sTag, "isEmulator=$isEmulator")
return isEmulator
}
private fun getLoadTesting(): Boolean {
val preferences = getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE)
return preferences.getBoolean(getString(R.string.preference_load_testing), false)
}
@SuppressLint("UnsafeDynamicallyLoadedCode")
private fun loadTestingLibraries() {
// clear data dir
val testDirPath = File(filesDir.path + File.separator + "testlib" + File.separator)
if (testDirPath.exists()) {
testDirPath.deleteRecursively()
}
testDirPath.mkdir()
getExternalFilesDir(null)?.let { dir ->
val testingPath = dir.path + File.separator + "test" + File.separator
File(testingPath).walk().forEach {
if (it.isFile) {
// welcome to the world of Android classloader permissions
val outputFile = File(testDirPath.path + File.separator + it.name)
copyFile(FileInputStream(it), FileOutputStream(outputFile))
try {
println("Loading test library ${outputFile.name}")
System.load(outputFile.path)
} catch (e: UnsatisfiedLinkError) {
e.printStackTrace()
}
}
}
}
}
private fun copyFile(inputStream: InputStream, outputStream: OutputStream) {
// gotta love copying
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
FileUtils.copy(inputStream, outputStream)
} else {
inputStream.use { input ->
outputStream.use { output ->
val buffer = ByteArray(4 * 1024)
while (true) {
val byteCount = input.read(buffer)
if (byteCount < 0) break
output.write(buffer, 0, byteCount)
}
output.flush()
}
}
}
}
}
@@ -0,0 +1,13 @@
package com.geode.geodelauncher
import com.geode.geodelauncher.utils.GJConstants
object LauncherFix {
fun loadLibrary() {
System.loadLibrary(GJConstants.LAUNCHER_FIX_LIB_NAME)
}
external fun setDataPath(dataPath: String)
external fun setOriginalDataPath(dataPath: String)
}
@@ -0,0 +1,234 @@
package com.geode.geodelauncher
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.selection.toggleable
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ExitToApp
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Warning
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.edit
import com.geode.geodelauncher.ui.theme.GeodeLauncherTheme
import com.geode.geodelauncher.utils.LaunchUtils
import java.io.File
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val gdInstalled = LaunchUtils.isGeometryDashInstalled(packageManager)
setContent {
GeodeLauncherTheme {
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
MainScreen(gdInstalled)
}
}
}
}
}
fun onLaunch(context: Context) {
val launchIntent = Intent(context, GeometryDashActivity::class.java)
launchIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(launchIntent)
}
fun onSettings(context: Context) {
Toast.makeText(context, "Settings are not implemented yet!", Toast.LENGTH_SHORT).show()
}
fun onOpenFolder(context: Context) {
context.getExternalFilesDir(null)?.let { file ->
val geodePath = file.path + File.separator + "geode" + File.separator
}
}
fun toggleLoadTesting(context: Context): Boolean {
val preferences = context.getSharedPreferences(
context.getString(R.string.preference_file_key), Context.MODE_PRIVATE)
val current = preferences.getBoolean(
context.getString(R.string.preference_load_testing), false)
preferences.edit {
putBoolean(context.getString(R.string.preference_load_testing), !current)
commit()
}
return preferences.getBoolean(context.getString(R.string.preference_load_testing), false)
}
fun getLoadTesting(context: Context): Boolean {
val preferences = context.getSharedPreferences(
context.getString(R.string.preference_file_key), Context.MODE_PRIVATE)
return preferences.getBoolean(context.getString(R.string.preference_load_testing), false)
}
@Composable
fun MainScreen(gdInstalled: Boolean = true) {
val context = LocalContext.current
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(id = R.drawable.geode_logo),
contentDescription = "Geode Logo",
modifier = Modifier.size(136.dp, 136.dp)
)
Text(
"Geode",
fontSize = 32.sp,
modifier = Modifier.padding(12.dp)
)
if (gdInstalled) {
Row {
Button(onClick = { onLaunch(context) }, enabled = gdInstalled) {
Icon(
Icons.Filled.PlayArrow,
contentDescription = "Play Icon"
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text("Launch")
}
/*
IconButton(onClick = { onSettings(context) }) {
Icon(
Icons.Filled.Settings,
contentDescription = "Settings Icon"
)
}
*/
}
} else {
Text(
"Geometry Dash could not be found.",
modifier = Modifier.padding(12.dp)
)
/*
Button(onClick = { onSettings(context) }) {
Icon(
Icons.Filled.Settings,
contentDescription = "Settings Icon"
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text("Settings")
}
*/
}
Spacer(modifier = Modifier.height(12.dp))
TestingUtils()
}
}
@Composable
fun TestingUtils() {
val context = LocalContext.current
val isLoadTesting = remember { mutableStateOf(getLoadTesting(context)) }
Card(
elevation = CardDefaults.elevatedCardElevation(),
colors = CardDefaults.elevatedCardColors(),
) {
Column(
Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(4.dp, Alignment.CenterVertically),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Row {
Icon(
Icons.Filled.Warning,
contentDescription = "Warning Icon"
)
Spacer(Modifier.size(4.dp))
Text("Testing Utils")
}
Row(
Modifier
.height(48.dp)
.toggleable(
value = isLoadTesting.value,
onValueChange = { isLoadTesting.value = toggleLoadTesting(context) },
role = Role.Checkbox
)
.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = isLoadTesting.value,
onCheckedChange = null
)
Text(
text = "Load files in /test",
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.padding(start = 16.dp)
)
}
Button(
onClick = { onOpenFolder(context) }
) {
Icon(
Icons.Filled.ExitToApp,
contentDescription = "Folder Icon"
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text("Open external folder")
}
}
}
}
@Preview(showSystemUi = true)
@Composable
fun MainScreenLightPreview() {
GeodeLauncherTheme {
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
MainScreen()
}
}
}
@Preview(showSystemUi = true)
@Composable
fun MainScreenDarkPreview() {
GeodeLauncherTheme(darkTheme = true) {
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
MainScreen()
}
}
}
@Preview
@Composable
fun MainScreenNoGeometryDashPreview() {
GeodeLauncherTheme {
MainScreen(gdInstalled = false)
}
}
@@ -0,0 +1,11 @@
package com.geode.geodelauncher.ui.theme
import androidx.compose.ui.graphics.Color
val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)
@@ -0,0 +1,75 @@
package com.geode.geodelauncher.ui.theme
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.ViewCompat
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
)
@Composable
fun GeodeLauncherTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColorScheme
else -> LightColorScheme
}
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
with ((view.context as Activity).window) {
statusBarColor = colorScheme.background.toArgb()
navigationBarColor = colorScheme.background.toArgb()
}
with (ViewCompat.getWindowInsetsController(view)) {
this?.isAppearanceLightStatusBars = !darkTheme
this?.isAppearanceLightNavigationBars = !darkTheme
}
}
}
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
content = content
)
}
@@ -0,0 +1,34 @@
package com.geode.geodelauncher.ui.theme
import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
// Set of Material typography styles to start with
val Typography = Typography(
bodyLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
)
/* Other default text styles to override
titleLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 22.sp,
lineHeight = 28.sp,
letterSpacing = 0.sp
),
labelSmall = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Medium,
fontSize = 11.sp,
lineHeight = 16.sp,
letterSpacing = 0.5.sp
)
*/
)
@@ -0,0 +1,15 @@
package com.geode.geodelauncher.utils
import android.annotation.SuppressLint
object GJConstants {
const val PACKAGE_NAME = "com.robtopx.geometryjump"
const val COCOS_LIB_NAME = "cocos2dcpp"
const val FMOD_LIB_NAME = "fmod"
const val LAUNCHER_FIX_LIB_NAME = "launcherfix"
// this value is hardcoded into GD
@SuppressLint("SdCardPath")
const val GJ_DATA_DIR = "/data/data/${PACKAGE_NAME}"
}
@@ -0,0 +1,24 @@
package com.geode.geodelauncher.utils
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.res.AssetManager
object LaunchUtils {
fun isGeometryDashInstalled(packageManager: PackageManager): Boolean {
return try {
packageManager.getPackageInfo(GJConstants.PACKAGE_NAME, 0)
true
} catch (e: PackageManager.NameNotFoundException) {
false
}
}
fun addAssetsFromPackage(assetManager: AssetManager, packageInfo: PackageInfo) {
// this method is officially marked as deprecated but it is the only method we are allowed to reflect
// (the source recommends replacing with AssetManager.setApkAssets(ApkAssets[], boolean) lol)
val clazz = assetManager.javaClass
val aspMethod = clazz.getDeclaredMethod("addAssetPath", String::class.java)
aspMethod.invoke(assetManager, packageInfo.applicationInfo.sourceDir)
}
}