Skip to content

Commit

Permalink
Add a (super ugly) panic screen
Browse files Browse the repository at this point in the history
  • Loading branch information
Dinnerbone authored and torokati44 committed Sep 17, 2024
1 parent fd9c1b6 commit 0319ac9
Show file tree
Hide file tree
Showing 8 changed files with 277 additions and 123 deletions.
12 changes: 1 addition & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ ruffle_video_software = { git = "https://github.com/ruffle-rs/ruffle.git", branc
ruffle_frontend_utils = { git = "https://github.com/ruffle-rs/ruffle.git", branch = "master" }

log = "0.4.22"
log-panics = { version = "2.1.0", features = ["with-backtrace"]}

# Redirect tracing to log
tracing = {version = "0.1.40", features = ["log", "log-always"]}
backtrace = "0.3.74"

url = "2.5.2"
webbrowser = "1.0.1"
Expand Down
139 changes: 72 additions & 67 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,68 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Ruffle"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:exported="true">

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".PlayerActivity"
android:exported="true"
android:configChanges="orientation|keyboardHidden|screenSize"

android:screenOrientation="user"
>
<meta-data android:name="android.app.lib_name" android:value="ruffle_android" />

<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />

<intent-filter>
<action android:name="android.intent.action.VIEW"/>

<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.OPENABLE" />

<data android:scheme="file"/>
<data android:scheme="content"/>

<data android:mimeType="application/x-shockwave-flash"/>

<data android:pathSuffix="swf" />
<data android:pathPattern="*.swf" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="*" />
<data android:pathPattern=".*\\.swf" />
</intent-filter>

</activity>
</application>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Ruffle"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:exported="true">

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".PanicActivity"
android:launchMode="singleTask"
android:exported="false">
</activity>
<activity
android:name=".PlayerActivity"
android:exported="true"
android:configChanges="orientation|keyboardHidden|screenSize"

android:screenOrientation="user"
>
<meta-data android:name="android.app.lib_name" android:value="ruffle_android" />

<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />

<intent-filter>
<action android:name="android.intent.action.VIEW"/>

<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.OPENABLE" />

<data android:scheme="file"/>
<data android:scheme="content"/>

<data android:mimeType="application/x-shockwave-flash"/>

<data android:pathSuffix="swf" />
<data android:pathPattern="*.swf" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="*" />
<data android:pathPattern=".*\\.swf" />
</intent-filter>

</activity>
</application>
</manifest>
20 changes: 20 additions & 0 deletions app/src/main/java/rs/ruffle/PanicActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package rs.ruffle

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import rs.ruffle.ui.theme.RuffleTheme

class PanicActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)

setContent {
RuffleTheme {
PanicScreen(message = intent.getStringExtra("message") ?: "Unknown")
}
}
}
}
77 changes: 77 additions & 0 deletions app/src/main/java/rs/ruffle/PanicScreen.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package rs.ruffle

import android.content.res.Configuration
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import rs.ruffle.ui.theme.RuffleTheme

@Composable
fun PanicScreen(message: String) {
Scaffold { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.fillMaxSize(),
verticalArrangement = Arrangement.Center
) {
Text(
modifier = Modifier
.fillMaxWidth()
.wrapContentSize(align = Alignment.Center),
style = MaterialTheme.typography.headlineLarge,
text = "Ruffle Panicked :("
)
SelectionContainer {
Text(
modifier = Modifier
.wrapContentSize(align = Alignment.Center)
.padding(horizontal = 8.dp, vertical = 20.dp)
.verticalScroll(rememberScrollState())
.horizontalScroll(rememberScrollState()),
text = message,
softWrap = false
)
}
}
}
}

@Preview(name = "Panic - Light", uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Panic - Dark", uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun PanicScreenPreview() {
RuffleTheme {
PanicScreen(
message = """Error: panicked at core/src/display_object/movie_clip.rs:477:9:
assertion `left == right` failed: Called replace_movie on a clip with LoaderInfo set
left: Some(LoaderInfoObject(LoaderInfoObject { ptr: 0x31b30a8 }))
right: None
at n.wbg.__wbg_new_796382978dfd4fb0 (https://unpkg.com/@ruffle-rs/ruffle/core.ruffle.90db0a0ab193ed0c601b.js:1:83857)
at ruffle_web.wasm.js_sys::Error::new::hfb561c222a4e70eb (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[12733]:0x98671a)
at ruffle_web.wasm.core::ops::function::FnOnce::call_once{{vtable.shim}}::h8a2a563fa204b611 (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[9789]:0x9164aa)
at ruffle_web.wasm.std::panicking::rust_panic_with_hook::h33fe77d38d305ca3 (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[6355]:0x8070ed)
at ruffle_web.wasm.core::panicking::panic_fmt::hde8b7aa66e2831e1 (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[9511]:0x9071fd)
at ruffle_web.wasm.core::panicking::assert_failed_inner::hc95b7725cb4077cb (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[4402]:0x73cb5e)
at ruffle_web.wasm.ruffle_core::display_object::movie_clip::MovieClip::replace_with_movie::haf940b0718ed269c (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[2052]:0x50a035)
at ruffle_web.wasm.ruffle_core::loader::Loader::movie_loader::{{closure}}::h566c935379317178 (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[1053]:0x2bc268)
at ruffle_web.wasm.<ruffle_web::navigator::WebNavigatorBackend as ruffle_core::backend::navigator::NavigatorBackend>::spawn_future::{{closure}}::h13f3540dbe40e875 (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[1520]:0x419980)
at ruffle_web.wasm.wasm_bindgen_futures::queue::Queue::new::{{closure}}::hf37247571cf9bbf7 (wasm://wasm/ruffle_web.wasm-0321683a:wasm-function[3648]:0x6ba342)"""
)
}
}
16 changes: 14 additions & 2 deletions app/src/main/java/rs/ruffle/PlayerActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import android.net.Uri
import android.os.Build
import android.os.Build.VERSION_CODES
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
Expand Down Expand Up @@ -230,6 +231,14 @@ class PlayerActivity : GameActivity() {
}

override fun onCreate(savedInstanceState: Bundle?) {
nativeInit { message ->
Log.e("ruffle", "Handling panic: $message")
startActivity(
Intent(this, PanicActivity::class.java).apply {
putExtra("message", message)
}
)
}
// When true, the app will fit inside any system UI windows.
// When false, we render behind any system UI windows.
WindowCompat.setDecorFitsSystemWindows(window, false)
Expand Down Expand Up @@ -264,11 +273,10 @@ class PlayerActivity : GameActivity() {
init {
// load the native activity
System.loadLibrary("ruffle_android")
nativeInit()
}

@JvmStatic
private external fun nativeInit()
private external fun nativeInit(crashCallback: CrashCallback)

private fun <T> gatherAllDescendantsOfType(v: View, t: Class<*>): List<T> {
val result: MutableList<T> = ArrayList()
Expand All @@ -282,4 +290,8 @@ class PlayerActivity : GameActivity() {
return result
}
}

fun interface CrashCallback {
fun onCrash(message: String)
}
}
54 changes: 26 additions & 28 deletions src/java.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,33 +172,31 @@ impl JavaInterface {
}

pub fn init(env: &mut JNIEnv, class: &JClass) {
JAVA_INTERFACE
.set(JavaInterface {
get_surface_width: env
.get_method_id(class, "getSurfaceWidth", "()I")
.expect("getSurfaceWidth must exist"),
get_surface_height: env
.get_method_id(class, "getSurfaceHeight", "()I")
.expect("getSurfaceHeight must exist"),
show_context_menu: env
.get_method_id(class, "showContextMenu", "([Ljava/lang/String;)V")
.expect("showContextMenu must exist"),
get_swf_bytes: env
.get_method_id(class, "getSwfBytes", "()[B")
.expect("getSwfBytes must exist"),
get_swf_uri: env
.get_method_id(class, "getSwfUri", "()Ljava/lang/String;")
.expect("getSwfUri must exist"),
get_trace_output: env
.get_method_id(class, "getTraceOutput", "()Ljava/lang/String;")
.expect("getTraceOutput must exist"),
get_loc_in_window: env
.get_method_id(class, "getLocInWindow", "()[I")
.expect("getLocInWindow must exist"),
get_android_data_storage_dir: env
.get_method_id(class, "getAndroidDataStorageDir", "()Ljava/lang/String;")
.expect("getAndroidDataStorageDir must exist"),
})
.unwrap_or_else(|_| panic!("Init cannot be called more than once!"))
let _ = JAVA_INTERFACE.set(JavaInterface {
get_surface_width: env
.get_method_id(class, "getSurfaceWidth", "()I")
.expect("getSurfaceWidth must exist"),
get_surface_height: env
.get_method_id(class, "getSurfaceHeight", "()I")
.expect("getSurfaceHeight must exist"),
show_context_menu: env
.get_method_id(class, "showContextMenu", "([Ljava/lang/String;)V")
.expect("showContextMenu must exist"),
get_swf_bytes: env
.get_method_id(class, "getSwfBytes", "()[B")
.expect("getSwfBytes must exist"),
get_swf_uri: env
.get_method_id(class, "getSwfUri", "()Ljava/lang/String;")
.expect("getSwfUri must exist"),
get_trace_output: env
.get_method_id(class, "getTraceOutput", "()Ljava/lang/String;")
.expect("getTraceOutput must exist"),
get_loc_in_window: env
.get_method_id(class, "getLocInWindow", "()[I")
.expect("getLocInWindow must exist"),
get_android_data_storage_dir: env
.get_method_id(class, "getAndroidDataStorageDir", "()Ljava/lang/String;")
.expect("getAndroidDataStorageDir must exist"),
});
}
}
Loading

0 comments on commit 0319ac9

Please sign in to comment.