Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Commit

Permalink
Use a Virtual display to host UI Widgets
Browse files Browse the repository at this point in the history
  • Loading branch information
MortimerGoro committed Feb 26, 2018
1 parent 3ba2813 commit 261001a
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,18 @@
package org.mozilla.vrbrowser;

import android.app.NativeActivity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;

public class PlatformActivity extends NativeActivity {
static String LOGTAG = "VRBrowser";
private FrameLayout mFrameLayout;

@Override
protected void onCreate(Bundle savedInstanceState) {
Log.e(LOGTAG,"in onCreate");
super.onCreate(savedInstanceState);

getWindow().takeSurface(null);
getWindow().takeInputQueue(null);

mFrameLayout = new FrameLayout(this);
SurfaceView surfaceView = new SurfaceView(this);
surfaceView.setClickable(true);
surfaceView.getHolder().addCallback(this);
surfaceView.setZOrderOnTop(true);
mFrameLayout.addView(surfaceView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));

setContentView(mFrameLayout);
}

protected void addWidget(View aView, int aWidth, int aHeight) {
mFrameLayout.addView(aView, 0, new FrameLayout.LayoutParams(aWidth, aHeight));
}
protected native void queueRunnable(Runnable aRunnable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
import android.content.Intent;
import android.graphics.SurfaceTexture;
import android.net.Uri;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.os.Bundle;
import android.support.annotation.Keep;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;

import org.mozilla.gecko.GeckoSession;
import org.mozilla.vrbrowser.ui.OffscreenDisplay;

import java.util.HashMap;

Expand All @@ -29,14 +33,23 @@ public class VRBrowserActivity extends PlatformActivity {
String mTargetUrl;
BrowserWidget mCurrentBrowser;
HashMap<Integer, Widget> mWidgets;
OffscreenDisplay mOffscreenDisplay;
FrameLayout mWidgetContainer;

@Override
protected void onCreate(Bundle savedInstanceState) {
Log.e(LOGTAG,"In onCreate");
super.onCreate(savedInstanceState);

mWidgets = new HashMap<>();
mWidgetContainer = new FrameLayout(this);
loadFromIntent(getIntent());
queueRunnable(new Runnable() {
@Override
public void run() {
createOffscreenDisplay();
}
});
}

@Override
Expand Down Expand Up @@ -82,7 +95,7 @@ void createWidget(final int aType, final int aHandle, SurfaceTexture aTexture, i

if (aType != Widget.Browser) {
// Add hidden UI widget to the platform window for invalidation
addWidget((View) widget, aWidth, aHeight);
mWidgetContainer.addView((View) widget, new FrameLayout.LayoutParams(aWidth, aHeight));
}
}

Expand All @@ -107,4 +120,28 @@ public void run() {
}
});
}

void createOffscreenDisplay() {
int[] ids = new int[1];
GLES20.glGenTextures(1, ids, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, ids[0]);

GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
int error = GLES20.glGetError();
if (error != GLES20.GL_NO_ERROR) {
Log.e(LOGTAG, "OpenGL Error creating OffscreenDisplay: " + error);
}

final SurfaceTexture texture = new SurfaceTexture(ids[0]);
runOnUiThread(new Runnable() {
@Override
public void run() {
mOffscreenDisplay = new OffscreenDisplay(VRBrowserActivity.this, texture, 16, 16);
mOffscreenDisplay.setContentView(mWidgetContainer);
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/* -*- 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.ui;

import android.app.Presentation;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.SurfaceTexture;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.View;

public class OffscreenDisplay {
private Context mContext;
private VirtualDisplay mVirtualDisplay;
private SurfaceTexture mTexture;
private Surface mSurface;
private OffscreenPresentation mPresentation;

private DisplayMetrics mDefaultMetrics;

public OffscreenDisplay(Context aContext, SurfaceTexture aTexture, int aWidth, int aHeight) {
mContext = aContext;
aTexture.setDefaultBufferSize(aWidth, aHeight);
mSurface = new Surface(aTexture);

DisplayManager manager = (DisplayManager) aContext.getSystemService(Context.DISPLAY_SERVICE);
Display defaultDisplay = manager.getDisplay(Display.DEFAULT_DISPLAY);

mDefaultMetrics = new DisplayMetrics();
defaultDisplay.getMetrics(mDefaultMetrics);

int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY |
DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION |
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;

mVirtualDisplay = manager.createVirtualDisplay("OffscreenViews", aWidth, aHeight,
mDefaultMetrics.densityDpi, mSurface, flags);

mPresentation = new OffscreenPresentation(mContext, mVirtualDisplay.getDisplay());
mPresentation.show();
}

public void setContentView(View aView) {
if (mPresentation == null) {
throw new IllegalStateException("No presentation!");
}

mPresentation.setContentView(aView);
}

public void resize(int aWidth, int aHeight) {
if (mVirtualDisplay == null) {
throw new IllegalStateException("No virtual display!");
}

mVirtualDisplay.resize(aWidth, aHeight, mDefaultMetrics.densityDpi);
}

public void release() {
if (mPresentation != null) {
mPresentation.dismiss();
mPresentation = null;
}

if (mVirtualDisplay != null) {
mVirtualDisplay.release();
mVirtualDisplay = null;
}

if (mSurface != null) {
mSurface.release();
}

if (mTexture != null) {
mTexture.release();
}
}

class OffscreenPresentation extends Presentation {
OffscreenPresentation(Context context, Display display) {
super(context, display);
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
}
57 changes: 38 additions & 19 deletions app/src/main/cpp/native-lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,17 @@

#define JNI_METHOD(return_type, method_name) \
JNIEXPORT return_type JNICALL \
Java_org_mozilla_vrbrowser_VRBrowserActivity_##method_name
Java_org_mozilla_vrbrowser_PlatformActivity_##method_name

using namespace crow;

static
jobject GetAssetManager(JNIEnv * aEnv, jobject aActivity) {
namespace {

jobject
GetAssetManager(JNIEnv *aEnv, jobject aActivity) {
jclass clazz = aEnv->GetObjectClass(aActivity);
jmethodID method = aEnv->GetMethodID(clazz, "getAssets", "()Landroid/content/res/AssetManager;");
jobject result = aEnv->CallObjectMethod(aActivity, method);
jobject result = aEnv->CallObjectMethod(aActivity, method);
if (!result) {
VRB_LOG("Failed to get AssetManager instance!");
}
Expand All @@ -43,6 +45,10 @@ struct AppContext {
BrowserEGLContextPtr mEgl;
DeviceDelegateOculusVRPtr mDevice;
};
typedef std::shared_ptr<AppContext> AppContextPtr;

AppContextPtr sAppContext;
}

void
CommandCallback(android_app *aApp, int32_t aCmd) {
Expand Down Expand Up @@ -114,6 +120,8 @@ CommandCallback(android_app *aApp, int32_t aCmd) {
}
}

extern "C" {

void
android_main(android_app *aAppState) {

Expand All @@ -126,21 +134,22 @@ android_main(android_app *aAppState) {
(*aAppState->activity->vm).AttachCurrentThread(&jniEnv, NULL);

// Create Browser context
auto appContext = std::make_shared<AppContext>();
appContext->mQueue = vrb::RunnableQueue::Create(aAppState->activity->vm);
appContext->mWorld = BrowserWorld::Create();
sAppContext = std::make_shared<AppContext>();
sAppContext->mQueue = vrb::RunnableQueue::Create(aAppState->activity->vm);
sAppContext->mWorld = BrowserWorld::Create();

// Create device delegate
appContext->mDevice = DeviceDelegateOculusVR::Create(appContext->mWorld->GetWeakContext(), aAppState);
appContext->mWorld->RegisterDeviceDelegate(appContext->mDevice);
sAppContext->mDevice = DeviceDelegateOculusVR::Create(sAppContext->mWorld->GetWeakContext(),
aAppState);
sAppContext->mWorld->RegisterDeviceDelegate(sAppContext->mDevice);

// Initialize java
auto assetManager = GetAssetManager(jniEnv, aAppState->activity->clazz);
appContext->mWorld->InitializeJava(jniEnv, aAppState->activity->clazz, assetManager);
sAppContext->mWorld->InitializeJava(jniEnv, aAppState->activity->clazz, assetManager);
jniEnv->DeleteLocalRef(assetManager);

// Set up activity & SurfaceView life cycle callbacks
aAppState->userData = appContext.get();
aAppState->userData = sAppContext.get();
aAppState->onAppCmd = CommandCallback;

// Main render loop
Expand All @@ -150,7 +159,7 @@ android_main(android_app *aAppState) {

// 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,
while (ALooper_pollAll(sAppContext->mWorld->IsPaused() ? -1 : 0,
NULL,
&events,
(void **) &pSource) >= 0) {
Expand All @@ -161,19 +170,29 @@ android_main(android_app *aAppState) {

// Check if we are exiting.
if (aAppState->destroyRequested != 0) {
appContext->mWorld->ShutdownGL();
appContext->mEgl->Destroy();
sAppContext->mWorld->ShutdownGL();
sAppContext->mEgl->Destroy();
aAppState->activity->vm->DetachCurrentThread();
sAppContext.reset();
exit(0);
}
}
if (appContext->mEgl) {
appContext->mEgl->MakeCurrent();
if (sAppContext->mEgl) {
sAppContext->mEgl->MakeCurrent();
}
appContext->mQueue->ProcessRunnables();
if (!appContext->mWorld->IsPaused() && appContext->mDevice->IsInVRMode()) {
sAppContext->mQueue->ProcessRunnables();
if (!sAppContext->mWorld->IsPaused() && sAppContext->mDevice->IsInVRMode()) {
VRB_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
appContext->mWorld->Draw();
sAppContext->mWorld->Draw();
}
}
}

JNI_METHOD(void, queueRunnable)
(JNIEnv *aEnv, jobject, jobject aRunnable) {
if (sAppContext) {
sAppContext->mQueue->AddRunnable(aEnv, aRunnable);
}
}

} // extern "C"
41 changes: 0 additions & 41 deletions app/src/wavevr/java/org/mozilla/vrbrowser/PlatformActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@
import com.htc.vr.sdk.VRActivity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
import java.lang.reflect.Field;

public class PlatformActivity extends VRActivity {
static final String LOGTAG = "VRB";
Expand All @@ -27,19 +22,6 @@ public PlatformActivity() {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Render to our SurfaceView instead of letting VRActivity take ownership of the window.
SurfaceHolder.Callback2 callback = getVRActivitySurfaceCallback();
if (callback != null) {
getWindow().takeSurface(null);
SurfaceView surfaceView = new SurfaceView(this);
surfaceView.setClickable(true);
surfaceView.getHolder().addCallback(callback);
surfaceView.setZOrderOnTop(true);
mFrameLayout = new FrameLayout(this);
mFrameLayout.addView(surfaceView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
setContentView(mFrameLayout);
}

queueRunnable(new Runnable() {
@Override
public void run() {
Expand All @@ -48,29 +30,6 @@ public void run() {
});
}

protected void addWidget(View aView, int aWidth, int aHeight) {
if (mFrameLayout != null) {
mFrameLayout.addView(aView, 0, new FrameLayout.LayoutParams(aWidth, aHeight));
}
}

private SurfaceHolder.Callback2 getVRActivitySurfaceCallback() {
try {
Field fPlatform = VRActivity.class.getDeclaredField("mVRPlatform");
fPlatform.setAccessible(true);
Object platform = fPlatform.get(this);
Field fRenderer = platform.getClass().getDeclaredField("mSVRRenderBase");
fRenderer.setAccessible(true);
Object renderer = fRenderer.get(platform);
if (renderer != null && renderer instanceof SurfaceHolder.Callback) {
return (SurfaceHolder.Callback2) renderer;
}
} catch (Exception e) {
Log.e(LOGTAG, "Error getting SurfaceHolder.Callback from VRActivity:" + e.toString());
}
return null;
}

protected native void queueRunnable(Runnable aRunnable);
protected native void initializeJava(AssetManager aAssets);
}

0 comments on commit 261001a

Please sign in to comment.