[Solved] Need help: Implementation to android DreamService failed: Rejecting re-init on previously-failed class java.lang.Class

Hi, guys
I’m trying to write a android screen-saver with Android/DreamService.
I tried to build my own DreamService extension from codes of JME/AndroidHarness .
below is my implementation of Android/DreamService:

public class MyService extends DreamService implements TouchListener, SystemListener {

    protected final static Logger logger = Logger.getLogger(MyService.class.getName());
    /**
     * The application class to start
     */
    protected String appClass = "AnnoCore";
    /**
     * The jme3 application object
     */
    protected LegacyApplication app = null;

    /**
     * Sets the desired RGB size for the surfaceview.  16 = RGB565, 24 = RGB888.
     * (default = 24)
     */
    protected int eglBitsPerPixel = 24;

    /**
     * Sets the desired number of Alpha bits for the surfaceview.  This affects
     * how the surfaceview is able to display Android views that are located
     * under the surfaceview jME uses to render the scenegraph.
     * 0 = Opaque surfaceview background (fastest)
     * 1->7 = Transparent surfaceview background
     * 8 or higher = Translucent surfaceview background
     * (default = 0)
     */
    protected int eglAlphaBits = 0;

    /**
     * The number of depth bits specifies the precision of the depth buffer.
     * (default = 16)
     */
    protected int eglDepthBits = 16;

    /**
     * Sets the number of samples to use for multisampling.<br>
     * Leave 0 (default) to disable multisampling.<br>
     * Set to 2 or 4 to enable multisampling.
     */
    protected int eglSamples = 0;

    /**
     * Set the number of stencil bits.
     * (default = 0)
     */
    protected int eglStencilBits = 0;

    /**
     * Set the desired frame rate.  If frameRate higher than 0, the application
     * will be capped at the desired frame rate.
     * (default = -1, no frame rate cap)
     */
    protected int frameRate = -1;

    /**
     * Sets the type of Audio Renderer to be used.
     * <p>
     * Android MediaPlayer / SoundPool can be used on all
     * supported Android platform versions (2.2+)<br>
     * OpenAL Soft uses an OpenSL backend and is only supported on Android
     * versions 2.3+.
     * <p>
     * Only use ANDROID_ static strings found in AppSettings
     *
     */
    protected String audioRendererType = AppSettings.ANDROID_OPENAL_SOFT;

    /**
     * If true Android Sensors are used as simulated Joysticks. Users can use the
     * Android sensor feedback through the RawInputListener or by registering
     * JoyAxisTriggers.
     */
    protected boolean joystickEventsEnabled = false;
    /**
     * If true KeyEvents are generated from TouchEvents
     */
    protected boolean keyEventsEnabled = true;
    /**
     * If true MouseEvents are generated from TouchEvents
     */
    protected boolean mouseEventsEnabled = true;
    /**
     * Flip X axis
     */
    protected boolean mouseEventsInvertX = false;
    /**
     * Flip Y axis
     */
    protected boolean mouseEventsInvertY = false;
    /**
     * if true finish this activity when the jme app is stopped
     */
    protected boolean finishOnAppStop = true;
    /**
     * set to false if you don't want the harness to handle the exit hook
     */
    protected boolean handleExitHook = true;
    /**
     * Title of the exit dialog, default is "Do you want to exit?"
     */
    protected String exitDialogTitle = "Do you want to exit?";
    /**
     * Message of the exit dialog, default is "Use your home key to bring this
     * app into the background or exit to terminate it."
     */
    protected String exitDialogMessage = "Use your home key to bring this app into the background or exit to terminate it.";
    /**
     * Set the screen window mode. If screenFullSize is true, then the
     * notification bar and title bar are removed and the screen covers the
     * entire display. If screenFullSize is false, then the notification bar
     * remains visible if screenShowTitle is true while screenFullScreen is
     * false, then the title bar is also displayed under the notification bar.
     */
    protected boolean screenFullScreen = true;
    /**
     * if screenShowTitle is true while screenFullScreen is false, then the
     * title bar is also displayed under the notification bar
     */
    protected boolean screenShowTitle = true;
    /**
     * Splash Screen picture Resource ID. If a Splash Screen is desired, set
     * splashPicID to the value of the Resource ID (i.e. R.drawable.picname). If
     * splashPicID = 0, then no splash screen will be displayed.
     */
    protected int splashPicID = 0;


    protected OGLESContext ctx;
    protected GLSurfaceView view = null;
    protected boolean isGLThreadPaused = true;
    protected ImageView splashImageView = null;
    protected FrameLayout frameLayout = null;
    final private String ESCAPE_EVENT = "TouchEscape";
    private boolean firstDrawFrame = true;
    private boolean inConfigChange = false;



    @Override
    @SuppressWarnings("unchecked")
    public void onAttachedToWindow() {
        initializeLogHandler();
        logger.fine("onCreate");
        super.onCreate();
        //requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);

        // Discover the screen resolution
        //TODO try to find a better way to get a hand on the resolution
        WindowManager wind = this.getWindowManager();
        Display disp = wind.getDefaultDisplay();
        Log.d("Daydream", "Resolution from Window, width:" + disp.getWidth() + ", height: " + disp.getHeight());

        // Create Settings
        logger.log(Level.FINE, "Creating settings");
        AppSettings settings = new AppSettings(true);
        settings.setEmulateMouse(mouseEventsEnabled);
        settings.setEmulateMouseFlipAxis(mouseEventsInvertX, mouseEventsInvertY);
        settings.setUseJoysticks(false);
        settings.setEmulateKeyboard(false);

        settings.setBitsPerPixel(eglBitsPerPixel);
        settings.setAlphaBits(eglAlphaBits);
        settings.setDepthBits(eglDepthBits);
        settings.setSamples(eglSamples);
        settings.setStencilBits(eglStencilBits);

        settings.setResolution(disp.getWidth(), disp.getHeight());
        settings.setAudioRenderer(audioRendererType);

        settings.setFrameRate(frameRate);

        // Create application instance
        try {
            if (app == null) {
                Class clazz = Class.forName(appClass);
                app = (LegacyApplication) clazz.getDeclaredConstructor().newInstance();
            }
            app.setSettings(settings);
            app.start();
        } catch (Exception ex) {
            handleError("Class " + appClass + " init failed", ex);
            setContentView(new TextView(this));
        }


        ctx = (OGLESContext) app.getContext();
        if(ctx==null){
            logger.severe("NULLLLL~~~~~~~~~~");
        }
        view = ctx.createView(this);
        // store the glSurfaceView in JmeAndroidSystem for future use
        JmeAndroidSystem.setView(view);
        // AndroidHarness wraps the app as a SystemListener.
        ctx.setSystemListener(this);
        layoutDisplay();
    }

    @Override
    public void onDreamingStarted(){
        super.onDreamingStarted();
        gainFocus();
    }
    @Override
    public void onDreamingStopped(){
        super.onDreamingStopped();
        loseFocus();
    }
    @Override
    public void onDetachedFromWindow(){
        logger.fine("onDestroy");
        if (app != null) {
            app.stop(!isGLThreadPaused);
        }
        setContentView(new TextView(this));
        ctx = null;
        app = null;
        view = null;
        JmeAndroidSystem.setView(null);
        super.onDetachedFromWindow();

    }


    public Application getJmeApplication() {
        return app;
    }

    /**
     * Called when an error has occurred. By default, will show an error message
     * to the user and print the exception/error to the log.
     */
    @Override
    public void handleError(final String errorMsg, final Throwable t) {
        String stackTrace = "";
        String title = "Error";

        if (t != null) {
            // Convert exception to string
            StringWriter sw = new StringWriter(100);
            t.printStackTrace(new PrintWriter(sw));
            stackTrace = sw.toString();
            title = t.toString();
        }

        final String finalTitle = title;
        final String finalMsg = (errorMsg != null ? errorMsg : "Uncaught Exception")
                + "\n" + stackTrace;

        logger.log(Level.SEVERE, finalMsg);
    }

    /**
     * Called by the android alert dialog, terminate the activity and OpenGL
     * rendering
     *
     * @param dialog ignored
     * @param whichButton the button index
     */

    /**
     * Gets called by the InputManager on all touch/drag/scale events
     */
    @Override
    public void onTouch(String name, TouchEvent evt, float tpf) {
        if (name.equals(ESCAPE_EVENT)) {
            switch (evt.getType()) {
                case KEY_UP:
                    if (app != null) {
                        app.stop(true);
                    }
                    app = null;
                    this.finish();
                    break;
                default:
                    break;
            }
        }
    }

    public void layoutDisplay() {
        logger.log(Level.FINE, "Splash Screen Picture Resource ID: {0}", splashPicID);
        if (view == null) {
            logger.log(Level.FINE, "view is null!");
        }
        logger.log(Level.FINE, "Splash Screen Skipped.");
        setContentView(view);
    }


    /**
     * Removes the standard Android log handler due to an issue with not logging
     * entries lower than INFO level and adds a handler that produces
     * JME formatted log messages.
     */
    protected void initializeLogHandler() {
        Logger log = LogManager.getLogManager().getLogger("");
        for (Handler handler : log.getHandlers()) {
            if (log.getLevel() != null && log.getLevel().intValue() <= Level.FINE.intValue()) {
                Log.v("MyService", "Removing Handler class: " + handler.getClass().getName());
            }
            log.removeHandler(handler);
        }
        Handler handler = new AndroidLogHandler();
        log.addHandler(handler);
        handler.setLevel(Level.ALL);
    }

    @Override
    public void initialize() {
        app.initialize();
        if (handleExitHook) {
            // remove existing mapping from SimpleApplication that stops the app
            // when the esc key is pressed (esc key = android back key) so that
            // AndroidHarness can produce the exit app dialog box.
            if (app.getInputManager().hasMapping(SimpleApplication.INPUT_MAPPING_EXIT)) {
                app.getInputManager().deleteMapping(SimpleApplication.INPUT_MAPPING_EXIT);
            }

            app.getInputManager().addMapping(ESCAPE_EVENT, new TouchTrigger(TouchInput.KEYCODE_BACK));
            app.getInputManager().addListener(this, new String[]{ESCAPE_EVENT});
        }
    }

    @Override
    public void reshape(int width, int height) {
        app.reshape(width, height);
    }

    @Override
    public void rescale(float x, float y) {
        app.rescale(x, y);
    }

    @Override
    public void update() {
        app.update();
        // call to remove the splash screen, if present.
        // call after app.update() to make sure no gap between
        // splash screen going away and app display being shown.
    }

    @Override
    public void requestClose(boolean esc) {
        app.requestClose(esc);
    }

    @Override
    public void destroy() {
        onDetachedFromWindow();
    }

    @Override
    public void gainFocus() {
        logger.fine("gainFocus");
        if (view != null) {
            view.onResume();
        }

        if (app != null) {
            //resume the audio
            AudioRenderer audioRenderer = app.getAudioRenderer();
            if (audioRenderer != null) {
                audioRenderer.resumeAll();
            }
            //resume the sensors (aka joysticks)
            if (app.getContext() != null) {
                JoyInput joyInput = app.getContext().getJoyInput();
                if (joyInput != null) {
                    if (joyInput instanceof AndroidSensorJoyInput) {
                        AndroidSensorJoyInput androidJoyInput = (AndroidSensorJoyInput) joyInput;
                        androidJoyInput.resumeSensors();
                    }
                }
            }
        }

        isGLThreadPaused = false;

        if (app != null) {
            app.gainFocus();
        }
    }

    @Override
    public void loseFocus() {
        logger.fine("loseFocus");
        if (app != null) {
            app.loseFocus();
        }

        if (view != null) {
            view.onPause();
        }

        if (app != null) {
            //pause the audio
            AudioRenderer audioRenderer = app.getAudioRenderer();
            if (audioRenderer != null) {
                audioRenderer.pauseAll();
            }
            //pause the sensors (aka joysticks)
            if (app.getContext() != null) {
                JoyInput joyInput = app.getContext().getJoyInput();
                if (joyInput != null) {
                    if (joyInput instanceof AndroidSensorJoyInput) {
                        AndroidSensorJoyInput androidJoyInput = (AndroidSensorJoyInput) joyInput;
                        androidJoyInput.pauseSensors();
                    }
                }
            }
        }
        isGLThreadPaused = true;
    }
    public MyService() {
    }

}

and I got error messages shown below:

SEVERE Failed to create JmeSystem delegate:
{0}
java.lang.reflect.InvocationTargetException
	at java.lang.reflect.Constructor.newInstance(Native Method)
	at com.jme3.system.JmeSystem.tryLoadDelegate(JmeSystem.java:238)
	at com.jme3.system.JmeSystem.checkDelegate(JmeSystem.java:250)
	at com.jme3.system.JmeSystem.showSettingsDialog(JmeSystem.java:226)
	at com.jme3.app.SimpleApplication.start(SimpleApplication.java:120)
	at com.cottonwoodanalytics.anno.screansaver.MyService.onAttachedToWindow(MyService.java:221)
	at com.android.internal.policy.PhoneWindow$DecorView.onAttachedToWindow(PhoneWindow.java:3784)
	at android.view.View.dispatchAttachedToWindow(View.java:15810)
	at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3139)
	at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1782)
	at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1488)
	at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7451)
	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:920)
	at android.view.Choreographer.doCallbacks(Choreographer.java:695)
	at android.view.Choreographer.doFrame(Choreographer.java:631)
	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:906)
	at android.os.Handler.handleCallback(Handler.java:739)
	at android.os.Handler.dispatchMessage(Handler.java:95)
	at android.os.Looper.loop(Looper.java:158)
	at android.app.ActivityThread.main(ActivityThread.java:7225)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Caused by: java.lang.NoClassDefFoundError: com.jme3.system.JmeSystemDelegate$$ExternalSyntheticLambda0
	at com.jme3.system.JmeSystemDelegate.<init>(JmeSystemDelegate.java:65)
	at com.jme3.system.android.JmeAndroidSystem.<init>(JmeAndroidSystem.java:41)
	at java.lang.reflect.Constructor.newInstance(Native Method) 
	at com.jme3.system.JmeSystem.tryLoadDelegate(JmeSystem.java:238) 
	at com.jme3.system.JmeSystem.checkDelegate(JmeSystem.java:250) 
	at com.jme3.system.JmeSystem.showSettingsDialog(JmeSystem.java:226) 
	at com.jme3.app.SimpleApplication.start(SimpleApplication.java:120) 
	at com.cottonwoodanalytics.anno.screansaver.MyService.onAttachedToWindow(MyService.java:221) 
	at com.android.internal.policy.PhoneWindow$DecorView.onAttachedToWindow(PhoneWindow.java:3784) 
	at android.view.View.dispatchAttachedToWindow(View.java:15810) 
	at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3139) 
	at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1782) 
	at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1488) 
	at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7451) 
	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:920) 
	at android.view.Choreographer.doCallbacks(Choreographer.java:695) 
	at android.view.Choreographer.doFrame(Choreographer.java:631) 
	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:906) 
	at android.os.Handler.handleCallback(Handler.java:739) 
	at android.os.Handler.dispatchMessage(Handler.java:95) 
	at android.os.Looper.loop(Looper.java:158) 
	at android.app.ActivityThread.main(ActivityThread.java:7225) 
	at java.lang.reflect.Method.invoke(Native Method) 
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 
SEVERE Class com.cottonwoodanalytics.anno.core.AnnoCore init failed
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean com.jme3.system.JmeSystemDelegate.showSettingsDialog(com.jme3.system.AppSettings, boolean)' on a null object reference
	at com.jme3.system.JmeSystem.showSettingsDialog(JmeSystem.java:227)
	at com.jme3.app.SimpleApplication.start(SimpleApplication.java:120)
	at com.cottonwoodanalytics.anno.screansaver.MyService.onAttachedToWindow(MyService.java:221)
	at com.android.internal.policy.PhoneWindow$DecorView.onAttachedToWindow(PhoneWindow.java:3784)
	at android.view.View.dispatchAttachedToWindow(View.java:15810)
	at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3139)
	at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1782)
	at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1488)
	at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7451)
	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:920)
	at android.view.Choreographer.doCallbacks(Choreographer.java:695)
	at android.view.Choreographer.doFrame(Choreographer.java:631)
	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:906)
	at android.os.Handler.handleCallback(Handler.java:739)
	at android.os.Handler.dispatchMessage(Handler.java:95)
	at android.os.Looper.loop(Looper.java:158)
	at android.app.ActivityThread.main(ActivityThread.java:7225)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
SEVERE NULLLLL~~~~~~~~~~
Shutting down VM
FATAL EXCEPTION: main
Process: com.cottonwoodanalytics.anno.screansaver, PID: 13864
java.lang.NullPointerException: Attempt to invoke virtual method 'android.opengl.GLSurfaceView com.jme3.system.android.OGLESContext.createView(android.content.Context)' on a null object reference
	at com.cottonwoodanalytics.anno.screansaver.MyService.onAttachedToWindow(MyService.java:232)
	at com.android.internal.policy.PhoneWindow$DecorView.onAttachedToWindow(PhoneWindow.java:3784)
	at android.view.View.dispatchAttachedToWindow(View.java:15810)
	at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3139)
	at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1782)
	at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1488)
	at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7451)
	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:920)
	at android.view.Choreographer.doCallbacks(Choreographer.java:695)
	at android.view.Choreographer.doFrame(Choreographer.java:631)
	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:906)
	at android.os.Handler.handleCallback(Handler.java:739)
	at android.os.Handler.dispatchMessage(Handler.java:95)
	at android.os.Looper.loop(Looper.java:158)
	at android.app.ActivityThread.main(ActivityThread.java:7225)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

as shown in android documentation, I move the init code from start() to onAttachedToWindow()
Did I just messed up with the lifecycle ? or other reasons?

Resolution from Window, width:1080, height: 1920
Unable to open '/system/framework/com.qti.location.sdk.jar': No such file or directory
Failed to open zip archive '/system/framework/com.qti.location.sdk.jar': I/O Error
Rejecting re-init on previously-failed class java.lang.Class<com.jme3.system.JmeSystemDelegate$$ExternalSyntheticLambda0>
Rejecting re-init on previously-failed class java.lang.Class<com.jme3.system.JmeSystemDelegate$$ExternalSyntheticLambda0>
Rejecting re-init on previously-failed class java.lang.Class<com.jme3.system.android.JmeAndroidSystem$$ExternalSyntheticLambda1>
Rejecting re-init on previously-failed class java.lang.Class<com.jme3.system.android.JmeAndroidSystem$$ExternalSyntheticLambda1>
Rejecting re-init on previously-failed class java.lang.Class<com.jme3.system.JmeSystemDelegate$$ExternalSyntheticLambda0>

What is a “Rejecting re-init on previously-failed class” ???

it looks like JME is failing due to a missing file (not related to JME):

'/system/framework/com.qti.location.sdk.jar'

no, this is an issue from Samsung sdk, and not related with our issue.
It seems like a reflection problem.

Caused by: java.lang.NoClassDefFoundError: com.jme3.system.JmeSystemDelegate$$ExternalSyntheticLambda0

It turns out I forgot set Desugaring true.

compileOptions {
        coreLibraryDesugaringEnabled true
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
2 Likes