diff --git a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java index b52f4ac08e..70911d855a 100644 --- a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java +++ b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2023 jMonkeyEngine + * Copyright (c) 2009-2025 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -247,10 +247,19 @@ protected void deinitInThread() { } listener.destroy(); - + // releases the view holder from the Android Input Resources + // releasing the view enables the context instance to be + // reclaimed by the GC. + // if not released; it leads to a weak reference leak + // disabling the destruction of the Context View Holder. + androidInput.setView(null); + + // nullifying the references + // signals their memory to be reclaimed listener = null; renderer = null; timer = null; + androidInput = null; // do android specific cleaning here logger.fine("Display destroyed."); diff --git a/jme3-android/src/main/java/com/jme3/view/surfaceview/JmeSurfaceView.java b/jme3-android/src/main/java/com/jme3/view/surfaceview/JmeSurfaceView.java index d364ab0923..67d73f4b5c 100644 --- a/jme3-android/src/main/java/com/jme3/view/surfaceview/JmeSurfaceView.java +++ b/jme3-android/src/main/java/com/jme3/view/surfaceview/JmeSurfaceView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2022 jMonkeyEngine + * Copyright (c) 2009-2025 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -239,11 +239,7 @@ public void startRenderer(int delayMillis) { } private void removeGLSurfaceView() { - ((Activity) getContext()).runOnUiThread(() -> { - if (glSurfaceView != null) { - JmeSurfaceView.this.removeView(glSurfaceView); - } - }); + ((Activity) getContext()).runOnUiThread(() -> JmeSurfaceView.this.removeView(glSurfaceView)); } @Override @@ -265,19 +261,34 @@ public void handleError(String errorMsg, Throwable throwable) { public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { switch (event) { case ON_DESTROY: - /*destroy only if the policy flag is enabled*/ - if (destructionPolicy == DestructionPolicy.DESTROY_WHEN_FINISH) { - legacyApplication.stop(!isGLThreadPaused()); - } + // activity is off the foreground stack + // activity is being destructed completely as a result of Activity#finish() + // this is a killable automata state! + jmeSurfaceViewLogger.log(Level.INFO, "Hosting Activity has been destructed."); break; case ON_PAUSE: - loseFocus(); + // activity is still on the foreground stack but not + // on the topmost level or before transition to stopped/hidden or destroyed state + // as a result of dispatch to Activity#finish() + // activity is no longer visible and is out of foreground + if (((Activity) getContext()).isFinishing()) { + if (destructionPolicy == DestructionPolicy.DESTROY_WHEN_FINISH) { + legacyApplication.stop(!isGLThreadPaused()); + } else if (destructionPolicy == DestructionPolicy.KEEP_WHEN_FINISH) { + jmeSurfaceViewLogger.log(Level.INFO, "Context stops, but game is still running."); + } + } else { + loseFocus(); + } break; case ON_RESUME: + // activity is back to the topmost of the + // foreground stack gainFocus(); break; case ON_STOP: - jmeSurfaceViewLogger.log(Level.INFO, "Context stops, but game is still running"); + // activity is out off the foreground stack or being destructed by a finishing dispatch + // this is a killable automata state! break; } } @@ -404,13 +415,13 @@ public void loseFocus() { @Override public void destroy() { - /*skip the destroy block if the invoking instance is null*/ - if (legacyApplication == null) { - return; + if (glSurfaceView != null) { + removeGLSurfaceView(); + } + if (legacyApplication != null) { + legacyApplication.destroy(); } - removeGLSurfaceView(); - legacyApplication.destroy(); - /*help the Dalvik Garbage collector to destruct the pointers, by making them nullptr*/ + /*help the Dalvik Garbage collector to destruct the objects, by releasing their references*/ /*context instances*/ legacyApplication = null; appSettings = null; @@ -430,10 +441,10 @@ public void destroy() { onRendererCompleted = null; onExceptionThrown = null; onLayoutDrawn = null; - /*nullifying the static memory (pushing zero to registers to prepare for a clean use)*/ GameState.setLegacyApplication(null); GameState.setFirstUpdatePassed(false); - jmeSurfaceViewLogger.log(Level.INFO, "Context and Game have been destructed"); + JmeAndroidSystem.setView(null); + jmeSurfaceViewLogger.log(Level.INFO, "Context and Game have been destructed."); } @Override @@ -516,11 +527,13 @@ public void bindAppStateToActivityLifeCycle(final boolean condition) { /*register this Ui Component as an observer to the context of jmeSurfaceView only if this context is a LifeCycleOwner*/ if (getContext() instanceof LifecycleOwner) { ((LifecycleOwner) getContext()).getLifecycle().addObserver(JmeSurfaceView.this); + jmeSurfaceViewLogger.log(Level.INFO, "Command binding SurfaceView to the Activity Lifecycle."); } } else { /*un-register this Ui Component as an observer to the context of jmeSurfaceView only if this context is a LifeCycleOwner*/ if (getContext() instanceof LifecycleOwner) { ((LifecycleOwner) getContext()).getLifecycle().removeObserver(JmeSurfaceView.this); + jmeSurfaceViewLogger.log(Level.INFO, "Command removing SurfaceView from the Activity Lifecycle."); } } } @@ -917,7 +930,7 @@ public void setShowErrorDialog(boolean showErrorDialog) { } /** - * Determines whether the app context would be destructed + * Determines whether the app context would be destructed as a result of dispatching {@link Activity#finish()} * with the holder activity context in case of {@link DestructionPolicy#DESTROY_WHEN_FINISH} or be * spared for a second use in case of {@link DestructionPolicy#KEEP_WHEN_FINISH}. * Default value is : {@link DestructionPolicy#DESTROY_WHEN_FINISH}. @@ -926,12 +939,14 @@ public void setShowErrorDialog(boolean showErrorDialog) { */ public enum DestructionPolicy { /** - * Finishes the game context with the activity context (ignores the static memory {@link GameState#legacyApplication}). + * Finishes the game context with the activity context (ignores the static memory {@link GameState#legacyApplication}) + * as a result of dispatching {@link Activity#finish()}. */ DESTROY_WHEN_FINISH, /** * Spares the game context inside a static memory {@link GameState#legacyApplication} - * when the activity context is destroyed, but the app stills in the background. + * when the activity context is destroyed dispatching {@link Activity#finish()}, but the {@link android.app.Application} + * stills in the background. */ KEEP_WHEN_FINISH } diff --git a/jme3-core/src/main/java/com/jme3/anim/tween/action/BlendSpace.java b/jme3-core/src/main/java/com/jme3/anim/tween/action/BlendSpace.java index a88be7529c..17b66f8b07 100644 --- a/jme3-core/src/main/java/com/jme3/anim/tween/action/BlendSpace.java +++ b/jme3-core/src/main/java/com/jme3/anim/tween/action/BlendSpace.java @@ -1,10 +1,95 @@ +/* + * Copyright (c) 2009-2025 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.jme3.anim.tween.action; +/** + * A provider interface which provides a value {@link BlendSpace#getWeight()} to control the blending between 2 successive actions in a {@link BlendAction}. + * The blending weight is a read-only value, and it can be manipulated using the arbitrary value {@link BlendSpace#setValue(float)} during the application runtime. + * + *
+ * Notes about the blending action and its relations with the blending weight: + *
+ * Different blending weight case scenarios managed by {@link BlendAction} internally: + *
+ * Notes about the blending weight value: + *