Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

180/360/3D video support #725

Merged
merged 1 commit into from Nov 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions app/CMakeLists.txt
Expand Up @@ -35,6 +35,7 @@ add_library( # Sets the name of the library.
src/main/cpp/JNIUtil.cpp
src/main/cpp/SplashAnimation.cpp
src/main/cpp/VRBrowser.cpp
src/main/cpp/VRVideo.cpp
src/main/cpp/Widget.cpp
src/main/cpp/WidgetPlacement.cpp
src/main/cpp/WidgetResizer.cpp
Expand Down
25 changes: 25 additions & 0 deletions app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java
Expand Up @@ -48,6 +48,7 @@
import org.mozilla.vrbrowser.ui.widgets.RootWidget;
import org.mozilla.vrbrowser.ui.widgets.TopBarWidget;
import org.mozilla.vrbrowser.ui.widgets.TrayWidget;
import org.mozilla.vrbrowser.ui.widgets.VideoProjectionMenuWidget;
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 @@ -806,6 +807,11 @@ public void setTrayVisible(boolean visible) {
}
}

@Override
public void setControllersVisible(final boolean aVisible) {
queueRunnable(() -> setControllersVisibleNative(aVisible));
}

@Override
public void setBrowserSize(float targetWidth, float targetHeight) {
mBrowserWidget.setBrowserSize(targetWidth, targetHeight, 1.0f);
Expand Down Expand Up @@ -849,6 +855,21 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions, in
}
}

@Override
public void showVRVideo(final int aWindowHandle, final @VideoProjectionMenuWidget.VideoProjectionFlags int aVideoProjection) {
queueRunnable(() -> showVRVideoNative(aWindowHandle, aVideoProjection));
}

@Override
public void hideVRVideo() {
queueRunnable(this::hideVRVideoNative);
}

@Override
public void resetUIYaw() {
queueRunnable(this::resetUIYawNative);
}

private native void addWidgetNative(int aHandle, WidgetPlacement aPlacement);
private native void updateWidgetNative(int aHandle, WidgetPlacement aPlacement);
private native void removeWidgetNative(int aHandle);
Expand All @@ -860,4 +881,8 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions, in
private native void workaroundGeckoSigAction();
private native void updateEnvironmentNative();
private native void updatePointerColorNative();
private native void showVRVideoNative(int aWindowHandler, int aVideoProjection);
private native void hideVRVideoNative();
private native void resetUIYawNative();
private native void setControllersVisibleNative(boolean aVisible);
}
198 changes: 198 additions & 0 deletions app/src/common/shared/org/mozilla/vrbrowser/browser/Media.java
@@ -0,0 +1,198 @@
package org.mozilla.vrbrowser.browser;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import org.mozilla.geckoview.MediaElement;

public class Media implements MediaElement.Delegate {
private static final String LOGTAG = "VRB";
private boolean mIsFullscreen = false;
private double mCurrentTime = 0.0f;
private MediaElement.Metadata mMetaData;
private double mPlaybackRate = 1.0f;
private int mReadyState = MediaElement.MEDIA_READY_STATE_HAVE_NOTHING;
private boolean mPlaying = false;
private boolean mEnded = false;
private double mVolume = 1.0f;
private boolean mIsMuted = false;
private boolean mIsUnloaded = false;
private org.mozilla.geckoview.MediaElement mMedia;
private MediaElement.Delegate mDelegate;

public Media(@NonNull MediaElement aMediaElement) {
mMedia = aMediaElement;
aMediaElement.setDelegate(this);
}

public void setDelegate(@Nullable MediaElement.Delegate aDelegate) {
mDelegate = aDelegate;
}

public double getDuration() {
if (mMetaData != null) {
return mMetaData.duration;
}
return -1.0f;
}

public boolean isFullscreen() {
return mIsFullscreen;
}

public double getCurrentTime() {
return mCurrentTime;
}

public MediaElement.Metadata getMetaData() {
return mMetaData;
}

public double getPlaybackRate() {
return mPlaybackRate;
}

public int getReadyState() {
return mReadyState;
}

public boolean isPlaying() {
return mPlaying;
}

public boolean isEnded() {
return mEnded;
}

public double getVolume() {
return mVolume;
}

public boolean isMuted() {
return mIsMuted;
}

public boolean isUnloaded() {
return mIsUnloaded;
}

public MediaElement getMediaElement() {
return mMedia;
}

public void seek(double aTime) {
mMedia.seek(aTime);
}

public void play() {
mMedia.play();
}

public void pause() {
mMedia.pause();
}

public void setVolume(double aVolume) {
mMedia.setVolume(aVolume);
}

public void setMuted(boolean aIsMuted) {
mMedia.setMuted(aIsMuted);
}

public void unload() {
mIsUnloaded = true;
mDelegate = null;
}

public int getWidth() {
return mMetaData != null ? (int)mMetaData.width : 0;
}

public int getHeight() {
return mMetaData != null ? (int)mMetaData.height : 0;
}

// Media Element delegate
@Override
public void onPlaybackStateChange(MediaElement mediaElement, int playbackState) {
if (playbackState == MediaElement.MEDIA_STATE_PLAY) {
mPlaying = true;
} else if (playbackState == MediaElement.MEDIA_STATE_PAUSE) {
mPlaying = false;
} else if (playbackState == MediaElement.MEDIA_STATE_ENDED) {
mEnded = true;
}
if (mDelegate != null) {
mDelegate.onPlaybackStateChange(mediaElement, playbackState);
}
}

@Override
public void onReadyStateChange(MediaElement mediaElement, int readyState) {
mReadyState = readyState;
if (mDelegate != null) {
mDelegate.onReadyStateChange(mediaElement, readyState);
}
}

@Override
public void onMetadataChange(MediaElement mediaElement, MediaElement.Metadata metaData) {
mMetaData = metaData;
if (mDelegate != null) {
mDelegate.onMetadataChange(mediaElement, metaData);
}
}

@Override
public void onLoadProgress(MediaElement mediaElement, MediaElement.LoadProgressInfo progressInfo) {
if (mDelegate != null) {
mDelegate.onLoadProgress(mediaElement, progressInfo);
}
}

@Override
public void onVolumeChange(MediaElement mediaElement, double volume, boolean muted) {
mVolume = volume;
mIsMuted = muted;
if (mDelegate != null) {
mDelegate.onVolumeChange(mediaElement, volume, muted);
}
}

@Override
public void onTimeChange(MediaElement mediaElement, double time) {
mCurrentTime = time;
double duration = getDuration();
if (duration <= 0 || mCurrentTime < getDuration()) {
mEnded = false;
}
if (mDelegate != null) {
mDelegate.onTimeChange(mediaElement, time);
}
}

@Override
public void onPlaybackRateChange(MediaElement mediaElement, double rate) {
mPlaybackRate = rate;
if (mDelegate != null) {
mDelegate.onPlaybackRateChange(mediaElement, rate);
}
}

@Override
public void onFullscreenChange(MediaElement mediaElement, boolean fullscreen) {
mIsFullscreen = fullscreen;
if (mDelegate != null) {
mDelegate.onFullscreenChange(mediaElement, fullscreen);
}
}

@Override
public void onError(MediaElement mediaElement, int code) {
if (mDelegate != null) {
mDelegate.onError(mediaElement, code);
}
}
}
Expand Up @@ -20,6 +20,7 @@
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.geckoview.AllowOrDeny;
import org.mozilla.geckoview.MediaElement;
import org.mozilla.geckoview.GeckoResult;
import org.mozilla.geckoview.GeckoRuntime;
import org.mozilla.geckoview.GeckoRuntimeSettings;
Expand Down Expand Up @@ -55,7 +56,7 @@

public class SessionStore implements GeckoSession.NavigationDelegate, GeckoSession.ProgressDelegate,
GeckoSession.ContentDelegate, GeckoSession.TextInputDelegate, GeckoSession.TrackingProtectionDelegate,
GeckoSession.PromptDelegate, SharedPreferences.OnSharedPreferenceChangeListener {
GeckoSession.PromptDelegate, GeckoSession.MediaDelegate, SharedPreferences.OnSharedPreferenceChangeListener {

private static SessionStore mInstance;
private static final String LOGTAG = "VRB";
Expand Down Expand Up @@ -103,6 +104,7 @@ class State {
boolean mFullScreen;
GeckoSession mSession;
SessionSettings mSettings;
ArrayList<Media> mMediaElements = new ArrayList<>();
}

private GeckoRuntime mRuntime;
Expand Down Expand Up @@ -328,6 +330,7 @@ int createSession(SessionSettings aSettings) {
state.mSession.getTextInput().setDelegate(this);
state.mSession.setPermissionDelegate(mPermissionDelegate);
state.mSession.setTrackingProtectionDelegate(this);
state.mSession.setMediaDelegate(this);
for (SessionChangeListener listener: mSessionChangeListeners) {
listener.onNewSession(state.mSession, result);
}
Expand All @@ -345,6 +348,7 @@ public void removeSession(int aSessionId) {
session.setPromptDelegate(null);
session.setPermissionDelegate(null);
session.setTrackingProtectionDelegate(null);
session.setMediaDelegate(null);
mSessions.remove(aSessionId);
for (SessionChangeListener listener: mSessionChangeListeners) {
listener.onRemoveSession(session, aSessionId);
Expand Down Expand Up @@ -499,6 +503,26 @@ public String getPreviousUri() {
return result;
}

public Media getFullScreenVideo() {
Media result = null;
if (mCurrentSession != null) {
State state = mSessions.get(mCurrentSession.hashCode());
if (state == null) {
return result;
}
if (state.mMediaElements.size() > 0) {
return state.mMediaElements.get(state.mMediaElements.size() - 1);
}
for (Media media: state.mMediaElements) {
if (media.isFullscreen()) {
result = media;
break;
}
}
}
return result;
}

public boolean isInputActive(int aSessionId) {
SessionStore.State state = mSessions.get(aSessionId);
if (state != null) {
Expand Down Expand Up @@ -1190,8 +1214,33 @@ public GeckoResult<AllowOrDeny> onPopupRequest(final GeckoSession session, final
return GeckoResult.fromValue(AllowOrDeny.DENY);
}

// SharedPreferences.OnSharedPreferenceChangeListener
// MediaDelegate
@Override
public void onMediaAdd(GeckoSession session, MediaElement element) {
SessionStore.State state = mSessions.get(getSessionId(session));
if (state == null) {
return;
}
Media media = new Media(element);
state.mMediaElements.add(media);
}

@Override
public void onMediaRemove(GeckoSession session, MediaElement element) {
SessionStore.State state = mSessions.get(getSessionId(session));
if (state == null) {
return;
}
for (int i = 0; i < state.mMediaElements.size(); ++i) {
Media media = state.mMediaElements.get(i);
if (media.getMediaElement() == element) {
media.unload();
return;
}
}
}

// SharedPreferences.OnSharedPreferenceChangeListener
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (mContext != null) {
Expand Down