Browse Source

Add new events and accompanying logic to notify when the app is paused and resumed on Android devices.

fhuya 6 years ago
parent
commit
a7712cc9e4

+ 2 - 0
core/os/main_loop.h

@@ -60,6 +60,8 @@ public:
 		NOTIFICATION_WM_ABOUT = 1011,
 		NOTIFICATION_CRASH = 1012,
 		NOTIFICATION_OS_IME_UPDATE = 1013,
+		NOTIFICATION_APP_RESUMED = 1014,
+		NOTIFICATION_APP_PAUSED = 1015,
 	};
 
 	virtual void input_event(const Ref<InputEvent> &p_event);

+ 8 - 0
doc/classes/MainLoop.xml

@@ -215,5 +215,13 @@
 			Notification received from the OS when an update of the Input Method Engine occurs (e.g. change of IME cursor position or composition string).
 			Specific to the macOS platform.
 		</constant>
+		<constant name="NOTIFICATION_APP_RESUMED" value="1014">
+			Notification received from the OS when the app is resumed.
+			Specific to the Android platform.
+		</constant>
+		<constant name="NOTIFICATION_APP_PAUSED" value="1015">
+			Notification received from the OS when the app is paused.
+			Specific to the Android platform.
+		</constant>
 	</constants>
 </class>

+ 8 - 0
doc/classes/Node.xml

@@ -962,6 +962,14 @@
 			Notification received from the OS when an update of the Input Method Engine occurs (e.g. change of IME cursor position or composition string).
 			Specific to the macOS platform.
 		</constant>
+		<constant name="NOTIFICATION_APP_RESUMED" value="1014">
+			Notification received from the OS when the app is resumed.
+			Specific to the Android platform.
+		</constant>
+		<constant name="NOTIFICATION_APP_PAUSED" value="1015">
+			Notification received from the OS when the app is paused.
+			Specific to the Android platform.
+		</constant>
 		<constant name="PAUSE_MODE_INHERIT" value="0" enum="PauseMode">
 			Inherits pause mode from the node's parent. For the root node, it is equivalent to [constant PAUSE_MODE_STOP]. Default.
 		</constant>

+ 3 - 14
platform/android/java/lib/src/org/godotengine/godot/Godot.java

@@ -669,12 +669,7 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
 			return;
 		}
 		mView.onPause();
-		mView.queueEvent(new Runnable() {
-			@Override
-			public void run() {
-				GodotLib.focusout();
-			}
-		});
+
 		mSensorManager.unregisterListener(this);
 
 		for (int i = 0; i < singleton_count; i++) {
@@ -703,6 +698,7 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
 	@Override
 	protected void onResume() {
 		super.onResume();
+		activityResumed = true;
 		if (!godot_initialized) {
 			if (null != mDownloaderClientStub) {
 				mDownloaderClientStub.connect(this);
@@ -711,12 +707,7 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
 		}
 
 		mView.onResume();
-		mView.queueEvent(new Runnable() {
-			@Override
-			public void run() {
-				GodotLib.focusin();
-			}
-		});
+
 		mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
 		mSensorManager.registerListener(this, mGravity, SensorManager.SENSOR_DELAY_GAME);
 		mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
@@ -737,8 +728,6 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
 
 			singletons[i].onMainResume();
 		}
-
-		activityResumed = true;
 	}
 
 	public void UiChangeListener() {

+ 12 - 0
platform/android/java/lib/src/org/godotengine/godot/GodotLib.java

@@ -211,4 +211,16 @@ public class GodotLib {
 	 * Invoked on the GL thread to configure the height of the virtual keyboard.
 	 */
 	public static native void setVirtualKeyboardHeight(int p_height);
+
+	/**
+	 * Invoked on the GL thread when the {@link GodotRenderer} has been resumed.
+	 * @see GodotRenderer#onActivityResumed()
+	 */
+	public static native void onRendererResumed();
+
+	/**
+	 * Invoked on the GL thread when the {@link GodotRenderer} has been paused.
+	 * @see GodotRenderer#onActivityPaused()
+	 */
+	public static native void onRendererPaused();
 }

+ 17 - 0
platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java

@@ -40,7 +40,14 @@ import org.godotengine.godot.utils.GLUtils;
  */
 class GodotRenderer implements GLSurfaceView.Renderer {
 
+	private boolean activityJustResumed = false;
+
 	public void onDrawFrame(GL10 gl) {
+		if (activityJustResumed) {
+			GodotLib.onRendererResumed();
+			activityJustResumed = false;
+		}
+
 		GodotLib.step();
 		for (int i = 0; i < Godot.singleton_count; i++) {
 			Godot.singletons[i].onGLDrawFrame(gl);
@@ -58,4 +65,14 @@ class GodotRenderer implements GLSurfaceView.Renderer {
 	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
 		GodotLib.newcontext(GLUtils.use_32);
 	}
+
+	void onActivityResumed() {
+		// We defer invoking GodotLib.onRendererResumed() until the first draw frame call.
+		// This ensures we have a valid GL context and surface when we do so.
+		activityJustResumed = true;
+	}
+
+	void onActivityPaused() {
+		GodotLib.onRendererPaused();
+	}
 }

+ 31 - 1
platform/android/java/lib/src/org/godotengine/godot/GodotView.java

@@ -68,6 +68,7 @@ public class GodotView extends GLSurfaceView {
 
 	private final Godot activity;
 	private final GodotInputHandler inputHandler;
+	private final GodotRenderer godotRenderer;
 
 	public GodotView(Godot activity, XRMode xrMode, boolean p_use_gl3, boolean p_use_32_bits, boolean p_use_debug_opengl) {
 		super(activity);
@@ -77,6 +78,7 @@ public class GodotView extends GLSurfaceView {
 
 		this.activity = activity;
 		this.inputHandler = new GodotInputHandler(this);
+		this.godotRenderer = new GodotRenderer();
 		init(xrMode, false, 16, 0);
 	}
 
@@ -161,10 +163,38 @@ public class GodotView extends GLSurfaceView {
 		}
 
 		/* Set the renderer responsible for frame rendering */
-		setRenderer(new GodotRenderer());
+		setRenderer(godotRenderer);
 	}
 
 	public void onBackPressed() {
 		activity.onBackPressed();
 	}
+
+	@Override
+	public void onResume() {
+		super.onResume();
+
+		queueEvent(new Runnable() {
+			@Override
+			public void run() {
+				// Resume the renderer
+				godotRenderer.onActivityResumed();
+				GodotLib.focusin();
+			}
+		});
+	}
+
+	@Override
+	public void onPause() {
+		super.onPause();
+
+		queueEvent(new Runnable() {
+			@Override
+			public void run() {
+				GodotLib.focusout();
+				// Pause the renderer
+				godotRenderer.onActivityPaused();
+			}
+		});
+	}
 }

+ 18 - 0
platform/android/java_godot_lib_jni.cpp

@@ -1387,3 +1387,21 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResu
 		AudioDriver::get_singleton()->capture_start();
 	}
 }
+
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz) {
+	if (step == 0)
+		return;
+
+	if (os_android->get_main_loop()) {
+		os_android->get_main_loop()->notification(MainLoop::NOTIFICATION_APP_RESUMED);
+	}
+}
+
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIEnv *env, jclass clazz) {
+	if (step == 0)
+		return;
+
+	if (os_android->get_main_loop()) {
+		os_android->get_main_loop()->notification(MainLoop::NOTIFICATION_APP_PAUSED);
+	}
+}

+ 2 - 0
platform/android/java_godot_lib_jni.h

@@ -64,6 +64,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *en
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jobject p_obj, jint ID, jstring method, jobjectArray params);
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jobject obj, jint p_height);
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jobject p_obj, jstring p_permission, jboolean p_result);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIEnv *env, jclass clazz);
 }
 
 #endif /* !JAVA_GODOT_LIB_JNI_H */

+ 2 - 0
scene/main/node.cpp

@@ -2861,6 +2861,8 @@ void Node::_bind_methods() {
 	BIND_CONSTANT(NOTIFICATION_WM_ABOUT);
 	BIND_CONSTANT(NOTIFICATION_CRASH);
 	BIND_CONSTANT(NOTIFICATION_OS_IME_UPDATE);
+	BIND_CONSTANT(NOTIFICATION_APP_RESUMED);
+	BIND_CONSTANT(NOTIFICATION_APP_PAUSED);
 
 	BIND_ENUM_CONSTANT(PAUSE_MODE_INHERIT);
 	BIND_ENUM_CONSTANT(PAUSE_MODE_STOP);

+ 3 - 1
scene/main/node.h

@@ -250,7 +250,9 @@ public:
 		NOTIFICATION_TRANSLATION_CHANGED = MainLoop::NOTIFICATION_TRANSLATION_CHANGED,
 		NOTIFICATION_WM_ABOUT = MainLoop::NOTIFICATION_WM_ABOUT,
 		NOTIFICATION_CRASH = MainLoop::NOTIFICATION_CRASH,
-		NOTIFICATION_OS_IME_UPDATE = MainLoop::NOTIFICATION_OS_IME_UPDATE
+		NOTIFICATION_OS_IME_UPDATE = MainLoop::NOTIFICATION_OS_IME_UPDATE,
+		NOTIFICATION_APP_RESUMED = MainLoop::NOTIFICATION_APP_RESUMED,
+		NOTIFICATION_APP_PAUSED = MainLoop::NOTIFICATION_APP_PAUSED
 
 	};
 

+ 17 - 13
scene/main/scene_tree.cpp

@@ -630,6 +630,7 @@ void SceneTree::_notification(int p_notification) {
 				break;
 			}
 		} break;
+
 		case NOTIFICATION_WM_GO_BACK_REQUEST: {
 
 			get_root()->propagate_notification(p_notification);
@@ -639,28 +640,23 @@ void SceneTree::_notification(int p_notification) {
 				break;
 			}
 		} break;
-		case NOTIFICATION_OS_MEMORY_WARNING:
-		case NOTIFICATION_OS_IME_UPDATE:
-		case NOTIFICATION_WM_MOUSE_ENTER:
-		case NOTIFICATION_WM_MOUSE_EXIT:
-		case NOTIFICATION_WM_FOCUS_IN:
-		case NOTIFICATION_WM_FOCUS_OUT:
-		case NOTIFICATION_WM_ABOUT: {
 
-			if (p_notification == NOTIFICATION_WM_FOCUS_IN) {
-				InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
-				if (id) {
-					id->ensure_touch_mouse_raised();
-				}
+		case NOTIFICATION_WM_FOCUS_IN: {
+
+			InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+			if (id) {
+				id->ensure_touch_mouse_raised();
 			}
 
 			get_root()->propagate_notification(p_notification);
 		} break;
+
 		case NOTIFICATION_TRANSLATION_CHANGED: {
 			if (!Engine::get_singleton()->is_editor_hint()) {
 				get_root()->propagate_notification(p_notification);
 			}
 		} break;
+
 		case NOTIFICATION_WM_UNFOCUS_REQUEST: {
 
 			notify_group_flags(GROUP_CALL_REALTIME | GROUP_CALL_MULTILEVEL, "input", NOTIFICATION_WM_UNFOCUS_REQUEST);
@@ -669,7 +665,15 @@ void SceneTree::_notification(int p_notification) {
 
 		} break;
 
-		case NOTIFICATION_CRASH: {
+		case NOTIFICATION_OS_MEMORY_WARNING:
+		case NOTIFICATION_OS_IME_UPDATE:
+		case NOTIFICATION_WM_MOUSE_ENTER:
+		case NOTIFICATION_WM_MOUSE_EXIT:
+		case NOTIFICATION_WM_FOCUS_OUT:
+		case NOTIFICATION_WM_ABOUT:
+		case NOTIFICATION_CRASH:
+		case NOTIFICATION_APP_RESUMED:
+		case NOTIFICATION_APP_PAUSED: {
 
 			get_root()->propagate_notification(p_notification);
 		} break;