diff --git a/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrPlayerActivity.java b/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrPlayerActivity.java
index 06b9fac487..5d465b494d 100644
--- a/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrPlayerActivity.java
+++ b/extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrPlayerActivity.java
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.google.android.exoplayer2.ext.gvr;
import android.content.Context;
@@ -21,8 +20,6 @@ import android.content.Intent;
import android.graphics.SurfaceTexture;
import android.opengl.Matrix;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
import android.view.ContextThemeWrapper;
import android.view.MotionEvent;
import android.view.Surface;
@@ -47,6 +44,7 @@ import com.google.vr.sdk.base.HeadTransform;
import com.google.vr.sdk.base.Viewport;
import com.google.vr.sdk.controller.Controller;
import com.google.vr.sdk.controller.ControllerManager;
+import com.google.vr.sdk.controller.Orientation;
import javax.microedition.khronos.egl.EGLConfig;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@@ -58,46 +56,36 @@ public abstract class GvrPlayerActivity extends GvrActivity {
private static final int EXIT_FROM_VR_REQUEST_CODE = 42;
- private final Handler mainHandler;
-
@Nullable private Player player;
- private @MonotonicNonNull GlViewGroup glView;
private @MonotonicNonNull ControllerManager controllerManager;
private @MonotonicNonNull SurfaceTexture surfaceTexture;
private @MonotonicNonNull Surface surface;
- private @MonotonicNonNull SceneRenderer scene;
- private @MonotonicNonNull PlayerControlView playerControl;
-
- public GvrPlayerActivity() {
- mainHandler = new Handler(Looper.getMainLooper());
- }
+ private @MonotonicNonNull SceneRenderer sceneRenderer;
+ private @MonotonicNonNull PlayerControlView playerControlView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setScreenAlwaysOn(true);
- GvrView gvrView = new GvrView(this);
- // Since videos typically have fewer pixels per degree than the phones, reducing the render
- // target scaling factor reduces the work required to render the scene.
- gvrView.setRenderTargetScale(.5f);
+ GvrView gvrView = new GvrView(/* context= */ this);
+ gvrView.setRenderTargetScale(getRenderTargetScale());
// If a custom theme isn't specified, the Context's theme is used. For VR Activities, this is
// the old Android default theme rather than a modern theme. Override this with a custom theme.
- Context theme = new ContextThemeWrapper(this, R.style.VrTheme);
- glView = new GlViewGroup(theme, R.layout.vr_ui);
+ Context theme = new ContextThemeWrapper(this, R.style.ExoVrTheme);
+ GlViewGroup glViewGroup = new GlViewGroup(theme, R.layout.exo_vr_ui);
- playerControl = Assertions.checkNotNull(glView.findViewById(R.id.controller));
- playerControl.setShowVrButton(true);
- playerControl.setVrButtonListener(v -> exit());
+ playerControlView = Assertions.checkNotNull(glViewGroup.findViewById(R.id.controller));
+ playerControlView.setShowVrButton(true);
+ playerControlView.setVrButtonListener(v -> exit());
+ sceneRenderer = new SceneRenderer();
PointerRenderer pointerRenderer = new PointerRenderer();
- scene = new SceneRenderer();
- Renderer renderer = new Renderer(scene, glView, pointerRenderer);
-
- // Attach glView to gvrView in order to properly handle UI events.
- gvrView.addView(glView, 0);
+ Renderer renderer = new Renderer(sceneRenderer, pointerRenderer, glViewGroup);
+ // Attach glViewGroup to gvrView in order to properly handle UI events.
+ gvrView.addView(glViewGroup);
// Standard GvrView configuration
gvrView.setEGLConfigChooser(
8, 8, 8, 8, // RGBA bits.
@@ -106,15 +94,13 @@ public abstract class GvrPlayerActivity extends GvrActivity {
gvrView.setRenderer(renderer);
setContentView(gvrView);
- // Most Daydream phones can render a 4k video at 60fps in sustained performance mode. These
- // options can be tweaked along with the render target scale.
if (gvrView.setAsyncReprojectionEnabled(true)) {
- AndroidCompat.setSustainedPerformanceMode(this, true);
+ AndroidCompat.setSustainedPerformanceMode(/* activity= */ this, true);
}
// Handle the user clicking on the 'X' in the top left corner. Since this is done when the user
// has taken the headset out of VR, it should launch the app's exit flow directly rather than
- // using the transition flow.
+ // using Daydream's exit transition.
gvrView.setOnCloseButtonListener(this::finish);
ControllerManager.EventListener listener =
@@ -126,15 +112,14 @@ public abstract class GvrPlayerActivity extends GvrActivity {
@Override
public void onRecentered() {
- // TODO if in cardboard mode call gvrView.recenterHeadTracker();
- glView.post(() -> Util.castNonNull(playerControl).show());
+ // TODO: If in cardboard mode call gvrView.recenterHeadTracker().
+ runOnUiThread(() -> Util.castNonNull(playerControlView).show());
}
};
controllerManager = new ControllerManager(this, listener);
-
Controller controller = controllerManager.getController();
ControllerEventListener controllerEventListener =
- new ControllerEventListener(controller, pointerRenderer, glView);
+ new ControllerEventListener(controller, pointerRenderer, glViewGroup);
controller.setEventListener(controllerEventListener);
}
@@ -144,7 +129,7 @@ public abstract class GvrPlayerActivity extends GvrActivity {
* @param newPlayer The {@link Player} to use, or {@code null} to detach the current player.
*/
protected void setPlayer(@Nullable Player newPlayer) {
- Assertions.checkNotNull(scene);
+ Assertions.checkNotNull(sceneRenderer);
if (player == newPlayer) {
return;
}
@@ -154,20 +139,20 @@ public abstract class GvrPlayerActivity extends GvrActivity {
if (surface != null) {
videoComponent.clearVideoSurface(surface);
}
- videoComponent.clearVideoFrameMetadataListener(scene);
- videoComponent.clearCameraMotionListener(scene);
+ videoComponent.clearVideoFrameMetadataListener(sceneRenderer);
+ videoComponent.clearCameraMotionListener(sceneRenderer);
}
}
player = newPlayer;
if (player != null) {
Player.VideoComponent videoComponent = player.getVideoComponent();
if (videoComponent != null) {
- videoComponent.setVideoFrameMetadataListener(scene);
- videoComponent.setCameraMotionListener(scene);
+ videoComponent.setVideoFrameMetadataListener(sceneRenderer);
+ videoComponent.setCameraMotionListener(sceneRenderer);
videoComponent.setVideoSurface(surface);
}
}
- Assertions.checkNotNull(playerControl).setPlayer(player);
+ Assertions.checkNotNull(playerControlView).setPlayer(player);
}
/**
@@ -177,7 +162,19 @@ public abstract class GvrPlayerActivity extends GvrActivity {
* @param stereoMode A {@link C.StereoMode} value.
*/
protected void setDefaultStereoMode(@C.StereoMode int stereoMode) {
- Assertions.checkNotNull(scene).setDefaultStereoMode(stereoMode);
+ Assertions.checkNotNull(sceneRenderer).setDefaultStereoMode(stereoMode);
+ }
+
+ /**
+ * Returns the render target scale passed to {@link GvrView#setRenderTargetScale(float)}. Since
+ * videos typically have fewer pixels per degree than the phone displays, the target can normally
+ * be lower than 1 to reduce the amount of work required to render the scene. The default value is
+ * 0.5.
+ *
+ * @return The render target scale passed to {@link GvrView#setRenderTargetScale(float)}.
+ */
+ protected float getRenderTargetScale() {
+ return 0.5f;
}
@CallSuper
@@ -210,12 +207,12 @@ public abstract class GvrPlayerActivity extends GvrActivity {
/** Tries to exit gracefully from VR using a VR transition dialog. */
@SuppressWarnings("nullness:argument.type.incompatible")
protected void exit() {
- // This needs to use GVR's exit transition to avoid disorienting the user.
- DaydreamApi api = DaydreamApi.create(this);
- if (api != null) {
- api.exitFromVr(this, EXIT_FROM_VR_REQUEST_CODE, null);
- // Eventually, the Activity's onActivityResult will be called.
- api.close();
+ DaydreamApi daydreamApi = DaydreamApi.create(this);
+ if (daydreamApi != null) {
+ // Use Daydream's exit transition to avoid disorienting the user. This will cause
+ // onActivityResult to be called.
+ daydreamApi.exitFromVr(/* activity= */ this, EXIT_FROM_VR_REQUEST_CODE, /* intent= */ null);
+ daydreamApi.close();
} else {
finish();
}
@@ -224,16 +221,16 @@ public abstract class GvrPlayerActivity extends GvrActivity {
/** Toggles PlayerControl visibility. */
@UiThread
protected void togglePlayerControlVisibility() {
- if (Assertions.checkNotNull(playerControl).isVisible()) {
- playerControl.hide();
+ if (Assertions.checkNotNull(playerControlView).isVisible()) {
+ playerControlView.hide();
} else {
- playerControl.show();
+ playerControlView.show();
}
}
- // Called on GL thread.
private void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture) {
- mainHandler.post(
+ // Called on the GL thread. Post to the main thread.
+ runOnUiThread(
() -> {
SurfaceTexture oldSurfaceTexture = this.surfaceTexture;
Surface oldSurface = this.surface;
@@ -260,18 +257,20 @@ public abstract class GvrPlayerActivity extends GvrActivity {
}
private class Renderer implements GvrView.StereoRenderer {
- private static final float Z_NEAR = .1f;
+ private static final float Z_NEAR = 0.1f;
private static final float Z_FAR = 100;
- private final float[] viewProjectionMatrix = new float[16];
- private final SceneRenderer scene;
- private final GlViewGroup glView;
+ private final SceneRenderer sceneRenderer;
private final PointerRenderer pointerRenderer;
+ private final GlViewGroup glViewGroup;
+ private final float[] viewProjectionMatrix;
- public Renderer(SceneRenderer scene, GlViewGroup glView, PointerRenderer pointerRenderer) {
- this.scene = scene;
- this.glView = glView;
+ public Renderer(
+ SceneRenderer sceneRenderer, PointerRenderer pointerRenderer, GlViewGroup glViewGroup) {
+ this.sceneRenderer = sceneRenderer;
this.pointerRenderer = pointerRenderer;
+ this.glViewGroup = glViewGroup;
+ viewProjectionMatrix = new float[16];
}
@Override
@@ -281,9 +280,9 @@ public abstract class GvrPlayerActivity extends GvrActivity {
public void onDrawEye(Eye eye) {
Matrix.multiplyMM(
viewProjectionMatrix, 0, eye.getPerspective(Z_NEAR, Z_FAR), 0, eye.getEyeView(), 0);
- scene.drawFrame(viewProjectionMatrix, eye.getType() == Eye.Type.RIGHT);
- if (glView.isVisible()) {
- glView.getRenderer().draw(viewProjectionMatrix);
+ sceneRenderer.drawFrame(viewProjectionMatrix, eye.getType() == Eye.Type.RIGHT);
+ if (glViewGroup.isVisible()) {
+ glViewGroup.getRenderer().draw(viewProjectionMatrix);
pointerRenderer.draw(viewProjectionMatrix);
}
}
@@ -293,8 +292,8 @@ public abstract class GvrPlayerActivity extends GvrActivity {
@Override
public void onSurfaceCreated(EGLConfig config) {
- onSurfaceTextureAvailable(scene.init());
- glView.getRenderer().init();
+ onSurfaceTextureAvailable(sceneRenderer.init());
+ glViewGroup.getRenderer().init();
pointerRenderer.init();
}
@@ -303,9 +302,9 @@ public abstract class GvrPlayerActivity extends GvrActivity {
@Override
public void onRendererShutdown() {
- glView.getRenderer().shutdown();
+ glViewGroup.getRenderer().shutdown();
pointerRenderer.shutdown();
- scene.shutdown();
+ sceneRenderer.shutdown();
}
}
@@ -313,16 +312,16 @@ public abstract class GvrPlayerActivity extends GvrActivity {
private final Controller controller;
private final PointerRenderer pointerRenderer;
- private final GlViewGroup glView;
+ private final GlViewGroup glViewGroup;
private final float[] controllerOrientationMatrix;
private boolean clickButtonDown;
private boolean appButtonDown;
public ControllerEventListener(
- Controller controller, PointerRenderer pointerRenderer, GlViewGroup glView) {
+ Controller controller, PointerRenderer pointerRenderer, GlViewGroup glViewGroup) {
this.controller = controller;
this.pointerRenderer = pointerRenderer;
- this.glView = glView;
+ this.glViewGroup = glViewGroup;
controllerOrientationMatrix = new float[16];
}
@@ -330,7 +329,8 @@ public abstract class GvrPlayerActivity extends GvrActivity {
@BinderThread
public void onUpdate() {
controller.update();
- controller.orientation.toRotationMatrix(controllerOrientationMatrix);
+ Orientation orientation = controller.orientation;
+ orientation.toRotationMatrix(controllerOrientationMatrix);
pointerRenderer.setControllerOrientation(controllerOrientationMatrix);
if (clickButtonDown || controller.clickButtonState) {
@@ -341,18 +341,19 @@ public abstract class GvrPlayerActivity extends GvrActivity {
} else {
action = MotionEvent.ACTION_MOVE;
}
- glView.post(
- () -> {
- float[] angles = controller.orientation.toYawPitchRollRadians(new float[3]);
- boolean clickedOnView = glView.simulateClick(action, angles[0], angles[1]);
- if (action == MotionEvent.ACTION_DOWN && !clickedOnView) {
- togglePlayerControlVisibility();
- }
- });
+ float[] yawPitchRoll = orientation.toYawPitchRollRadians(new float[3]);
+ runOnUiThread(() -> dispatchClick(action, yawPitchRoll[0], yawPitchRoll[1]));
} else if (!appButtonDown && controller.appButtonState) {
- glView.post(GvrPlayerActivity.this::togglePlayerControlVisibility);
+ runOnUiThread(GvrPlayerActivity.this::togglePlayerControlVisibility);
}
appButtonDown = controller.appButtonState;
}
+
+ private void dispatchClick(int action, float yaw, float pitch) {
+ boolean clickedOnView = glViewGroup.simulateClick(action, yaw, pitch);
+ if (action == MotionEvent.ACTION_DOWN && !clickedOnView) {
+ togglePlayerControlVisibility();
+ }
+ }
}
}
diff --git a/extensions/gvr/src/main/res/values-v21/styles.xml b/extensions/gvr/src/main/res/layout/exo_vr_ui.xml
similarity index 74%
rename from extensions/gvr/src/main/res/values-v21/styles.xml
rename to extensions/gvr/src/main/res/layout/exo_vr_ui.xml
index 276db1b42d..6863da9578 100644
--- a/extensions/gvr/src/main/res/values-v21/styles.xml
+++ b/extensions/gvr/src/main/res/layout/exo_vr_ui.xml
@@ -13,6 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-
-
+
diff --git a/extensions/gvr/src/main/res/layout/vr_ui.xml b/extensions/gvr/src/main/res/layout/vr_ui.xml
deleted file mode 100644
index e84ee31fe6..0000000000
--- a/extensions/gvr/src/main/res/layout/vr_ui.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
diff --git a/extensions/gvr/src/main/res/values/styles.xml b/extensions/gvr/src/main/res/values/styles.xml
index ab5fde106a..2affbb2f05 100644
--- a/extensions/gvr/src/main/res/values/styles.xml
+++ b/extensions/gvr/src/main/res/values/styles.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
-
+
diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/CanvasRenderer.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/CanvasRenderer.java
index ed9be4ea7e..82a9f48d04 100644
--- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/CanvasRenderer.java
+++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/CanvasRenderer.java
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.google.android.exoplayer2.ui.spherical;
import static com.google.android.exoplayer2.util.GlUtil.checkGlError;
diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/GlViewGroup.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/GlViewGroup.java
index 37ac8e98d0..3be8c3d6d7 100644
--- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/GlViewGroup.java
+++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/GlViewGroup.java
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.google.android.exoplayer2.ui.spherical;
import android.content.Context;
diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/PointerRenderer.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/PointerRenderer.java
index fa7118a0fb..c8773a2838 100644
--- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/PointerRenderer.java
+++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/PointerRenderer.java
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.google.android.exoplayer2.ui.spherical;
import static com.google.android.exoplayer2.util.GlUtil.checkGlError;
@@ -26,7 +25,7 @@ import java.nio.FloatBuffer;
/** Renders a pointer. */
public final class PointerRenderer {
// The pointer quad is 2 * SIZE units.
- private static final float SIZE = .01f;
+ private static final float SIZE = 0.01f;
private static final float DISTANCE = 1;
// Standard vertex shader.
diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java
index 419f31436a..d2089759f6 100644
--- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java
+++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java
@@ -55,7 +55,7 @@ public final class SphericalSurfaceView extends GLSurfaceView {
// Arbitrary vertical field of view.
private static final int FIELD_OF_VIEW_DEGREES = 90;
- private static final float Z_NEAR = .1f;
+ private static final float Z_NEAR = 0.1f;
private static final float Z_FAR = 100;
// TODO Calculate this depending on surface size and field of view.
@@ -84,7 +84,7 @@ public final class SphericalSurfaceView extends GLSurfaceView {
// Configure sensors and touch.
sensorManager =
(SensorManager) Assertions.checkNotNull(context.getSystemService(Context.SENSOR_SERVICE));
- Sensor orientationSensor = null;
+ @Nullable Sensor orientationSensor = null;
if (Util.SDK_INT >= 18) {
// TYPE_GAME_ROTATION_VECTOR is the easiest sensor since it handles all the complex math for
// fusion. It's used instead of TYPE_ROTATION_VECTOR since the latter uses the magnetometer on