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

Commit

Permalink
Implement WebXR Interstitial
Browse files Browse the repository at this point in the history
  • Loading branch information
MortimerGoro committed Apr 8, 2020
1 parent bce60f9 commit 6f7a696
Show file tree
Hide file tree
Showing 31 changed files with 565 additions and 190 deletions.
1 change: 0 additions & 1 deletion app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ add_library( # Sets the name of the library.
src/main/cpp/ExternalVR.cpp
src/main/cpp/GeckoSurfaceTexture.cpp
src/main/cpp/GestureDelegate.cpp
src/main/cpp/LoadingAnimation.cpp
src/main/cpp/JNIUtil.cpp
src/main/cpp/Pointer.cpp
src/main/cpp/Skybox.cpp
Expand Down
45 changes: 40 additions & 5 deletions app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import org.mozilla.vrbrowser.ui.widgets.TrayWidget;
import org.mozilla.vrbrowser.ui.widgets.UISurfaceTextureRenderer;
import org.mozilla.vrbrowser.ui.widgets.UIWidget;
import org.mozilla.vrbrowser.ui.widgets.WebXRInterstitialWidget;
import org.mozilla.vrbrowser.ui.widgets.Widget;
import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate;
import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement;
Expand Down Expand Up @@ -166,11 +167,13 @@ public void run() {
NavigationBarWidget mNavigationBar;
CrashDialogWidget mCrashDialog;
TrayWidget mTray;
WebXRInterstitialWidget mWebXRInterstitial;
PermissionDelegate mPermissionDelegate;
LinkedList<UpdateListener> mWidgetUpdateListeners;
LinkedList<PermissionListener> mPermissionListeners;
LinkedList<FocusChangeListener> mFocusChangeListeners;
LinkedList<WorldClickListener> mWorldClickListeners;
LinkedList<WebXRListener> mWebXRListeners;
CopyOnWriteArrayList<Delegate> mConnectivityListeners;
LinkedList<Runnable> mBackHandlers;
private boolean mIsPresentingImmersive = false;
Expand Down Expand Up @@ -260,6 +263,7 @@ protected void onCreate(Bundle savedInstanceState) {
mPermissionListeners = new LinkedList<>();
mFocusChangeListeners = new LinkedList<>();
mWorldClickListeners = new LinkedList<>();
mWebXRListeners = new LinkedList<>();
mBackHandlers = new LinkedList<>();
mBrightnessQueue = new LinkedList<>();
mConnectivityListeners = new CopyOnWriteArrayList<>();
Expand Down Expand Up @@ -323,6 +327,9 @@ protected void initializeWidgets() {
// Create keyboard widget
mKeyboard = new KeyboardWidget(this);

// Create the WebXR interstitial
mWebXRInterstitial = new WebXRInterstitialWidget(this);

// Windows
mWindows = new Windows(this);
mWindows.setDelegate(new Windows.Delegate() {
Expand Down Expand Up @@ -366,7 +373,7 @@ public void onWindowVideoAvailabilityChanged(@NonNull WindowWidget aWindow) {

attachToWindow(mWindows.getFocusedWindow(), null);

addWidgets(Arrays.asList(mRootWidget, mNavigationBar, mKeyboard, mTray));
addWidgets(Arrays.asList(mRootWidget, mNavigationBar, mKeyboard, mTray, mWebXRInterstitial));

// Show the what's upp dialog if we haven't showed it yet and this is v6.
if (!SettingsStore.getInstance(this).isWhatsNewDisplayed()) {
Expand Down Expand Up @@ -956,14 +963,20 @@ public void run() {

@Keep
@SuppressWarnings("unused")
void pauseGeckoViewCompositor() {
void onEnterWebXR() {
if (Thread.currentThread() == mUiThread) {
return;
}
mIsPresentingImmersive = true;
mWindows.enterImmersiveMode();
runOnUiThread(() -> {
mWindows.enterImmersiveMode();
for (WebXRListener listener: mWebXRListeners) {
listener.onEnterWebXR();
}
});
TelemetryWrapper.startImmersive();
GleanMetricsService.startImmersive();

PauseCompositorRunnable runnable = new PauseCompositorRunnable();

synchronized (mCompositorLock) {
Expand All @@ -980,12 +993,18 @@ void pauseGeckoViewCompositor() {

@Keep
@SuppressWarnings("unused")
void resumeGeckoViewCompositor() {
void onExitWebXR() {
if (Thread.currentThread() == mUiThread) {
return;
}
mIsPresentingImmersive = false;
mWindows.exitImmersiveMode();
runOnUiThread(() -> {
mWindows.exitImmersiveMode();
for (WebXRListener listener: mWebXRListeners) {
listener.onExitWebXR();
}
});

// Show the window in front of you when you exit immersive mode.
resetUIYaw();

Expand Down Expand Up @@ -1364,6 +1383,21 @@ public void removeWorldClickListener(WorldClickListener aListener) {
mWorldClickListeners.remove(aListener);
}

@Override
public void addWebXRListener(WebXRListener aListener) {
mWebXRListeners.add(aListener);
}

@Override
public void removeWebXRListener(WebXRListener aListener) {
mWebXRListeners.remove(aListener);
}

@Override
public void setWebXRIntersitialForced(boolean aForced) {
queueRunnable(() -> setWebXRIntersitialForcedNative(aForced));
}

@Override
public void addConnectivityListener(Delegate aListener) {
if (!mConnectivityListeners.contains(aListener)) {
Expand Down Expand Up @@ -1596,5 +1630,6 @@ public void updateLocale(@NonNull Context context) {
private native void runCallbackNative(long aCallback);
private native void setCylinderDensityNative(float aDensity);
private native void setCPULevelNative(@CPULevelFlags int aCPULevel);
private native void setWebXRIntersitialForcedNative(boolean aForced);
private native void setIsServo(boolean aIsServo);
}
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,6 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) {
aPlacement.parentAnchorX = 0.5f;
aPlacement.parentAnchorY = 0.0f;
aPlacement.translationY = -35;
aPlacement.opaque = false;
aPlacement.cylinder = true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) {
aPlacement.parentAnchorX = 0.5f;
aPlacement.parentAnchorY = 0.0f;
aPlacement.translationY = -35;
aPlacement.opaque = false;
aPlacement.cylinder = true;
aPlacement.visible = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) {
aPlacement.anchorY = 0.0f;
aPlacement.parentAnchorX = 0.5f;
aPlacement.parentAnchorY = 1.0f;
aPlacement.opaque = false;
}

private void updateUI() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,6 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) {
aPlacement.parentAnchorY = 0.0f;
aPlacement.rotationAxisX = 1.0f;
aPlacement.rotation = (float)Math.toRadians(-45);
aPlacement.opaque = false;
aPlacement.cylinder = false;
aPlacement.textureScale = 1.0f;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.mozilla.vrbrowser.ui.widgets;

import android.content.Context;
import android.view.LayoutInflater;

import androidx.annotation.IntDef;
import androidx.databinding.DataBindingUtil;

import org.mozilla.vrbrowser.R;
import org.mozilla.vrbrowser.VRBrowserActivity;
import org.mozilla.vrbrowser.databinding.WebxrInterstitialControllerBinding;
import org.mozilla.vrbrowser.utils.DeviceType;

public class WebXRInterstitialController extends UIWidget {
private WebxrInterstitialControllerBinding mBinding;


@IntDef(value = { HAND_NONE, HAND_LEFT, HAND_RIGHT })
public @interface Hand {}
public static final int HAND_NONE = -1;
public static final int HAND_LEFT = 0;
public static final int HAND_RIGHT = 1;

public WebXRInterstitialController(Context aContext, int aModel, @Hand int aHand ) {
super(aContext);
initialize(aModel, aHand);
}

@Override
protected void initializeWidgetPlacement(WidgetPlacement aPlacement) {
aPlacement.scene = WidgetPlacement.SCENE_WEBXR_INTERSTITIAL;
aPlacement.visible = false;
}

private void updatePlacement() {
mWidgetPlacement.setSizeFromMeasure(getContext(), this);
if (mBinding.getHand() == HAND_LEFT) {
mWidgetPlacement.anchorX = 1.0f;
mWidgetPlacement.anchorY = 0.5f;
mWidgetPlacement.parentAnchorX = 0.0f;
mWidgetPlacement.parentAnchorY = 0.5f;
mWidgetPlacement.translationX = -WidgetPlacement.dpDimension(getContext(), R.dimen.webxr_interstitial_controller_margin);
} else if (mBinding.getHand() == HAND_RIGHT) {
mWidgetPlacement.anchorX = 0.0f;
mWidgetPlacement.anchorY = 0.5f;
mWidgetPlacement.parentAnchorX = 1.0f;
mWidgetPlacement.parentAnchorY = 0.5f;
mWidgetPlacement.translationX = WidgetPlacement.dpDimension(getContext(), R.dimen.webxr_interstitial_controller_margin);
} else {
mWidgetPlacement.anchorX = 0.5f;
mWidgetPlacement.anchorY = 1.0f;
mWidgetPlacement.parentAnchorX = 0.5f;
mWidgetPlacement.parentAnchorY = 0.0f;
mWidgetPlacement.translationX = -WidgetPlacement.dpDimension(getContext(), R.dimen.webxr_interstitial_controller_margin);
}
}

private void initialize(int aModel, @Hand int aHand) {
LayoutInflater inflater = LayoutInflater.from(getContext());
mBinding = DataBindingUtil.inflate(inflater, R.layout.webxr_interstitial_controller, this, true);
mBinding.setLifecycleOwner((VRBrowserActivity)getContext());
mBinding.setModel(aModel);
mBinding.setHand(aHand);
mBinding.executePendingBindings();
updatePlacement();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package org.mozilla.vrbrowser.ui.widgets;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;

import androidx.databinding.DataBindingUtil;

import org.mozilla.vrbrowser.R;
import org.mozilla.vrbrowser.VRBrowserActivity;
import org.mozilla.vrbrowser.databinding.WebxrInterstitialBinding;
import org.mozilla.vrbrowser.utils.DeviceType;

import java.util.ArrayList;

public class WebXRInterstitialWidget extends UIWidget implements WidgetManagerDelegate.WebXRListener {
private static final int INTERSTITIAL_FORCE_TIME = 3000;
private WebxrInterstitialBinding mBinding;
private Animation mAnimation;
private ArrayList<WebXRInterstitialController> mControllers = new ArrayList<>();
private boolean firstEnterXR = true;

public WebXRInterstitialWidget(Context aContext) {
super(aContext);
initialize();
}

@Override
protected void initializeWidgetPlacement(WidgetPlacement aPlacement) {
Context context = getContext();
aPlacement.scene = WidgetPlacement.SCENE_WEBXR_INTERSTITIAL;
aPlacement.width = WidgetPlacement.dpDimension(context, R.dimen.webxr_interstitial_width);
aPlacement.height = WidgetPlacement.dpDimension(context, R.dimen.webxr_interstitial_height);
aPlacement.worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.window_world_width) * aPlacement.width / getWorldWidth();
aPlacement.translationY = WidgetPlacement.unitFromMeters(context, R.dimen.webxr_interstitial_world_y);
aPlacement.translationZ = WidgetPlacement.unitFromMeters(getContext(), R.dimen.webxr_interstitial_world_z);
aPlacement.anchorX = 0.5f;
aPlacement.anchorY = 0.5f;
}

private void initialize() {
LayoutInflater inflater = LayoutInflater.from(getContext());
mBinding = DataBindingUtil.inflate(inflater, R.layout.webxr_interstitial, this, true);
mBinding.setLifecycleOwner((VRBrowserActivity)getContext());

mAnimation = new RotateAnimation(
0, 360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
);
mAnimation.setDuration(1000);
mAnimation.setRepeatCount(Animation.INFINITE);
mWidgetManager.addWebXRListener(this);
}

@Override
public void releaseWidget() {
mWidgetManager.removeWebXRListener(this);
super.releaseWidget();
}

private void addController(@DeviceType.Type int aDevice, @WebXRInterstitialController.Hand int aHand) {
mControllers.add(new WebXRInterstitialController(getContext(), aDevice, aHand));
}

private void initializeControllers() {
int deviceType = DeviceType.getType();
if (deviceType == DeviceType.OculusGo) {
addController(DeviceType.OculusGo, WebXRInterstitialController.HAND_NONE);
} else if (deviceType == DeviceType.OculusQuest) {
addController(DeviceType.OculusQuest, WebXRInterstitialController.HAND_LEFT);
addController(DeviceType.OculusQuest, WebXRInterstitialController.HAND_RIGHT);
}
for (UIWidget controller: mControllers) {
controller.getPlacement().parentHandle = getHandle();
}
}

private void showControllers() {
if (mControllers.size() == 0) {
initializeControllers();
}

for (UIWidget widget: mControllers) {
widget.show(KEEP_FOCUS);
}
}

private void hideControllers() {
for (UIWidget widget: mControllers) {
widget.hide(KEEP_WIDGET);
}
}

private void startAnimation() {
mBinding.webxrSpinner.startAnimation(mAnimation);
}

private void stopAnimation() {
mBinding.webxrSpinner.clearAnimation();
}

@Override
public void onEnterWebXR() {
startAnimation();
if (firstEnterXR) {
firstEnterXR = false;
showControllers();
postDelayed(() -> {
if (mWidgetManager != null) {
mWidgetManager.setWebXRIntersitialForced(false);
}
}, INTERSTITIAL_FORCE_TIME);
}
}


@Override
public void onExitWebXR() {
stopAnimation();
hideControllers();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ interface WorldClickListener {
void onWorldClick();
}

interface WebXRListener {
void onEnterWebXR();
void onExitWebXR();
}

float DEFAULT_DIM_BRIGHTNESS = 0.25f;
float DEFAULT_NO_DIM_BRIGHTNESS = 1.0f;

Expand Down Expand Up @@ -76,6 +81,9 @@ interface WorldClickListener {
void removePermissionListener(PermissionListener aListener);
void addWorldClickListener(WorldClickListener aListener);
void removeWorldClickListener(WorldClickListener aListener);
void addWebXRListener(WebXRListener aListener);
void removeWebXRListener(WebXRListener aListener);
void setWebXRIntersitialForced(boolean aForced);
boolean isPermissionGranted(@NonNull String permission);
void requestPermission(String uri, @NonNull String permission, GeckoSession.PermissionDelegate.Callback aCallback);
boolean canOpenNewWindow();
Expand Down
Loading

0 comments on commit 6f7a696

Please sign in to comment.