blob: 73651f51c6e94586356326468384c419b4fbc36f [file] [log] [blame]
/*
* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.skia.arcore;
import android.app.Activity;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.ActionMode;
import android.view.ContextMenu;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.PopupMenu;
import android.widget.Toast;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/**
* This is a simple example that shows how to create an augmented reality (AR) application using the
* ARCore C API.
*/
public class HelloArActivity extends AppCompatActivity
implements GLSurfaceView.Renderer, DisplayManager.DisplayListener {
private static final String TAG = HelloArActivity.class.getSimpleName();
private static final int SNACKBAR_UPDATE_INTERVAL_MILLIS = 1000; // In milliseconds.
private GLSurfaceView mSurfaceView;
private Activity activity = null;
private boolean mViewportChanged = false;
private int mViewportWidth;
private int mViewportHeight;
private View contextView = null;
private int mCurrentObjectRotation = 0;
private float mCurrentValue = 0;
private float X = 0;
private float Y = 0;
private boolean toEdit = false;
// Opaque native pointer to the native application instance.
private long mNativeApplication;
private GestureDetector mGestureDetector;
private Snackbar mLoadingMessageSnackbar;
private Handler mPlaneStatusCheckingHandler;
private final Runnable mPlaneStatusCheckingRunnable =
new Runnable() {
@Override
public void run() {
// The runnable is executed on main UI thread.
try {
if (JniInterface.hasDetectedPlanes(mNativeApplication)) {
if (mLoadingMessageSnackbar != null) {
mLoadingMessageSnackbar.dismiss();
}
mLoadingMessageSnackbar = null;
} else {
mPlaneStatusCheckingHandler.postDelayed(
mPlaneStatusCheckingRunnable, SNACKBAR_UPDATE_INTERVAL_MILLIS);
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
};
private int mDrawMode = -1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
activity = this;
//hide notifications bar
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
mSurfaceView = (GLSurfaceView) findViewById(R.id.surfaceview);
mGestureDetector =
new GestureDetector(
this,
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(final MotionEvent e) {
toEdit = JniInterface.onTouchedFirst(mNativeApplication, e.getX(), e.getY(), mDrawMode);
Log.i(TAG, "toEdit: " + toEdit);
X = e.getX();
Y = e.getY();
contextView.showContextMenu(e.getX(), e.getY());
return true;
}
@Override
public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
Log.i(TAG, "Scrolling!");
JniInterface.onTouchTranslate(mNativeApplication, e2.getX(), e2.getY());
return true;
}
@Override
public boolean onDown(MotionEvent e) {
return true;
}
});
mSurfaceView.setOnTouchListener(
new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
});
// Set up renderer.
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);
JniInterface.assetManager = getAssets();
mNativeApplication = JniInterface.createNativeApplication(getAssets());
mPlaneStatusCheckingHandler = new Handler();
//Floating context menu
contextView = findViewById(R.id.menuView);
this.registerForContextMenu(contextView);
View.OnLongClickListener listener = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
activity.closeContextMenu();
return false;
}
};
contextView.setOnLongClickListener(listener);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, v, menuInfo);
if (!toEdit) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.draw_menu, menu);
menu.setHeaderTitle("Draw Options");
}
v.setClickable(false);
v.setFocusable(false);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
case R.id.draw_text:
JniInterface.onTouchedFinal(mNativeApplication, 0);
return true;
case R.id.draw_circle:
JniInterface.onTouchedFinal(mNativeApplication, 1);
return true;
case R.id.draw_rect:
JniInterface.onTouchedFinal(mNativeApplication, 2);
return true;
case R.id.edit_size:
return true;
case R.id.edit_text:
return true;
default:
return super.onContextItemSelected(item);
}
}
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.rotation_mode, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.rotation_axis_aligned:
mCurrentObjectRotation = 0;
break;
case R.id.rotation_camera_aligned:
mCurrentObjectRotation = 1;
break;
case R.id.rotation_snap_aligned:
mCurrentObjectRotation = 2;
break;
case R.id.action:
mCurrentValue = 180;
JniInterface.onAction(mNativeApplication, mCurrentValue);
return true;
default:
return true;
}
JniInterface.onObjectRotationChanged(mNativeApplication, mCurrentObjectRotation);
return true;
}
@Override
protected void onResume() {
super.onResume();
// ARCore requires camera permissions to operate. If we did not yet obtain runtime
// permission on Android M and above, now is a good time to ask the user for it.
if (!CameraPermissionHelper.hasCameraPermission(this)) {
CameraPermissionHelper.requestCameraPermission(this);
return;
}
JniInterface.onResume(mNativeApplication, getApplicationContext(), this);
mSurfaceView.onResume();
mLoadingMessageSnackbar =
Snackbar.make(
HelloArActivity.this.findViewById(android.R.id.content),
"Searching for surfaces...",
Snackbar.LENGTH_INDEFINITE);
// Set the snackbar background to light transparent black color.
mLoadingMessageSnackbar.getView().setBackgroundColor(0xbf323232);
mLoadingMessageSnackbar.show();
mPlaneStatusCheckingHandler.postDelayed(
mPlaneStatusCheckingRunnable, SNACKBAR_UPDATE_INTERVAL_MILLIS);
// Listen to display changed events to detect 180° rotation, which does not cause a config
// change or view resize.
getSystemService(DisplayManager.class).registerDisplayListener(this, null);
}
@Override
public void onPause() {
super.onPause();
mSurfaceView.onPause();
JniInterface.onPause(mNativeApplication);
mPlaneStatusCheckingHandler.removeCallbacks(mPlaneStatusCheckingRunnable);
getSystemService(DisplayManager.class).unregisterDisplayListener(this);
}
@Override
public void onDestroy() {
super.onDestroy();
// Synchronized to avoid racing onDrawFrame.
synchronized (this) {
JniInterface.destroyNativeApplication(mNativeApplication);
mNativeApplication = 0;
}
}
@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
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
JniInterface.onGlSurfaceCreated(mNativeApplication);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
mViewportWidth = width;
mViewportHeight = height;
mViewportChanged = true;
}
@Override
public void onDrawFrame(GL10 gl) {
// Synchronized to avoid racing onDestroy.
synchronized (this) {
if (mNativeApplication == 0) {
return;
}
if (mViewportChanged) {
int displayRotation = getWindowManager().getDefaultDisplay().getRotation();
JniInterface.onDisplayGeometryChanged(
mNativeApplication, displayRotation, mViewportWidth, mViewportHeight);
mViewportChanged = false;
}
JniInterface.onGlSurfaceDrawFrame(mNativeApplication);
}
}
@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)) {
// Permission denied with checking "Do not ask again".
CameraPermissionHelper.launchPermissionSettings(this);
}
finish();
}
}
// DisplayListener methods
@Override
public void onDisplayAdded(int displayId) {
}
@Override
public void onDisplayRemoved(int displayId) {
}
@Override
public void onDisplayChanged(int displayId) {
mViewportChanged = true;
}
}