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();
User contributions licensed under CC BY-SA 3.0