android: fix exit on background
This commit is contained in:
parent
f95645ea81
commit
23712ca361
5 changed files with 83 additions and 36 deletions
|
@ -28,8 +28,13 @@ public class BackgroundService extends Service {
|
||||||
NotificationManager manager = getSystemService(NotificationManager.class);
|
NotificationManager manager = getSystemService(NotificationManager.class);
|
||||||
manager.notify(SYNC_STATUS_NOTIFICATION_ID, mNotificationBuilder.build());
|
manager.notify(SYNC_STATUS_NOTIFICATION_ID, mNotificationBuilder.build());
|
||||||
|
|
||||||
|
if (exitAppAfterNodeStop()) {
|
||||||
|
sendBroadcast(new Intent(MainActivity.FINISH_ACTIVITY_ACTION));
|
||||||
|
mStopped = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mStopped) {
|
if (!mStopped) {
|
||||||
mHandler.postDelayed(this, 500);
|
mHandler.postDelayed(this, 300);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -127,4 +132,5 @@ public class BackgroundService extends Service {
|
||||||
|
|
||||||
private native String getSyncStatusText();
|
private native String getSyncStatusText();
|
||||||
private native String getSyncTitle();
|
private native String getSyncTitle();
|
||||||
|
private native boolean exitAppAfterNodeStop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package mw.gri.android;
|
package mw.gri.android;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.hardware.SensorManager;
|
import android.hardware.SensorManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
@ -13,10 +17,21 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
public class MainActivity extends GameActivity {
|
public class MainActivity extends GameActivity {
|
||||||
|
|
||||||
|
public static String FINISH_ACTIVITY_ACTION = "MainActivity.finish";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("grim");
|
System.loadLibrary("grim");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context ctx, Intent i) {
|
||||||
|
if (i.getAction().equals(FINISH_ACTIVITY_ACTION)) {
|
||||||
|
onExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
// Setup HOME environment variable for native code configurations.
|
// Setup HOME environment variable for native code configurations.
|
||||||
|
@ -40,6 +55,9 @@ public class MainActivity extends GameActivity {
|
||||||
}
|
}
|
||||||
onDisplayCutoutsChanged(Utils.getDisplayCutouts(this));
|
onDisplayCutoutsChanged(Utils.getDisplayCutouts(this));
|
||||||
|
|
||||||
|
// Register receiver to finish activity from the BackgroundService.
|
||||||
|
registerReceiver(mBroadcastReceiver, new IntentFilter(FINISH_ACTIVITY_ACTION));
|
||||||
|
|
||||||
// Start notification service.
|
// Start notification service.
|
||||||
BackgroundService.start(this);
|
BackgroundService.start(this);
|
||||||
}
|
}
|
||||||
|
@ -62,10 +80,12 @@ public class MainActivity extends GameActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
|
unregisterReceiver(mBroadcastReceiver);
|
||||||
|
|
||||||
if (!mManualExit) {
|
if (!mManualExit) {
|
||||||
onTermination();
|
onTermination();
|
||||||
}
|
}
|
||||||
// Temp fix: kill process after 3 seconds to prevent app hanging at next launch
|
// Temp fix: kill process after 3 seconds to prevent app hanging at next launch.
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(3000);
|
Thread.sleep(3000);
|
||||||
|
@ -80,8 +100,12 @@ public class MainActivity extends GameActivity {
|
||||||
mActivityDestroyed.set(true);
|
mActivityDestroyed.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from native code
|
// Called from native code.
|
||||||
public void onExit() {
|
public void onExit() {
|
||||||
|
// Return if exit was already requested.
|
||||||
|
if (mManualExit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
mManualExit = true;
|
mManualExit = true;
|
||||||
BackgroundService.stop(this);
|
BackgroundService.stop(this);
|
||||||
finish();
|
finish();
|
||||||
|
|
|
@ -15,9 +15,10 @@
|
||||||
use egui::{Context, Stroke};
|
use egui::{Context, Stroke};
|
||||||
use egui::os::OperatingSystem;
|
use egui::os::OperatingSystem;
|
||||||
|
|
||||||
use crate::gui::Colors;
|
use crate::gui::{Colors, Navigator};
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
use crate::gui::screens::Root;
|
use crate::gui::screens::Root;
|
||||||
|
use crate::node::Node;
|
||||||
|
|
||||||
pub struct PlatformApp<Platform> {
|
pub struct PlatformApp<Platform> {
|
||||||
pub(crate) app: App,
|
pub(crate) app: App,
|
||||||
|
@ -132,3 +133,28 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn Java_mw_gri_android_MainActivity_onBackButtonPress(
|
||||||
|
_env: jni::JNIEnv,
|
||||||
|
_class: jni::objects::JObject,
|
||||||
|
_activity: jni::objects::JObject,
|
||||||
|
) {
|
||||||
|
Navigator::back();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[no_mangle]
|
||||||
|
/// Calling on unexpected Android application termination (removal from recent apps).
|
||||||
|
pub extern "C" fn Java_mw_gri_android_MainActivity_onTermination(
|
||||||
|
_env: jni::JNIEnv,
|
||||||
|
_class: jni::objects::JObject,
|
||||||
|
_activity: jni::objects::JObject,
|
||||||
|
) {
|
||||||
|
Node::stop(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,12 +80,9 @@ impl Root {
|
||||||
}
|
}
|
||||||
ui.add_space(16.0);
|
ui.add_space(16.0);
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
Spinner::new().size(48.0).color(Colors::GRAY).ui(ui);
|
Spinner::new().size(48.0).color(Colors::GOLD).ui(ui);
|
||||||
ui.add_space(12.0);
|
ui.add_space(12.0);
|
||||||
ui.label(RichText::new(t!("sync_status.shutdown"))
|
ui.label(t!("sync_status.shutdown"));
|
||||||
.size(17.0)
|
|
||||||
.color(Colors::TEXT)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
ui.add_space(10.0);
|
ui.add_space(10.0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -103,7 +100,7 @@ impl Root {
|
||||||
App::exit(frame, cb);
|
App::exit(frame, cb);
|
||||||
modal.close();
|
modal.close();
|
||||||
} else {
|
} else {
|
||||||
Node::stop();
|
Node::stop(true);
|
||||||
modal.disable_closing();
|
modal.disable_closing();
|
||||||
self.show_exit_progress = true;
|
self.show_exit_progress = true;
|
||||||
}
|
}
|
||||||
|
@ -147,15 +144,3 @@ impl Root {
|
||||||
(is_panel_open, panel_width)
|
(is_panel_open, panel_width)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn Java_mw_gri_android_MainActivity_onBackButtonPress(
|
|
||||||
_env: jni::JNIEnv,
|
|
||||||
_class: jni::objects::JObject,
|
|
||||||
_activity: jni::objects::JObject,
|
|
||||||
) {
|
|
||||||
Navigator::back();
|
|
||||||
}
|
|
|
@ -25,7 +25,7 @@ use grin_config::config;
|
||||||
use grin_core::global;
|
use grin_core::global;
|
||||||
use grin_core::global::ChainTypes;
|
use grin_core::global::ChainTypes;
|
||||||
use grin_servers::{Server, ServerStats};
|
use grin_servers::{Server, ServerStats};
|
||||||
use jni::sys::jstring;
|
use jni::sys::{jboolean, jstring};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
|
@ -46,6 +46,8 @@ pub struct Node {
|
||||||
restart_needed: AtomicBool,
|
restart_needed: AtomicBool,
|
||||||
/// Thread flag to stop the server.
|
/// Thread flag to stop the server.
|
||||||
stop_needed: AtomicBool,
|
stop_needed: AtomicBool,
|
||||||
|
/// Flag to check if app exit is needed after server stop.
|
||||||
|
exit_after_stop: AtomicBool
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Node {
|
impl Default for Node {
|
||||||
|
@ -56,14 +58,16 @@ impl Default for Node {
|
||||||
starting: AtomicBool::new(false),
|
starting: AtomicBool::new(false),
|
||||||
restart_needed: AtomicBool::new(false),
|
restart_needed: AtomicBool::new(false),
|
||||||
stop_needed: AtomicBool::new(false),
|
stop_needed: AtomicBool::new(false),
|
||||||
|
exit_after_stop: AtomicBool::new(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
/// Stop the [`Server`].
|
/// Stop the [`Server`] and setup exit flag after if needed.
|
||||||
pub fn stop() {
|
pub fn stop(exit_after_stop: bool) {
|
||||||
NODE_STATE.stop_needed.store(true, Ordering::Relaxed);
|
NODE_STATE.stop_needed.store(true, Ordering::Relaxed);
|
||||||
|
NODE_STATE.exit_after_stop.store(exit_after_stop, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start [`Server`] with provided chain type.
|
/// Start [`Server`] with provided chain type.
|
||||||
|
@ -190,14 +194,14 @@ impl Node {
|
||||||
|
|
||||||
/// Get synchronization status i18n text.
|
/// Get synchronization status i18n text.
|
||||||
pub fn get_sync_status_text() -> String {
|
pub fn get_sync_status_text() -> String {
|
||||||
if Node::is_starting() {
|
|
||||||
return t!("sync_status.initial")
|
|
||||||
};
|
|
||||||
|
|
||||||
if Node::is_stopping() {
|
if Node::is_stopping() {
|
||||||
return t!("sync_status.shutdown")
|
return t!("sync_status.shutdown")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if Node::is_starting() {
|
||||||
|
return t!("sync_status.initial")
|
||||||
|
};
|
||||||
|
|
||||||
if Node::is_restarting() {
|
if Node::is_restarting() {
|
||||||
return t!("sync_status.server_restarting")
|
return t!("sync_status.server_restarting")
|
||||||
}
|
}
|
||||||
|
@ -440,11 +444,13 @@ pub extern "C" fn Java_mw_gri_android_BackgroundService_getSyncTitle(
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
/// Calling on unexpected Android application termination (removal from recent apps).
|
/// Check if app exit is needed after node stop.
|
||||||
pub extern "C" fn Java_mw_gri_android_MainActivity_onTermination(
|
pub extern "C" fn Java_mw_gri_android_BackgroundService_exitAppAfterNodeStop(
|
||||||
_env: jni::JNIEnv,
|
_env: jni::JNIEnv,
|
||||||
_class: jni::objects::JObject,
|
_class: jni::objects::JObject,
|
||||||
_activity: jni::objects::JObject,
|
_activity: jni::objects::JObject,
|
||||||
) {
|
) -> jboolean {
|
||||||
Node::stop();
|
let exit_after_stop = NODE_STATE.exit_after_stop.load(Ordering::Relaxed);
|
||||||
|
let is_app_exit_needed = !Node::is_running() && exit_after_stop;
|
||||||
|
return is_app_exit_needed as jboolean;
|
||||||
}
|
}
|
Loading…
Reference in a new issue