[SOLVED] simpleCamera extension attempt [FAIL!] - help needed

To help expand my java coding skills, I took on what should be a simple project to take a picture with the camera, and return the thumbnail generated to an image component.

With help and advice from others, I followed code from Android Developers Training:

https://developer.android.com/training/camera/photobasics#TaskCaptureIntent

and came up with the following java file below. I have no errors in my IDE (IntelliJ). This builds an aix using RUSH. However, on testing in companion (2.61u) on Android 10 and 11, it generates an error on load:

Error from Companion: java.lang.Class is not accessible from java.lang.Class

(I do not have mismatched companion, and have reloaded after installing extension etc., tested on multiple devices)

and if I run the TakePicture block it generates this error:

invoke: no method named `TakePicture' in class java.lang.Boolean

I can compile an apk, but on first run it just crashes.

Not really sure what is wrong or what is missing, and would welcome some help. If more information is needed then please say.

JAVA
package uk.co.metricrat.simplecamera;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;

import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.runtime.ActivityResultListener;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.ComponentContainer;
import com.google.appinventor.components.runtime.errors.YailRuntimeError;

import android.widget.ImageView;
import com.google.appinventor.components.runtime.Image;



class SimpleCamera extends AndroidNonvisibleComponent implements ActivityResultListener {

  final Activity activity;
  static final int REQUEST_IMAGE_CAPTURE = 1;
  private ImageView imageView;


  public SimpleCamera(ComponentContainer container) {
    super(container.$form());
    this.activity = container.$context();
  }

  
  @SimpleFunction(description = "Takes Thumbnail Picture with Camera and return")
  public void TakePicture(Image image) {
    imageView = (ImageView) image.getView();
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    try {
      this.activity.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
    } catch (ActivityNotFoundException e) {
      throw new YailRuntimeError(e.getMessage(), "Cannot start activity");
    }
  }

  
  @Override
  public void resultReturned(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
      Bundle extras = data.getExtras();
      Bitmap imageBitmap = (Bitmap) extras.get("data");
      imageView.setImageBitmap(imageBitmap);
    }
  }
}

You should make your extension's class public to outer packages.

public SimpleCamera extends AndroidNonvisibleComponent 

It's because AppInventor is trying to create an instance of your extension class and fails to finds it since it's not public. While creating the class, an error has occurred, so you couldn't access any methods since the component is not sucessfully created.

1 Like

Ah yes, senior moment exposed !!

Thank you @Kumaraswamy.

Tested and errors go away, camera brought to life.

Unfortunately, I am not quite there yet, no image is returned to the image component ?

1 Like

You can take a look here for that:

1 Like

Thank you @vknow360. Your code returns a file, I am seeking to avoid that, but to directly display the bitmap in the image component (or other view component...)

I guess you have to register any implementation interface.

form.registerForActivityResult(this);

This will return the result code, maybe you will have to compare against the result code returned by the overided method.

Like so ?:

if (requestCode == 0) {
        requestCode = form.registerForActivityResult(this);
      }
2 Likes

OK, added this to the
@SimpleFunction before calling the intent, changing the 0 to 1,
and changed the variable setting to
static int REQUEST_IMAGE_CAPTURE = 1;
(there was a final there too, but this was bring up an error in IntelliJ...)

On first run this produces an image (:D), but will not generate an image on subsequent clicks of the button. I am guessing that REQUEST_IMAGE_CAPTURE is for some reason not being reset to 1 ? or should I just set it 0?

JAVA now...
public class SimpleCamera extends AndroidNonvisibleComponent implements ActivityResultListener {

  final Activity activity;
  static int REQUEST_IMAGE_CAPTURE = 1;
  private ImageView imageView;


  public SimpleCamera(ComponentContainer container) {
    super(container.$form());
    this.activity = container.$context();
  }

 @SimpleFunction(description = "Takes Thumbnail Picture with Camera and return")
  public void TakePicture(Image image) {
    imageView = (ImageView) image.getView();

    if (REQUEST_IMAGE_CAPTURE == 1) {
      REQUEST_IMAGE_CAPTURE = form.registerForActivityResult(this);
    }

    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    try {
      this.activity.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
    } catch (ActivityNotFoundException e) {
      throw new YailRuntimeError(e.getMessage(), "Cannot start activity");
    }
  }

  @Override
  public void resultReturned(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
      Bundle extras = data.getExtras();
      Bitmap imageBitmap = (Bitmap) extras.get("data");
      imageView.setImageBitmap(imageBitmap);
    }
  }

Could you try removing the if statement and moving its body to initialize the variable?

 public CameraTest(ComponentContainer container) {
        super(container.$form());
        this.activity = container.$context();
        REQUEST_IMAGE_CAPTURE = form.registerForActivityResult(this);
    }
1 Like

I seem to have fixed it by also removing the if statement (keeping the then part), and removing the setting of REQUEST_IMAGE_CAPTURE to 1.

I will test your way too. Thank you.

2 Likes

Going to mark this solved.

Many thanks @Kumaraswamy & @vknow360 for input

For what it is worth, the thumbnail images are OK for viewing at around half screen width (landscape) and below on a normal phone. If that is all you need then it could be a way....

Final Java
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;

import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.runtime.ActivityResultListener;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.ComponentContainer;
import com.google.appinventor.components.runtime.errors.YailRuntimeError;

import android.widget.ImageView;
import com.google.appinventor.components.runtime.Image;

public class SimpleCamera extends AndroidNonvisibleComponent implements ActivityResultListener {

  final Activity activity;
  private final int REQUEST_IMAGE_CAPTURE;
  private ImageView imageView;


  public SimpleCamera(ComponentContainer container) {
    super(container.$form());
    this.activity = container.$context();
    REQUEST_IMAGE_CAPTURE = form.registerForActivityResult(this);
  }

  @SimpleFunction(description = "Takes Thumbnail Picture with Camera and return")
  public void TakePicture(Image image) {
    imageView = (ImageView) image.getView();

    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    try {
      this.activity.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
    } catch (ActivityNotFoundException e) {
      throw new YailRuntimeError(e.getMessage(), "Cannot start activity");
    }
  }

  @Override
  public void resultReturned(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
      Bundle extras = data.getExtras();
      Bitmap imageBitmap = (Bitmap) extras.get("data");
      imageView.setImageBitmap(imageBitmap);
    }
  }
}
1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.