diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index dd4888dc4..f81ef5787 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -57,8 +57,15 @@ target_sources( native-lib PUBLIC src/main/cpp/native-lib.cpp + src/main/cpp/BrowserEGLContext.cpp ) + +include(AndroidNdkModules) +android_ndk_import_module_native_app_glue() +target_link_libraries(native-lib native_app_glue) +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate") endif() + # Searches for a specified prebuilt library and stores the path as a # variable. Because CMake includes system libraries in the search path by # default, you only need to specify the name of the public NDK library diff --git a/app/build.gradle b/app/build.gradle index f6ad104af..1413afb38 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -80,11 +80,23 @@ android { ] } + googlevr { + java.srcDirs = [ + 'src/common/nativeactivity' + ] + } + oculusvr { + java.srcDirs = [ + 'src/common/nativeactivity' + ] jniLibs.srcDirs = ["${project.rootDir}/third_party/ovr_mobile/VrApi/Libs"] } svr { + java.srcDirs = [ + 'src/common/nativeactivity' + ] jniLibs.srcDirs = ["${project.rootDir}/third_party/svr/libs"] } diff --git a/app/src/common/nativeactivity/org/mozilla/vrbrowser/VRBrowserActivity.java b/app/src/common/nativeactivity/org/mozilla/vrbrowser/VRBrowserActivity.java new file mode 100644 index 000000000..f9d2fe73f --- /dev/null +++ b/app/src/common/nativeactivity/org/mozilla/vrbrowser/VRBrowserActivity.java @@ -0,0 +1,100 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.vrbrowser; + +import android.app.NativeActivity; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; +import android.graphics.SurfaceTexture; +import android.view.Surface; +import android.view.SurfaceView; + +import org.mozilla.gecko.GeckoSession; + +public class VRBrowserActivity extends NativeActivity { + static String LOGTAG = "VRBrowser"; + static final String DEFAULT_URL = "https://mozvr.com"; + // Used to load the 'native-lib' library on application startup. + static { + System.loadLibrary("native-lib"); + } + + private SurfaceView mSurfaceView; + private static GeckoSession mSession; + private static Surface mBrowserSurface; + + @Override + protected void onCreate(Bundle savedInstanceState) { + Log.e(LOGTAG,"in onCreate"); + super.onCreate(savedInstanceState); + if (mSession == null) { + mSession = new GeckoSession(); + } + getWindow().takeSurface(null); + SurfaceView surfaceView = new SurfaceView(this); + surfaceView.getHolder().addCallback(this); + + setContentView(surfaceView); + loadFromIntent(getIntent()); + } + + @Override + protected void onNewIntent(final Intent intent) { + Log.e(LOGTAG,"In onNewIntent"); + super.onNewIntent(intent); + setIntent(intent); + final String action = intent.getAction(); + if (Intent.ACTION_VIEW.equals(action)) { + if (intent.getData() != null) { + loadFromIntent(intent); + } + } + } + + private void loadFromIntent(final Intent intent) { + final Uri uri = intent.getData(); + Log.e(LOGTAG, "Load URI from intent: " + (uri != null ? uri.toString() : DEFAULT_URL)); + String uriValue = (uri != null ? uri.toString() : DEFAULT_URL); + mSession.loadUri(uriValue); + } + + @Override + protected void onPause() { + Log.e(LOGTAG, "In onPause"); + super.onPause(); + } + + @Override + protected void onResume() { + Log.e(LOGTAG, "in onResume"); + super.onResume(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + private void setSurfaceTexture(String aName, final SurfaceTexture aTexture, final int aWidth, final int aHeight) { + runOnUiThread(new Runnable() { + public void run() { + createBrowser(aTexture, aWidth, aHeight); + } + }); + } + + private void createBrowser(SurfaceTexture aTexture, int aWidth, int aHeight) { + if (aTexture != null) { + Log.e(LOGTAG,"In createBrowser"); + aTexture.setDefaultBufferSize(aWidth, aHeight); + mBrowserSurface = new Surface(aTexture); + mSession.acquireDisplay().surfaceChanged(mBrowserSurface, aWidth, aHeight); + mSession.openWindow(this); + } + } +} diff --git a/app/src/googlevr/AndroidManifest.xml b/app/src/googlevr/AndroidManifest.xml index 78bcde5ae..4d49ae1b3 100644 --- a/app/src/googlevr/AndroidManifest.xml +++ b/app/src/googlevr/AndroidManifest.xml @@ -5,6 +5,7 @@ android:screenOrientation="landscape" android:enableVrMode="@string/gvr_vr_mode_component" android:resizeableActivity="false"> + diff --git a/app/src/main/cpp/BrowserEGLContext.cpp b/app/src/main/cpp/BrowserEGLContext.cpp new file mode 100644 index 000000000..97e2907c8 --- /dev/null +++ b/app/src/main/cpp/BrowserEGLContext.cpp @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "BrowserEGLContext.h" +#include "vrb/Logger.h" +#include +#include + +BrowserEGLContext::BrowserEGLContext() + : mMajorVersion(0), mMinorVersion(0), mDisplay(0), mConfig(0), mSurface(0), mContext(0), + mNativeWindow(nullptr) { +} + +BrowserEGLContextPtr +BrowserEGLContext::Create() { + return std::make_shared(); +} + +bool +BrowserEGLContext::Initialize(ANativeWindow *aNativeWindow) { + mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (eglInitialize(mDisplay, &mMajorVersion, &mMinorVersion) == EGL_FALSE) { + VRB_LOG("eglInitialize() failed: %s", ErrorToString(eglGetError())); + return false; + } + + // Do NOT use eglChooseConfig, because the Android EGL code pushes in multisample + // flags in eglChooseConfig if the user has selected the "force 4x MSAA" option in + // settings, and that is completely wasted for the time warp renderer. + const int MAX_CONFIGS = 1024; + + EGLConfig configs[MAX_CONFIGS]; + EGLint numConfigs = 0; + if (eglGetConfigs(mDisplay, configs, MAX_CONFIGS, &numConfigs) == EGL_FALSE) { + VRB_LOG("eglGetConfigs() failed: %s", ErrorToString(eglGetError())); + return false; + } + + const EGLint configAttribs[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, + EGL_SAMPLES, 0, + EGL_NONE + }; + + for (int i = 0; i < numConfigs; ++i) { + EGLint value = 0; + + eglGetConfigAttrib(mDisplay, configs[i], EGL_RENDERABLE_TYPE, &value); + + // Check EGL Client Version + if ((value & EGL_OPENGL_ES3_BIT_KHR) != EGL_OPENGL_ES3_BIT_KHR) { + continue; + } + + // EGL_WINDOW_BIT is required so it can share textures with the window context. + eglGetConfigAttrib(mDisplay, configs[i], EGL_SURFACE_TYPE, &value); + if ((value & (EGL_WINDOW_BIT | EGL_PBUFFER_BIT)) != (EGL_WINDOW_BIT | EGL_PBUFFER_BIT)) { + continue; + } + + int j = 0; + for (; configAttribs[j] != EGL_NONE; j += 2) { + eglGetConfigAttrib(mDisplay, configs[i], configAttribs[j], &value); + if (value != configAttribs[j + 1]) { + break; + } + } + if (configAttribs[j] == EGL_NONE) { + mConfig = configs[i]; + break; + } + } + + if (mConfig == 0) { + VRB_LOG("eglChooseConfig() failed: %s", ErrorToString(eglGetError())); + return false; + } + + + //Reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. + mNativeWindow = aNativeWindow; + EGLint format; + eglGetConfigAttrib(mDisplay, mConfig, EGL_NATIVE_VISUAL_ID, &format); + ANativeWindow_setBuffersGeometry(aNativeWindow, 0, 0, format); + + EGLint contextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 3, + EGL_NONE + }; + + mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, contextAttribs); + if (mContext == EGL_NO_CONTEXT) { + VRB_LOG("eglCreateContext() failed: %s", ErrorToString(eglGetError())); + return false; + } + + mSurface = eglCreateWindowSurface(mDisplay, mConfig, mNativeWindow, nullptr); + + if (mSurface == EGL_NO_SURFACE) { + VRB_LOG("eglCreateWindowSurface() failed: %s", ErrorToString(eglGetError())); + eglDestroyContext(mDisplay, mContext); + mContext = EGL_NO_CONTEXT; + return false; + } + + if (eglMakeCurrent(mDisplay, mSurface, mSurface, mContext) == EGL_FALSE) { + VRB_LOG("eglMakeCurrent() failed: %s", ErrorToString(eglGetError())); + eglDestroySurface(mDisplay, mSurface); + eglDestroyContext(mDisplay, mContext); + mContext = EGL_NO_CONTEXT; + return false; + } + + return true; +} + +void +BrowserEGLContext::Destroy() { + if (mDisplay) { + if (eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_FALSE) { + VRB_LOG("eglMakeCurrent() failed: %s", ErrorToString(eglGetError())); + } + } + if (mContext != EGL_NO_CONTEXT) { + if (eglDestroyContext(mDisplay, mContext) == EGL_FALSE) { + VRB_LOG("eglDestroyContext() failed: %s", ErrorToString(eglGetError())); + } + mContext = EGL_NO_CONTEXT; + } + if (mSurface != EGL_NO_SURFACE) { + if (eglDestroySurface(mDisplay, mSurface) == EGL_FALSE) { + VRB_LOG("eglDestroySurface() failed: %s", ErrorToString(eglGetError())); + } + mSurface = EGL_NO_SURFACE; + } + if (mDisplay) { + if (eglTerminate(mDisplay) == EGL_FALSE) { + VRB_LOG("eglTerminate() failed: %s", ErrorToString(eglGetError())); + } + mDisplay = 0; + } +} + + +// Handle Android Life Cycle. +// Android has started the activity or sent it to foreground. +// Create a new surface and attach it to the recreated ANativeWindow. +// Restore the EGLContext. +void +BrowserEGLContext::SurfaceChanged(ANativeWindow *aWindow) { + if (mSurface != EGL_NO_SURFACE) { + return; + } + mNativeWindow = aWindow; + mSurface = eglCreateWindowSurface(mDisplay, mConfig, aWindow, nullptr); + if (mSurface == EGL_NO_SURFACE) { + VRB_LOG("eglCreateWindowSurface() failed: %s", ErrorToString(eglGetError())); + } +} + +// Handle Android Life Cycle. +// Android has stopped the activity or sent it to background. +// Release the surface attached to the destroyed ANativeWindow. +// The EGLContext is not destroyed so it can be restored later. +void +BrowserEGLContext::SurfaceDestroyed() { + if (mSurface != EGL_NO_SURFACE) { + if (eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_FALSE) { + VRB_LOG("eglMakeCurrent() failed: %s", ErrorToString(eglGetError())); + } + if (eglDestroySurface(mDisplay, mSurface) == EGL_FALSE) { + VRB_LOG("eglDestroySurface() failed: %s", ErrorToString(eglGetError())); + } + mSurface = EGL_NO_SURFACE; + } +} + +bool +BrowserEGLContext::IsSurfaceReady() const { + return mSurface != EGL_NO_SURFACE; +} + +bool +BrowserEGLContext::MakeCurrent() { + if (eglMakeCurrent(mDisplay, mSurface, mSurface, mContext) == EGL_FALSE) { + VRB_LOG("eglMakeCurrent() failed: %s", ErrorToString(eglGetError())); + return false; + } + return true; +} + +bool +BrowserEGLContext::SwapBuffers() { + if (eglSwapBuffers(mDisplay, mSurface) == EGL_FALSE) { + VRB_LOG("SwapBuffers() failed: %s", ErrorToString(eglGetError())); + return false; + } + return true; +} + +const char * +BrowserEGLContext::ErrorToString(EGLint error) { + switch (error) { + case EGL_SUCCESS: + return "EGL_SUCCESS"; + case EGL_NOT_INITIALIZED: + return "EGL_NOT_INITIALIZED"; + case EGL_BAD_ACCESS: + return "EGL_BAD_ACCESS"; + case EGL_BAD_ALLOC: + return "EGL_BAD_ALLOC"; + case EGL_BAD_ATTRIBUTE: + return "EGL_BAD_ATTRIBUTE"; + case EGL_BAD_CONTEXT: + return "EGL_BAD_CONTEXT"; + case EGL_BAD_CONFIG: + return "EGL_BAD_CONFIG"; + case EGL_BAD_CURRENT_SURFACE: + return "EGL_BAD_CURRENT_SURFACE"; + case EGL_BAD_DISPLAY: + return "EGL_BAD_DISPLAY"; + case EGL_BAD_SURFACE: + return "EGL_BAD_SURFACE"; + case EGL_BAD_MATCH: + return "EGL_BAD_MATCH"; + case EGL_BAD_PARAMETER: + return "EGL_BAD_PARAMETER"; + case EGL_BAD_NATIVE_PIXMAP: + return "EGL_BAD_NATIVE_PIXMAP"; + case EGL_BAD_NATIVE_WINDOW: + return "EGL_BAD_NATIVE_WINDOW"; + case EGL_CONTEXT_LOST: + return "EGL_CONTEXT_LOST"; + default: + return "Unknown Error"; + } +} diff --git a/app/src/main/cpp/BrowserEGLContext.h b/app/src/main/cpp/BrowserEGLContext.h new file mode 100644 index 000000000..a679e8ea8 --- /dev/null +++ b/app/src/main/cpp/BrowserEGLContext.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +struct ANativeWindow; + +class BrowserEGLContext; + +typedef std::shared_ptr BrowserEGLContextPtr; +typedef std::weak_ptr BrowserEGLContextWeakPtr; + +class BrowserEGLContext { +public: + static BrowserEGLContextPtr Create(); + static const char *ErrorToString(EGLint error); + + bool Initialize(ANativeWindow *aWindow); + void Destroy(); + void SurfaceChanged(ANativeWindow *aWindow); + void SurfaceDestroyed(); + bool IsSurfaceReady() const; + bool MakeCurrent(); + bool SwapBuffers(); + BrowserEGLContext(); +private: + EGLint mMajorVersion; + EGLint mMinorVersion; + EGLDisplay mDisplay; + EGLConfig mConfig; + EGLSurface mSurface; + EGLContext mContext; + ANativeWindow *mNativeWindow; +}; \ No newline at end of file diff --git a/app/src/main/cpp/BrowserWorld.cpp b/app/src/main/cpp/BrowserWorld.cpp index a79453e6c..af7c0de87 100644 --- a/app/src/main/cpp/BrowserWorld.cpp +++ b/app/src/main/cpp/BrowserWorld.cpp @@ -178,6 +178,11 @@ BrowserWorld::Resume() { m.paused = false; } +bool +BrowserWorld::IsPaused() const { + return m.paused; +} + void BrowserWorld::InitializeJava(JNIEnv* aEnv, jobject& aActivity, jobject& aAssetManager) { if (m.context) { diff --git a/app/src/main/cpp/BrowserWorld.h b/app/src/main/cpp/BrowserWorld.h index ce459d856..1b944176b 100644 --- a/app/src/main/cpp/BrowserWorld.h +++ b/app/src/main/cpp/BrowserWorld.h @@ -25,6 +25,7 @@ class BrowserWorld { void RegisterDeviceDelegate(DeviceDelegatePtr aDelegate); void Pause(); void Resume(); + bool IsPaused() const; void InitializeJava(JNIEnv* aEnv, jobject& aActivity, jobject& aAssetManager); void InitializeGL(); void ShutdownJava(); diff --git a/app/src/main/cpp/native-lib.cpp b/app/src/main/cpp/native-lib.cpp index 4e1299928..b42b36d33 100644 --- a/app/src/main/cpp/native-lib.cpp +++ b/app/src/main/cpp/native-lib.cpp @@ -10,77 +10,129 @@ #include "BrowserWorld.h" #include "vrb/Logger.h" #include "vrb/GLError.h" - -static BrowserWorldPtr sWorld; +#include "BrowserEGLContext.h" +#include +#include +#include #define JNI_METHOD(return_type, method_name) \ JNIEXPORT return_type JNICALL \ Java_org_mozilla_vrbrowser_VRBrowserActivity_##method_name -extern "C" { -JNI_METHOD(void, activityPaused) -(JNIEnv*, jobject) { - if (sWorld) { - sWorld->Pause(); +struct AppContext { + vrb::RunnableQueuePtr mQueue; + BrowserWorldPtr mWorld; + BrowserEGLContextPtr mEgl; +}; + +void +CommandCallback(android_app *aApp, int32_t aCmd) { + AppContext *ctx = (AppContext *) aApp->userData; + + switch (aCmd) { + // A new ANativeWindow is ready for use. Upon receiving this command, + // android_app->window will contain the new window surface. + case APP_CMD_INIT_WINDOW: + VRB_LOG("APP_CMD_INIT_WINDOW %p", aApp->window); + if (!ctx->mEgl) { + ctx->mEgl = BrowserEGLContext::Create(); + ctx->mEgl->Initialize(aApp->window); + ctx->mEgl->MakeCurrent(); + VRB_CHECK(glClearColor(0.0, 0.0, 0.0, 1.0)); + VRB_CHECK(glEnable(GL_DEPTH_TEST)); + VRB_CHECK(glEnable(GL_CULL_FACE)); + ctx->mWorld->InitializeGL(); + } else { + ctx->mEgl->SurfaceChanged(aApp->window); + ctx->mEgl->MakeCurrent(); + } + break; + + // The existing ANativeWindow needs to be terminated. Upon receiving this command, + // android_app->window still contains the existing window; + // after calling android_app_exec_cmd it will be set to NULL. + case APP_CMD_TERM_WINDOW: + VRB_LOG("APP_CMD_TERM_WINDOW"); + if (ctx->mEgl) { + ctx->mEgl->SurfaceDestroyed(); + } + break; + // The app's activity has been paused. + case APP_CMD_PAUSE: + VRB_LOG("APP_CMD_PAUSE"); + ctx->mWorld->Pause(); + break; + + // The app's activity has been resumed. + case APP_CMD_RESUME: + VRB_LOG("APP_CMD_RESUME"); + ctx->mWorld->Resume(); + break; + + // the app's activity is being destroyed, + // and waiting for the app thread to clean up and exit before proceeding. + case APP_CMD_DESTROY: + VRB_LOG("APP_CMD_DESTROY"); + ctx->mWorld->ShutdownJava(); + break; + + default: + break; } } -JNI_METHOD(void, activityResumed) -(JNIEnv*, jobject) { - if (sWorld) { - sWorld->Resume(); - } -} - -JNI_METHOD(void, activityCreated) -(JNIEnv* aEnv, jobject aActivity, jobject aAssetManager) { - if (!sWorld) { - sWorld = BrowserWorld::Create(); - } - sWorld->InitializeJava(aEnv, aActivity, aAssetManager); -} - -JNI_METHOD(void, activityDestroyed) -(JNIEnv* env, jobject) { - if (sWorld) { - sWorld->ShutdownJava(); - } -} +void +android_main(android_app *aAppState) { + pthread_setname_np(pthread_self(), "VRRenderer"); -JNI_METHOD(void, initializeGL) -(JNIEnv*, jobject) { - if (!sWorld) { - sWorld = BrowserWorld::Create(); + if (!ALooper_forThread()) { + ALooper_prepare(0); } - sWorld->InitializeGL(); -} - -JNI_METHOD(void, updateGL) -(JNIEnv*, jobject, int width, int height) { - VRB_CHECK(glViewport(0, 0, width, height)); - VRB_CHECK(glClearColor(0.0, 0.0, 0.0, 1.0)); - VRB_CHECK(glEnable(GL_DEPTH_TEST)); - VRB_CHECK(glEnable(GL_CULL_FACE)); - // VRB_CHECK(glDisable(GL_CULL_FACE)); - sWorld->SetViewport(width, height); -} - - - -JNI_METHOD(void, drawGL) -(JNIEnv*, jobject) { - VRB_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); - sWorld->Draw(); -} - -JNI_METHOD(void, shutdownGL) -(JNIEnv*, jobject) { - if (sWorld) { - sWorld->ShutdownGL(); + // Attach JNI thread + JNIEnv *jniEnv; + (*aAppState->activity->vm).AttachCurrentThread(&jniEnv, NULL); + + // Create Browser context + auto appContext = std::make_shared(); + appContext->mQueue = vrb::RunnableQueue::Create(aAppState->activity->vm); + appContext->mWorld = BrowserWorld::Create(); + + // Set up activity & SurfaceView life cycle callbacks + aAppState->userData = appContext.get(); + aAppState->onAppCmd = CommandCallback; + + // Main render loop + while (true) { + int events; + android_poll_source *pSource; + + // Loop until all events are read + // If the activity is paused use a blocking call to read events. + while (ALooper_pollAll(appContext->mWorld->IsPaused() ? -1 : 0, + NULL, + &events, + (void **) &pSource) >= 0) { + // Process event. + if (pSource) { + pSource->process(aAppState, pSource); + } + + // Check if we are exiting. + if (aAppState->destroyRequested != 0) { + appContext->mWorld->ShutdownGL(); + appContext->mEgl->Destroy(); + aAppState->activity->vm->DetachCurrentThread(); + exit(0); + } + } + + appContext->mQueue->ProcessRunnables(); + if (!appContext->mWorld->IsPaused() && appContext->mEgl && appContext->mEgl->IsSurfaceReady()) { + VRB_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); + appContext->mWorld->Draw(); + } } } - -} // extern "C" \ No newline at end of file diff --git a/app/src/main/java/org/mozilla/vrbrowser/VRBrowserActivity.java b/app/src/main/java/org/mozilla/vrbrowser/VRBrowserActivity.java deleted file mode 100644 index b05447877..000000000 --- a/app/src/main/java/org/mozilla/vrbrowser/VRBrowserActivity.java +++ /dev/null @@ -1,178 +0,0 @@ -/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.vrbrowser; - -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.opengl.GLSurfaceView; -import android.os.Bundle; -import android.util.Log; -import android.graphics.SurfaceTexture; -import android.view.Surface; -import android.view.SurfaceHolder; - -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; - -import org.mozilla.gecko.GeckoSession; - -public class VRBrowserActivity extends Activity { - static String LOGTAG = "VRBrowser"; - static final String DEFAULT_URL = "https://mozvr.com"; - // Used to load the 'native-lib' library on application startup. - static { - System.loadLibrary("native-lib"); - } - - private GLSurfaceView mView; - private static GeckoSession mSession; - private static Surface mBrowserSurface; - - private final Runnable activityCreatedRunnable = new Runnable() { - @Override - public void run() { - activityCreated(getAssets()); - } - }; - - private final Runnable activityDestroyedRunnable = new Runnable() { - @Override - public void run() { - activityDestroyed(); - } - }; - - private final Runnable activityPausedRunnable = new Runnable() { - @Override - public void run() { - synchronized (this) { - activityPaused(); - shutdownGL(); - notifyAll(); - } - } - }; - - private final Runnable activityResumedRunnable = new Runnable() { - @Override - public void run() { - activityResumed(); - } - }; - - @Override - protected void onCreate(Bundle savedInstanceState) { - Log.e(LOGTAG,"in onCreate"); - super.onCreate(savedInstanceState); - if (mSession == null) { - mSession = new GeckoSession(); - } - mView = new GLSurfaceView(this); - mView.setEGLContextClientVersion(3); - mView.setEGLConfigChooser(8, 8, 8, 0, 16, 0); - //mView.setPreserveEGLContextOnPause(true); - mView.setRenderer( - new GLSurfaceView.Renderer() { - @Override - public void onSurfaceCreated(GL10 gl, EGLConfig config) { - Log.e(LOGTAG, "In onSurfaceCreated"); - initializeGL(); - } - - @Override - public void onSurfaceChanged(GL10 gl, int width, int height) { - Log.e(LOGTAG, "In onSurfaceChanged"); - updateGL(width, height); - } - - @Override - public void onDrawFrame(GL10 gl) { - //Log.e(LOGTAG, "in onDrawFrame"); - drawGL(); - } - }); - mView.queueEvent(activityCreatedRunnable); - setContentView(mView); - loadFromIntent(getIntent()); - } - - @Override - protected void onNewIntent(final Intent intent) { - Log.e(LOGTAG,"In onNewIntent"); - super.onNewIntent(intent); - setIntent(intent); - final String action = intent.getAction(); - if (Intent.ACTION_VIEW.equals(action)) { - if (intent.getData() != null) { - loadFromIntent(intent); - } - } - } - - private void loadFromIntent(final Intent intent) { - final Uri uri = intent.getData(); - Log.e(LOGTAG, "Load URI from intent: " + (uri != null ? uri.toString() : DEFAULT_URL)); - String uriValue = (uri != null ? uri.toString() : DEFAULT_URL); - mSession.loadUri(uriValue); - } - - @Override - protected void onPause() { - Log.e(LOGTAG, "In onPause"); - synchronized (activityPausedRunnable) { - mView.queueEvent(activityPausedRunnable); - try { - activityPausedRunnable.wait(); - } catch(InterruptedException e) { - - } - } - mView.onPause(); - super.onPause(); - } - - @Override - protected void onResume() { - Log.e(LOGTAG, "in onResume"); - super.onResume(); - mView.onResume(); - mView.queueEvent(activityResumedRunnable); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mView.queueEvent(activityDestroyedRunnable); - } - - private void setSurfaceTexture(String aName, final SurfaceTexture aTexture, final int aWidth, final int aHeight) { - runOnUiThread(new Runnable() { - public void run() { - createBrowser(aTexture, aWidth, aHeight); - } - }); - } - - private void createBrowser(SurfaceTexture aTexture, int aWidth, int aHeight) { - if (aTexture != null) { - Log.e(LOGTAG,"In createBrowser"); - aTexture.setDefaultBufferSize(aWidth, aHeight); - mBrowserSurface = new Surface(aTexture); - mSession.acquireDisplay().surfaceChanged(mBrowserSurface, aWidth, aHeight); - mSession.openWindow(this); - } - } - - private native void activityCreated(Object aAssetManager); - private native void activityPaused(); - private native void activityResumed(); - private native void activityDestroyed(); - private native void initializeGL(); - private native void updateGL(int width, int height); - private native void shutdownGL(); - private native void drawGL(); -} diff --git a/app/src/oculusvr/AndroidManifest.xml b/app/src/oculusvr/AndroidManifest.xml index 690489ab0..4aa2006b8 100644 --- a/app/src/oculusvr/AndroidManifest.xml +++ b/app/src/oculusvr/AndroidManifest.xml @@ -3,6 +3,7 @@ + diff --git a/app/src/svr/AndroidManifest.xml b/app/src/svr/AndroidManifest.xml index 585144010..4ca879e12 100644 --- a/app/src/svr/AndroidManifest.xml +++ b/app/src/svr/AndroidManifest.xml @@ -8,6 +8,7 @@ +