Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android: Prevent potential NPEs and improve nullability handling #89999

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 60 additions & 53 deletions platform/android/java/lib/src/org/godotengine/godot/Godot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -396,16 +396,19 @@ class Godot(private val context: Context) : SensorEventListener {
}

if (host == primaryHost) {
renderView!!.startRenderer()
renderView?.startRenderer()
}
val view: View = renderView!!.view
containerLayout?.addView(
view,

renderView?.let {
containerLayout?.addView(
it.view,
ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
)
)
}

editText.setView(renderView)
io?.setEdit(editText)

Expand Down Expand Up @@ -448,20 +451,23 @@ class Godot(private val context: Context) : SensorEventListener {
})
} else {
// Infer the virtual keyboard height using visible area.
view.viewTreeObserver.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
renderView?.view?.viewTreeObserver?.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
// Don't allocate a new Rect every time the callback is called.
val visibleSize = Rect()
override fun onGlobalLayout() {
val surfaceView = renderView!!.view
surfaceView.getWindowVisibleDisplayFrame(visibleSize)
val keyboardHeight = surfaceView.height - visibleSize.bottom
GodotLib.setVirtualKeyboardHeight(keyboardHeight)
renderView?.let {
val surfaceView = it.view

surfaceView.getWindowVisibleDisplayFrame(visibleSize)
val keyboardHeight = surfaceView.height - visibleSize.bottom
GodotLib.setVirtualKeyboardHeight(keyboardHeight)
}
}
})
}

if (host == primaryHost) {
renderView!!.queueOnRenderThread {
renderView?.queueOnRenderThread {
for (plugin in pluginRegistry.allPlugins) {
plugin.onRegisterPluginWithGodotNative()
}
Expand Down Expand Up @@ -495,15 +501,15 @@ class Godot(private val context: Context) : SensorEventListener {
return
}

renderView!!.onActivityStarted()
renderView?.onActivityStarted()
}

fun onResume(host: GodotHost) {
if (host != primaryHost) {
return
}

renderView!!.onActivityResumed()
renderView?.onActivityResumed()
if (mAccelerometer != null) {
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME)
}
Expand Down Expand Up @@ -535,7 +541,7 @@ class Godot(private val context: Context) : SensorEventListener {
return
}

renderView!!.onActivityPaused()
renderView?.onActivityPaused()
mSensorManager.unregisterListener(this)
for (plugin in pluginRegistry.allPlugins) {
plugin.onMainPause()
Expand All @@ -547,7 +553,7 @@ class Godot(private val context: Context) : SensorEventListener {
return
}

renderView!!.onActivityStopped()
renderView?.onActivityStopped()
}

fun onDestroy(primaryHost: GodotHost) {
Expand All @@ -569,7 +575,7 @@ class Godot(private val context: Context) : SensorEventListener {
* Configuration change callback
*/
fun onConfigurationChanged(newConfig: Configuration) {
var newDarkMode = newConfig.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
val newDarkMode = newConfig.uiMode.and(Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
if (darkMode != newDarkMode) {
darkMode = newDarkMode
GodotLib.onNightModeChanged()
Expand Down Expand Up @@ -686,9 +692,7 @@ class Godot(private val context: Context) : SensorEventListener {
* This must be called after the render thread has started.
*/
fun runOnRenderThread(action: Runnable) {
if (renderView != null) {
renderView!!.queueOnRenderThread(action)
}
renderView?.queueOnRenderThread(action)
}

/**
Expand Down Expand Up @@ -765,7 +769,7 @@ class Godot(private val context: Context) : SensorEventListener {
return mClipboard.hasPrimaryClip()
}

fun getClipboard(): String? {
fun getClipboard(): String {
val clipData = mClipboard.primaryClip ?: return ""
val text = clipData.getItemAt(0).text ?: return ""
return text.toString()
Expand All @@ -782,15 +786,14 @@ class Godot(private val context: Context) : SensorEventListener {

@Keep
private fun forceQuit(instanceId: Int): Boolean {
if (primaryHost == null) {
return false
}
return if (instanceId == 0) {
primaryHost!!.onGodotForceQuit(this)
true
} else {
primaryHost!!.onGodotForceQuit(instanceId)
}
primaryHost?.let {
if (instanceId == 0) {
it.onGodotForceQuit(this)
return true
} else {
return it.onGodotForceQuit(instanceId)
}
} ?: return false
}

fun onBackPressed(host: GodotHost) {
Expand All @@ -804,14 +807,14 @@ class Godot(private val context: Context) : SensorEventListener {
shouldQuit = false
}
}
if (shouldQuit && renderView != null) {
renderView!!.queueOnRenderThread { GodotLib.back() }
if (shouldQuit) {
renderView?.queueOnRenderThread { GodotLib.back() }
}
}

private fun getRotatedValues(values: FloatArray?): FloatArray? {
if (values == null || values.size != 3) {
return values
return null
}
val display =
(requireActivity().getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay
Expand Down Expand Up @@ -848,35 +851,39 @@ class Godot(private val context: Context) : SensorEventListener {
}
when (event.sensor.type) {
Sensor.TYPE_ACCELEROMETER -> {
val rotatedValues = getRotatedValues(event.values)
renderView!!.queueOnRenderThread {
GodotLib.accelerometer(
-rotatedValues!![0], -rotatedValues[1], -rotatedValues[2]
)
getRotatedValues(event.values)?.let { rotatedValues ->
renderView?.queueOnRenderThread {
GodotLib.accelerometer(
-rotatedValues[0], -rotatedValues[1], -rotatedValues[2]
)
}
}
}
Sensor.TYPE_GRAVITY -> {
val rotatedValues = getRotatedValues(event.values)
renderView!!.queueOnRenderThread {
GodotLib.gravity(
-rotatedValues!![0], -rotatedValues[1], -rotatedValues[2]
)
getRotatedValues(event.values)?.let { rotatedValues ->
renderView?.queueOnRenderThread {
GodotLib.gravity(
-rotatedValues[0], -rotatedValues[1], -rotatedValues[2]
)
}
}
}
Sensor.TYPE_MAGNETIC_FIELD -> {
val rotatedValues = getRotatedValues(event.values)
renderView!!.queueOnRenderThread {
GodotLib.magnetometer(
-rotatedValues!![0], -rotatedValues[1], -rotatedValues[2]
)
getRotatedValues(event.values)?.let { rotatedValues ->
renderView?.queueOnRenderThread {
GodotLib.magnetometer(
-rotatedValues[0], -rotatedValues[1], -rotatedValues[2]
)
}
}
}
Sensor.TYPE_GYROSCOPE -> {
val rotatedValues = getRotatedValues(event.values)
renderView!!.queueOnRenderThread {
GodotLib.gyroscope(
rotatedValues!![0], rotatedValues[1], rotatedValues[2]
)
getRotatedValues(event.values)?.let { rotatedValues ->
renderView?.queueOnRenderThread {
GodotLib.gyroscope(
rotatedValues[0], rotatedValues[1], rotatedValues[2]
)
}
}
}
}
Expand Down Expand Up @@ -1039,7 +1046,7 @@ class Godot(private val context: Context) : SensorEventListener {

@Keep
private fun initInputDevices() {
renderView!!.initInputDevices()
renderView?.initInputDevices()
}

@Keep
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ abstract class GodotActivity : FragmentActivity(), GodotHost {
override fun onDestroy() {
Log.v(TAG, "Destroying Godot app...")
super.onDestroy()
if (godotFragment != null) {
terminateGodotInstance(godotFragment!!.godot)

godotFragment?.let {
terminateGodotInstance(it.godot)
}
}

Expand All @@ -93,22 +94,26 @@ abstract class GodotActivity : FragmentActivity(), GodotHost {
}

private fun terminateGodotInstance(instance: Godot) {
if (godotFragment != null && instance === godotFragment!!.godot) {
Log.v(TAG, "Force quitting Godot instance")
ProcessPhoenix.forceQuit(this)
godotFragment?.let {
if (instance === it.godot) {
Log.v(TAG, "Force quitting Godot instance")
ProcessPhoenix.forceQuit(this)
}
}
}

override fun onGodotRestartRequested(instance: Godot) {
runOnUiThread {
if (godotFragment != null && instance === godotFragment!!.godot) {
// It's very hard to properly de-initialize Godot on Android to restart the game
// from scratch. Therefore, we need to kill the whole app process and relaunch it.
//
// Restarting only the activity, wouldn't be enough unless it did proper cleanup (including
// releasing and reloading native libs or resetting their state somehow and clearing static data).
Log.v(TAG, "Restarting Godot instance...")
ProcessPhoenix.triggerRebirth(this)
godotFragment?.let {
if (instance === it.godot) {
// It's very hard to properly de-initialize Godot on Android to restart the game
// from scratch. Therefore, we need to kill the whole app process and relaunch it.
//
// Restarting only the activity, wouldn't be enough unless it did proper cleanup (including
// releasing and reloading native libs or resetting their state somehow and clearing static data).
Log.v(TAG, "Restarting Godot instance...")
ProcessPhoenix.triggerRebirth(this)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ class FileAccessHandler(val context: Context) {
}

return try {
DataAccess.fileExists(storageScope, context, path!!)
path?.let {
DataAccess.fileExists(storageScope, context, it)
} ?: false
} catch (e: SecurityException) {
false
}
Expand All @@ -69,20 +71,22 @@ class FileAccessHandler(val context: Context) {
}

return try {
DataAccess.removeFile(storageScope, context, path!!)
path?.let {
DataAccess.removeFile(storageScope, context, it)
} ?: false
} catch (e: Exception) {
false
}
}

internal fun renameFile(context: Context, storageScopeIdentifier: StorageScope.Identifier, from: String?, to: String?): Boolean {
internal fun renameFile(context: Context, storageScopeIdentifier: StorageScope.Identifier, from: String, to: String): Boolean {
val storageScope = storageScopeIdentifier.identifyStorageScope(from)
if (storageScope == StorageScope.UNKNOWN) {
return false
}

return try {
DataAccess.renameFile(storageScope, context, from!!, to!!)
DataAccess.renameFile(storageScope, context, from, to)
} catch (e: Exception) {
false
}
Expand All @@ -106,16 +110,18 @@ class FileAccessHandler(val context: Context) {
return INVALID_FILE_ID
}

try {
val dataAccess = DataAccess.generateDataAccess(storageScope, context, path!!, accessFlag) ?: return INVALID_FILE_ID
return try {
path?.let {
val dataAccess = DataAccess.generateDataAccess(storageScope, context, it, accessFlag) ?: return INVALID_FILE_ID

files.put(++lastFileId, dataAccess)
return lastFileId
files.put(++lastFileId, dataAccess)
lastFileId
} ?: INVALID_FILE_ID
} catch (e: FileNotFoundException) {
return FILE_NOT_FOUND_ERROR_ID
FILE_NOT_FOUND_ERROR_ID
} catch (e: Exception) {
Log.w(TAG, "Error while opening $path", e)
return INVALID_FILE_ID
INVALID_FILE_ID
}
}

Expand Down Expand Up @@ -176,7 +182,9 @@ class FileAccessHandler(val context: Context) {
}

return try {
DataAccess.fileLastModified(storageScope, context, filepath!!)
filepath?.let {
DataAccess.fileLastModified(storageScope, context, it)
} ?: 0L
} catch (e: SecurityException) {
0L
}
Expand Down
Loading