Camera capture only getting blank image Android + ARCore

0

I am trying to trigger a camera capture executed natively in Android ARCore from Javascript. If I call my SavePictureCam(); natively. e.g: placing the call in onDrawFrame(); function I get the camera capture stored into local storage properly.

But If I call the SavePictureCam(); using JavaScript Web interface.

public class WebViewJavaScriptInterface{
    @JavascriptInterface
    public void SavePicture() {
        SavePictureCam();
    }
}

I get a blank image stored in my disk instead.

My full code is described below, and I must admit, I did not write this from scratch. I composed this using below source :

Could anyone point out to me what did I miss? I suspect that when I call SavePictureCam(); from JavaScript Web Interface the screen object does not get passed.

MainActivity.java

package com.amazon.sumerianarcorestarter;
import android.graphics.Bitmap;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import android.widget.Toast;
import com.google.ar.core.Config;
import com.google.ar.core.Frame;
import com.google.ar.core.Session;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.IntBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class MainActivity extends AppCompatActivity implements GLSurfaceView.Renderer {

 private int mWidth;
 private int mHeight;

 private static final String TAG = MainActivity.class.getSimpleName();
 private static final String SCENE_URL = "https://ap-southeast-2.sumerian.aws/c4a89031fe7c4214a91e3c5204a5d410.scene/?arMode=true";

 private GLSurfaceView mSurfaceView;
 private Session mSession;
 private SumerianConnector mSumerianConnector;

 private final BackgroundRenderer mBackgroundRenderer = new BackgroundRenderer();


 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  mSurfaceView = findViewById(R.id.gl_surface_view);
  mSurfaceView.setPreserveEGLContextOnPause(true);
  mSurfaceView.setEGLContextClientVersion(2);
  mSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); // Alpha used for plane blending.
  mSurfaceView.setRenderer(this);
  mSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);

  WebView webView = (WebView) findViewById(R.id.activity_main_webview);
  webView.getSettings().setJavaScriptEnabled(true);
  webView.addJavascriptInterface(new WebViewJavaScriptInterface(), "app");
 }

 public class WebViewJavaScriptInterface {
  @JavascriptInterface
  public void SavePicture() {
   SavePictureCam();
  }
 }

 @Override
 public void onWindowFocusChanged(boolean hasFocus) {
  super.onWindowFocusChanged(hasFocus);
  if (hasFocus) {
   // Standard Android full-screen functionality.
   getWindow().getDecorView().setSystemUiVisibility(
    View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
   getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  }
 }

 @Override
 protected void onResume() {
  super.onResume();

  if (mSession == null) {
   if (!CameraPermissionHelper.hasCameraPermission(this)) {
    CameraPermissionHelper.requestCameraPermission(this);
    return;
   }

   try {
    mSession = new Session( /* context= */ this);
   } catch (Exception e) {
    throw new RuntimeException(e);
   }

   final WebView webView = findViewById(R.id.activity_main_webview);
   mSumerianConnector = new SumerianConnector(webView, mSession, mSurfaceView);

   Config config = new Config(mSession);
   config.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE);
   if (!mSession.isSupported(config)) {
    throw new RuntimeException("This device does not support AR");
   }

   mSession.configure(config);
   mSumerianConnector.loadUrl(SCENE_URL);
  }

  mSession.resume();
  mSurfaceView.onResume();
 }

 @Override
 public void onPause() {
  super.onPause();

  mSurfaceView.onPause();
  if (mSession != null) {
   mSession.pause();
  }
 }

 @Override
 public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] results) {
  if (!CameraPermissionHelper.hasCameraPermission(this)) {
   Toast.makeText(this,
    "Camera permission is needed to run this application", Toast.LENGTH_LONG).show();
   if (!CameraPermissionHelper.shouldShowRequestPermissionRationale(this)) {
    CameraPermissionHelper.launchPermissionSettings(this);
   }
   finish();
  }
 }

 @Override
 public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  GLES20.glClearColor(0.1 f, 0.1 f, 0.1 f, 1.0 f);
  mBackgroundRenderer.createOnGlThread( /*context=*/ this);
  mSession.setCameraTextureName(mBackgroundRenderer.getTextureId());

 }

 @Override
 public void onSurfaceChanged(GL10 gl, int width, int height) {
  GLES20.glViewport(0, 0, width, height);
  mSession.setDisplayGeometry(getSystemService(WindowManager.class).getDefaultDisplay().getRotation(), width, height);
  mWidth = width;
  mHeight = height;
 }

 @Override
 public void onDrawFrame(GL10 gl) {
  GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

  if (mSession == null) {
   return;
  }

  try {
   final Frame frame = mSession.update();
   mBackgroundRenderer.draw(frame);
   mSumerianConnector.update();
  } catch (Throwable t) {
   Log.e(TAG, "Exception on the OpenGL thread", t);
  }
 }


 public void SavePictureCam() {
  Log.v("ScreenCapture", "Screen Captured");

  try {
   int pixelData[] = new int[mWidth * mHeight];
   IntBuffer buf = IntBuffer.wrap(pixelData);
   buf.position(0);
   GLES20.glReadPixels(0, 0, mWidth, mHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);

   final File out = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/Sumerian", "Img" + Long.toHexString(System.currentTimeMillis()) + ".png");
   if (!out.getParentFile().exists()) {
    out.getParentFile().mkdirs();
   }
   int bitmapData[] = new int[pixelData.length];
   for (int i = 0; i < mHeight; i++) {
    for (int j = 0; j < mWidth; j++) {
     int p = pixelData[i * mWidth + j];
     int b = (p & 0x00ff0000) >> 16;
     int r = (p & 0x000000ff) << 16;
     int ga = p & 0xff00ff00;
     bitmapData[(mHeight - i - 1) * mWidth + j] = ga | r | b;
    }
   }
   Bitmap bmp = Bitmap.createBitmap(bitmapData, mWidth, mHeight, Bitmap.Config.ARGB_8888);
   FileOutputStream fos = new FileOutputStream(out);
   bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
   fos.flush();
   fos.close();
  } catch (IOException e) {
   System.out.println(e.toString());
  }
 }

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.amazon.sumerianarcorestarter.MainActivity">

    <android.opengl.GLSurfaceView
        android:id="@+id/gl_surface_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="top" />

    <WebView
        android:id="@+id/activity_main_webview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


</android.support.constraint.ConstraintLayout>

JavaScript Call

app.SavePicture();
javascript
java
android
arcore
asked on Stack Overflow May 22, 2018 by hutanrimba

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0