1

I am generating an image that is saved in FileSytemStorage.getAppHomePath() dir. I now need to share it via Email, SMS ... That's why I am using the following code (based on Codename One documentation) in my action method :

    long time = new Date().getTime();

    String fullOutputPath = FileSystemStorage.getInstance().getAppHomePath()
            + "Montage_" + Long.toString(time) + ".png";

    // Save the image with the ImageIO class
    try (OutputStream os = FileSystemStorage.getInstance().openOutputStream(fullOutputPath)){
        ImageIO.getImageIO().save(montage.getMontageImage(), os, ImageIO.FORMAT_PNG, 1.0f);

        }


    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

        // Enable image sharing (outside the try/catch so that the outputstream in closed for sure)
        if (FileSystemStorage.getInstance().exists(fullOutputPath)) {
            Dialog.show("Saved", "Photo collage saved to " + fullOutputPath
                    + " (file size = " + FileSystemStorage.getInstance().getLength(fullOutputPath) +" B)", "OK", null);
            //Photo collage saved to file://home/Montage_14669... .png (file size = 50387B)

            findValidateMontageShareButton3().setImageToShare(fullOutputPath, "image/png");
            // Null pointer exception

So in that way I get a NPE and if I don't test if the file does exist there is no NPE but the image is still missing (both in the simulator and on the device).

The stack trace is as follows :

java.lang.NullPointerException
at userclasses.StateMachine.onPage3_ValidateMontageShareButton3Action(StateMachine.java:852)
at generated.StateMachineBase.handleComponentAction(StateMachineBase.java:757)
at com.codename1.ui.util.UIBuilder$FormListener.actionPerformed(UIBuilder.java:2835)
at com.codename1.ui.util.EventDispatcher.fireActionSync(EventDispatcher.java:459)
at com.codename1.ui.util.EventDispatcher.fireActionEvent(EventDispatcher.java:362)
at com.codename1.ui.Button.fireActionEvent(Button.java:411)
at com.codename1.ui.Button.released(Button.java:442)
at com.codename1.ui.Button.pointerReleased(Button.java:530)
at com.codename1.ui.Form.pointerReleased(Form.java:2627)
at com.codename1.ui.Form.pointerReleased(Form.java:2563)
at com.codename1.ui.Component.pointerReleased(Component.java:3158)
at com.codename1.ui.Display.handleEvent(Display.java:2025)
at com.codename1.ui.Display.edtLoopImpl(Display.java:1067)
at com.codename1.ui.Display.mainEDTLoop(Display.java:996)
at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120)
at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)

It looks that the file my app is generating is not accesible to the sharing app. Do I have to add any extra permission as advised here for Android ?

Please note : I don't know if it is related to this problem but I cannot access to Codename One Settings menu from Eclipse anymore (maybe since upgrade to CN1 lib v 115)

Any help appreciated,

Cheers

Community
  • 1
  • 1
HelloWorld
  • 2,275
  • 18
  • 29
  • The necessary permissions should be in place. What's the stack of the null pointer exception? – Shai Almog Jun 27 '16 at 04:09
  • I added the stack trace. – HelloWorld Jun 27 '16 at 08:20
  • You gave me an idea. I tested if findValidateMontageShareButton3() was returning null and it was indeed. So although I cannot explain it, I changed to `((ShareButton) c).setImageToShare(fullOutputPath, "image/png");` and the NPE went away. Unfortunatelly the message I send still misses the image. – HelloWorld Jun 27 '16 at 09:11
  • 1
    The reason for the stack trace is simple, you need to use `findValidateMontageShareButton3(f)` and not `findValidateMontageShareButton3()`. The latter is only good if you are within the current form. For the settings issue try deleting guibuilder*.jar from the .codenameone directory under your home directory and see if that helps (this is probably unrelated though). When you say the image isn't included, where do you test it? On Android only? Did you include text as well? Try not including text. Which intent did you pick for sharing? – Shai Almog Jun 28 '16 at 04:07
  • Thanks for the tip regarding `findValidateMontageShareButton`. As far as the Codename One Settings is concerned, I also renamed the project without space (My Project -> MyProject) and it worked. So the image is not included in the simulator (and on my Android 4.4 device). I did not include text. But what is weird is that if I share the image, choose email, (the image is neither included in the email client mock up nor in my PC email client), go back to my app sharing page, share it again, now it appears. Same behaviour on the device : first time nothing, then second or third time sth. – HelloWorld Jun 28 '16 at 07:40
  • I chose the email intent and also the SMS intent on the device. – HelloWorld Jun 28 '16 at 07:43

1 Answers1

1

So here is part of the answer which works in the simulator (ie the image appears in the fake email client => see image below).

Image in the fake email client

So it appears that the share button cannot be set up in the action method (ie the method that is triggered when the user click on the share button). It has to be set up previously.

Consequently, in the beforeShow method my code reads as follows :`

    FontImage.setMaterialIcon(findValidateMontageShareButton3(), FontImage.MATERIAL_CHECK_CIRCLE);


   final long time = new Date().getTime();

   // We generate the montage filename JPG otherwise it cannot be sent
   montage.setMontageFullPath(FileSystemStorage.getInstance().getAppHomePath()
            + "Montage_" + Long.toString(time) + ".jpg");

   // We assign the montage filename to the share button BEFORE we can click the button (otherwise the
   // filename cannot be taken into account)
   findValidateMontageShareButton3(f).setImageToShare(
        montage.getMontageFullPath(), "image/jpeg");

Then in the onAction method related to the share button the code reads :

    // Save the image with the ImageIO class
    // We wait until the file is completely written to continue
    Display.getInstance().invokeAndBlock(new Runnable() {

        @Override
        public void run() {
            try (OutputStream os = FileSystemStorage.getInstance().openOutputStream(montage.getMontageFullPath())){
                ImageIO.getImageIO().save(montage.getMontageImage(), os, ImageIO.FORMAT_JPEG, 1);   

            } catch (IOException e) {
                Dialog.show("Erreur", "Impossible de sauvegarder le montage! Merci de vérifier l'espace disque disponible.", null, "OK" );
            }
        }
    });

I tested it and it worked on the simulator but not on the device. Either with a png or a jpeg file, the file cannot be attached to the SMS or email (Android error message "abnormal file, can't attached file").

However if I do it a second time, then the file can be attached. So now the image is not missing but it cannot be attached (the first time) which is still embarrassing.

HelloWorld
  • 2,275
  • 18
  • 29
  • Thanks, that seems like a misbehavior of the component that should be fixed. We'll postpone the share button action to the next EDT cycle which will allow your code to process first and effectively solve the issue. – Shai Almog Jun 29 '16 at 04:23
  • Is there a workaround I can do in between, or I'd better wait for the CN1 lib upgrade ? Do you have any idea when it should be ready ? – HelloWorld Jun 29 '16 at 06:47
  • 1
    Libraries update every Friday so I guess you can wait a day or two – Shai Almog Jun 30 '16 at 04:00
  • I changed my mind, so I did not check if it works now as I wanted earlier. What I am doing now is display a save button that saves the image on the device (somewhere that is allowed) and open it with `Display.execute()` . It opens the OS photo viewer that allows to share or save the image in the gallery (tested on iPhone 4) which was not allowed from my app. For now it fines me ;-)! – HelloWorld Jul 02 '16 at 04:42