Bug 1148149 - Support Android Presentation API. r=snorp, r=jgilbert
This commit is contained in:
@@ -446,6 +446,9 @@ GLContextEGL::ReleaseSurface() {
|
|||||||
if (mOwnsContext) {
|
if (mOwnsContext) {
|
||||||
mozilla::gl::DestroySurface(mSurface);
|
mozilla::gl::DestroySurface(mSurface);
|
||||||
}
|
}
|
||||||
|
if (mSurface == mSurfaceOverride) {
|
||||||
|
mSurfaceOverride = EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
mSurface = EGL_NO_SURFACE;
|
mSurface = EGL_NO_SURFACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -813,6 +816,41 @@ GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
|
|||||||
return glContext.forget();
|
return glContext.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
EGLSurface
|
||||||
|
GLContextProviderEGL::CreateEGLSurface(void* aWindow)
|
||||||
|
{
|
||||||
|
if (!sEGLLibrary.EnsureInitialized()) {
|
||||||
|
MOZ_CRASH("Failed to load EGL library!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLConfig config;
|
||||||
|
if (!CreateConfig(&config)) {
|
||||||
|
MOZ_CRASH("Failed to create EGLConfig!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(aWindow);
|
||||||
|
|
||||||
|
EGLSurface surface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, aWindow, 0);
|
||||||
|
|
||||||
|
if (surface == EGL_NO_SURFACE) {
|
||||||
|
MOZ_CRASH("Failed to create EGLSurface!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GLContextProviderEGL::DestroyEGLSurface(EGLSurface surface)
|
||||||
|
{
|
||||||
|
if (!sEGLLibrary.EnsureInitialized()) {
|
||||||
|
MOZ_CRASH("Failed to load EGL library!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
|
||||||
|
}
|
||||||
|
#endif // defined(ANDROID)
|
||||||
|
|
||||||
already_AddRefed<GLContextEGL>
|
already_AddRefed<GLContextEGL>
|
||||||
GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& size)
|
GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& size)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
#ifndef GL_CONTEXT_PROVIDER_NAME
|
#ifndef GL_CONTEXT_PROVIDER_NAME
|
||||||
#error GL_CONTEXT_PROVIDER_NAME not defined
|
#error GL_CONTEXT_PROVIDER_NAME not defined
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(ANDROID)
|
||||||
|
typedef void* EGLSurface;
|
||||||
|
#endif // defined(ANDROID)
|
||||||
|
|
||||||
class GL_CONTEXT_PROVIDER_NAME
|
class GL_CONTEXT_PROVIDER_NAME
|
||||||
{
|
{
|
||||||
@@ -76,6 +79,11 @@ public:
|
|||||||
static already_AddRefed<GLContext>
|
static already_AddRefed<GLContext>
|
||||||
CreateWrappingExisting(void* aContext, void* aSurface);
|
CreateWrappingExisting(void* aContext, void* aSurface);
|
||||||
|
|
||||||
|
#if defined(ANDROID)
|
||||||
|
static EGLSurface CreateEGLSurface(void* aWindow);
|
||||||
|
static void DestroyEGLSurface(EGLSurface surface);
|
||||||
|
#endif // defined(ANDROID)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a pointer to the global context, creating it if it doesn't exist.
|
* Get a pointer to the global context, creating it if it doesn't exist.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -54,6 +54,11 @@
|
|||||||
#include "nsRegion.h" // for nsIntRegion, etc
|
#include "nsRegion.h" // for nsIntRegion, etc
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
#include "AndroidBridge.h"
|
||||||
|
#include "opengl/CompositorOGL.h"
|
||||||
|
#include "GLContextEGL.h"
|
||||||
|
#include "GLContextProvider.h"
|
||||||
|
#include "ScopedGLHelpers.h"
|
||||||
#endif
|
#endif
|
||||||
#include "GeckoProfiler.h"
|
#include "GeckoProfiler.h"
|
||||||
#include "TextRenderer.h" // for TextRenderer
|
#include "TextRenderer.h" // for TextRenderer
|
||||||
@@ -306,6 +311,9 @@ LayerManagerComposite::EndTransaction(DrawPaintedLayerCallback aCallback,
|
|||||||
ApplyOcclusionCulling(mRoot, opaque);
|
ApplyOcclusionCulling(mRoot, opaque);
|
||||||
|
|
||||||
Render();
|
Render();
|
||||||
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
|
RenderToPresentationSurface();
|
||||||
|
#endif
|
||||||
mGeometryChanged = false;
|
mGeometryChanged = false;
|
||||||
} else {
|
} else {
|
||||||
// Modified layer tree
|
// Modified layer tree
|
||||||
@@ -768,6 +776,175 @@ LayerManagerComposite::Render()
|
|||||||
RecordFrame();
|
RecordFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
|
class ScopedCompositorProjMatrix {
|
||||||
|
public:
|
||||||
|
ScopedCompositorProjMatrix(CompositorOGL* aCompositor, const Matrix4x4& aProjMatrix):
|
||||||
|
mCompositor(aCompositor),
|
||||||
|
mOriginalProjMatrix(mCompositor->GetProjMatrix())
|
||||||
|
{
|
||||||
|
mCompositor->SetProjMatrix(aProjMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScopedCompositorProjMatrix()
|
||||||
|
{
|
||||||
|
mCompositor->SetProjMatrix(mOriginalProjMatrix);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
CompositorOGL* const mCompositor;
|
||||||
|
const Matrix4x4 mOriginalProjMatrix;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScopedCompostitorSurfaceSize {
|
||||||
|
public:
|
||||||
|
ScopedCompostitorSurfaceSize(CompositorOGL* aCompositor, const gfx::IntSize& aSize) :
|
||||||
|
mCompositor(aCompositor),
|
||||||
|
mOriginalSize(mCompositor->GetDestinationSurfaceSize())
|
||||||
|
{
|
||||||
|
mCompositor->SetDestinationSurfaceSize(aSize);
|
||||||
|
}
|
||||||
|
~ScopedCompostitorSurfaceSize()
|
||||||
|
{
|
||||||
|
mCompositor->SetDestinationSurfaceSize(mOriginalSize);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
CompositorOGL* const mCompositor;
|
||||||
|
const gfx::IntSize mOriginalSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScopedCompositorRenderOffset {
|
||||||
|
public:
|
||||||
|
ScopedCompositorRenderOffset(CompositorOGL* aCompositor, const ScreenPoint& aOffset) :
|
||||||
|
mCompositor(aCompositor),
|
||||||
|
mOriginalOffset(mCompositor->GetScreenRenderOffset())
|
||||||
|
{
|
||||||
|
mCompositor->SetScreenRenderOffset(aOffset);
|
||||||
|
}
|
||||||
|
~ScopedCompositorRenderOffset()
|
||||||
|
{
|
||||||
|
mCompositor->SetScreenRenderOffset(mOriginalOffset);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
CompositorOGL* const mCompositor;
|
||||||
|
const ScreenPoint mOriginalOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScopedContextSurfaceOverride {
|
||||||
|
public:
|
||||||
|
ScopedContextSurfaceOverride(GLContextEGL* aContext, void* aSurface) :
|
||||||
|
mContext(aContext)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aSurface);
|
||||||
|
mContext->SetEGLSurfaceOverride(aSurface);
|
||||||
|
mContext->MakeCurrent(true);
|
||||||
|
}
|
||||||
|
~ScopedContextSurfaceOverride()
|
||||||
|
{
|
||||||
|
mContext->SetEGLSurfaceOverride(EGL_NO_SURFACE);
|
||||||
|
mContext->MakeCurrent(true);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
GLContextEGL* const mContext;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerManagerComposite::RenderToPresentationSurface()
|
||||||
|
{
|
||||||
|
if (!AndroidBridge::Bridge()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* window = AndroidBridge::Bridge()->GetPresentationWindow();
|
||||||
|
|
||||||
|
if (!window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLSurface surface = AndroidBridge::Bridge()->GetPresentationSurface();
|
||||||
|
|
||||||
|
if (!surface) {
|
||||||
|
//create surface;
|
||||||
|
surface = GLContextProviderEGL::CreateEGLSurface(window);
|
||||||
|
if (!surface) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidBridge::Bridge()->SetPresentationSurface(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
CompositorOGL* compositor = static_cast<CompositorOGL*>(mCompositor.get());
|
||||||
|
GLContext* gl = compositor->gl();
|
||||||
|
GLContextEGL* egl = GLContextEGL::Cast(gl);
|
||||||
|
|
||||||
|
if (!egl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IntSize windowSize = AndroidBridge::Bridge()->GetNativeWindowSize(window);
|
||||||
|
|
||||||
|
if ((windowSize.width <= 0) || (windowSize.height <= 0)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int actualWidth = windowSize.width;
|
||||||
|
const int actualHeight = windowSize.height;
|
||||||
|
|
||||||
|
const gfx::IntSize originalSize = compositor->GetDestinationSurfaceSize();
|
||||||
|
|
||||||
|
const int pageWidth = originalSize.width;
|
||||||
|
const int pageHeight = originalSize.height;
|
||||||
|
|
||||||
|
float scale = 1.0;
|
||||||
|
|
||||||
|
if ((pageWidth > actualWidth) || (pageHeight > actualHeight)) {
|
||||||
|
const float scaleWidth = (float)actualWidth / (float)pageWidth;
|
||||||
|
const float scaleHeight = (float)actualHeight / (float)pageHeight;
|
||||||
|
scale = scaleWidth <= scaleHeight ? scaleWidth : scaleHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gfx::IntSize actualSize(actualWidth, actualHeight);
|
||||||
|
ScopedCompostitorSurfaceSize overrideSurfaceSize(compositor, actualSize);
|
||||||
|
|
||||||
|
const ScreenPoint offset((actualWidth - (int)(scale * pageWidth)) / 2, 0);
|
||||||
|
ScopedCompositorRenderOffset overrideRenderOffset(compositor, offset);
|
||||||
|
ScopedContextSurfaceOverride overrideSurface(egl, surface);
|
||||||
|
|
||||||
|
nsIntRegion invalid;
|
||||||
|
Rect bounds(0.0f, 0.0f, scale * pageWidth, (float)actualHeight);
|
||||||
|
Rect rect, actualBounds;
|
||||||
|
|
||||||
|
mCompositor->BeginFrame(invalid, nullptr, bounds, &rect, &actualBounds);
|
||||||
|
|
||||||
|
// Override the projection matrix since the presentation frame buffer
|
||||||
|
// is probably not the same size as the device frame buffer. The override
|
||||||
|
// projection matrix also scales the content to fit into the presentation
|
||||||
|
// frame buffer.
|
||||||
|
Matrix viewMatrix;
|
||||||
|
viewMatrix.PreTranslate(-1.0, 1.0);
|
||||||
|
viewMatrix.PreScale((2.0f * scale) / (float)actualWidth, (2.0f * scale) / (float)actualHeight);
|
||||||
|
viewMatrix.PreScale(1.0f, -1.0f);
|
||||||
|
viewMatrix.PreTranslate((int)((float)offset.x / scale), offset.y);
|
||||||
|
|
||||||
|
Matrix4x4 projMatrix = Matrix4x4::From2D(viewMatrix);
|
||||||
|
|
||||||
|
ScopedCompositorProjMatrix overrideProjMatrix(compositor, projMatrix);
|
||||||
|
|
||||||
|
// The Java side of Fennec sets a scissor rect that accounts for
|
||||||
|
// chrome such as the URL bar. Override that so that the entire frame buffer
|
||||||
|
// is cleared.
|
||||||
|
ScopedScissorRect screen(egl, 0, 0, actualWidth, actualHeight);
|
||||||
|
egl->fClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
|
egl->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
const nsIntRect clipRect = nsIntRect(0, 0, (int)(scale * pageWidth), actualHeight);
|
||||||
|
RootLayer()->Prepare(RenderTargetPixel::FromUntyped(clipRect));
|
||||||
|
RootLayer()->RenderLayer(clipRect);
|
||||||
|
|
||||||
|
mCompositor->EndFrame();
|
||||||
|
mCompositor->SetFBAcquireFence(mRoot);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
SubtractTransformedRegion(nsIntRegion& aRegion,
|
SubtractTransformedRegion(nsIntRegion& aRegion,
|
||||||
const nsIntRegion& aRegionToSubtract,
|
const nsIntRegion& aRegionToSubtract,
|
||||||
|
|||||||
@@ -276,6 +276,9 @@ private:
|
|||||||
* Render the current layer tree to the active target.
|
* Render the current layer tree to the active target.
|
||||||
*/
|
*/
|
||||||
void Render();
|
void Render();
|
||||||
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
|
void RenderToPresentationSurface();
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render debug overlays such as the FPS/FrameCounter above the frame.
|
* Render debug overlays such as the FPS/FrameCounter above the frame.
|
||||||
|
|||||||
@@ -799,6 +799,22 @@ CompositorParent::SchedulePauseOnCompositorThread()
|
|||||||
lock.Wait();
|
lock.Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CompositorParent::ScheduleResumeOnCompositorThread()
|
||||||
|
{
|
||||||
|
MonitorAutoLock lock(mResumeCompositionMonitor);
|
||||||
|
|
||||||
|
CancelableTask *resumeTask =
|
||||||
|
NewRunnableMethod(this, &CompositorParent::ResumeComposition);
|
||||||
|
MOZ_ASSERT(CompositorLoop());
|
||||||
|
CompositorLoop()->PostTask(FROM_HERE, resumeTask);
|
||||||
|
|
||||||
|
// Wait until the resume has actually been processed by the compositor thread
|
||||||
|
lock.Wait();
|
||||||
|
|
||||||
|
return !mPaused;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CompositorParent::ScheduleResumeOnCompositorThread(int width, int height)
|
CompositorParent::ScheduleResumeOnCompositorThread(int width, int height)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ public:
|
|||||||
* Returns true if a surface was obtained and the resume succeeded; false
|
* Returns true if a surface was obtained and the resume succeeded; false
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
|
bool ScheduleResumeOnCompositorThread();
|
||||||
bool ScheduleResumeOnCompositorThread(int width, int height);
|
bool ScheduleResumeOnCompositorThread(int width, int height);
|
||||||
|
|
||||||
virtual void ScheduleComposition();
|
virtual void ScheduleComposition();
|
||||||
|
|||||||
@@ -304,6 +304,19 @@ public:
|
|||||||
const gfx::Matrix4x4& GetProjMatrix() const {
|
const gfx::Matrix4x4& GetProjMatrix() const {
|
||||||
return mProjMatrix;
|
return mProjMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetProjMatrix(const gfx::Matrix4x4& aProjMatrix) {
|
||||||
|
mProjMatrix = aProjMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gfx::IntSize GetDestinationSurfaceSize() const {
|
||||||
|
return gfx::IntSize (mSurfaceSize.width, mSurfaceSize.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ScreenPoint& GetScreenRenderOffset() const {
|
||||||
|
return mRenderOffset;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual gfx::IntSize GetWidgetSize() const override
|
virtual gfx::IntSize GetWidgetSize() const override
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -294,6 +294,9 @@ public class GeckoAppShell
|
|||||||
|
|
||||||
public static native SurfaceBits getSurfaceBits(Surface surface);
|
public static native SurfaceBits getSurfaceBits(Surface surface);
|
||||||
|
|
||||||
|
public static native void addPresentationSurface(Surface surface);
|
||||||
|
public static native void removePresentationSurface(Surface surface);
|
||||||
|
|
||||||
public static native void onFullScreenPluginHidden(View view);
|
public static native void onFullScreenPluginHidden(View view);
|
||||||
|
|
||||||
public static class CreateShortcutFaviconLoadedListener implements OnFaviconLoadedListener {
|
public static class CreateShortcutFaviconLoadedListener implements OnFaviconLoadedListener {
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
package org.mozilla.gecko;
|
package org.mozilla.gecko;
|
||||||
|
|
||||||
|
import android.app.Presentation;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v7.media.MediaControlIntent;
|
import android.support.v7.media.MediaControlIntent;
|
||||||
@@ -12,6 +15,13 @@ import android.support.v7.media.MediaRouteSelector;
|
|||||||
import android.support.v7.media.MediaRouter;
|
import android.support.v7.media.MediaRouter;
|
||||||
import android.support.v7.media.MediaRouter.RouteInfo;
|
import android.support.v7.media.MediaRouter.RouteInfo;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.Display;
|
||||||
|
import android.view.Surface;
|
||||||
|
import android.view.SurfaceHolder;
|
||||||
|
import android.view.SurfaceView;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewGroup.LayoutParams;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import com.google.android.gms.cast.CastMediaControlIntent;
|
import com.google.android.gms.cast.CastMediaControlIntent;
|
||||||
|
|
||||||
@@ -61,6 +71,7 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
|||||||
|
|
||||||
private MediaRouter mediaRouter = null;
|
private MediaRouter mediaRouter = null;
|
||||||
private final Map<String, GeckoMediaPlayer> displays = new HashMap<String, GeckoMediaPlayer>();
|
private final Map<String, GeckoMediaPlayer> displays = new HashMap<String, GeckoMediaPlayer>();
|
||||||
|
private GeckoPresentation presentation = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -135,19 +146,23 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
|||||||
displays.remove(route.getId());
|
displays.remove(route.getId());
|
||||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(
|
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(
|
||||||
"MediaPlayer:Removed", route.getId()));
|
"MediaPlayer:Removed", route.getId()));
|
||||||
|
updatePresentation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public void onRouteSelected(MediaRouter router, int type, MediaRouter.RouteInfo route) {
|
public void onRouteSelected(MediaRouter router, int type, MediaRouter.RouteInfo route) {
|
||||||
|
updatePresentation();
|
||||||
}
|
}
|
||||||
|
|
||||||
// These methods aren't used by the support version Media Router
|
// These methods aren't used by the support version Media Router
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) {
|
public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) {
|
||||||
|
updatePresentation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo route) {
|
public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo route) {
|
||||||
|
updatePresentation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -159,6 +174,7 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
|||||||
debug("onRouteAdded: route=" + route);
|
debug("onRouteAdded: route=" + route);
|
||||||
final GeckoMediaPlayer display = getMediaPlayerForRoute(route);
|
final GeckoMediaPlayer display = getMediaPlayerForRoute(route);
|
||||||
saveAndNotifyOfDisplay("MediaPlayer:Added", route, display);
|
saveAndNotifyOfDisplay("MediaPlayer:Added", route, display);
|
||||||
|
updatePresentation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -166,6 +182,7 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
|||||||
debug("onRouteChanged: route=" + route);
|
debug("onRouteChanged: route=" + route);
|
||||||
final GeckoMediaPlayer display = displays.get(route.getId());
|
final GeckoMediaPlayer display = displays.get(route.getId());
|
||||||
saveAndNotifyOfDisplay("MediaPlayer:Changed", route, display);
|
saveAndNotifyOfDisplay("MediaPlayer:Changed", route, display);
|
||||||
|
updatePresentation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveAndNotifyOfDisplay(final String eventName,
|
private void saveAndNotifyOfDisplay(final String eventName,
|
||||||
@@ -221,4 +238,86 @@ public class MediaPlayerManager extends Fragment implements NativeEventListener
|
|||||||
.build();
|
.build();
|
||||||
mediaRouter.addCallback(selectorBuilder, callback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
|
mediaRouter.addCallback(selectorBuilder, callback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
if (presentation != null) {
|
||||||
|
presentation.dismiss();
|
||||||
|
presentation = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePresentation() {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mediaRouter == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute();
|
||||||
|
Display display = route != null ? route.getPresentationDisplay() : null;
|
||||||
|
|
||||||
|
if (display != null) {
|
||||||
|
if ((presentation != null) && (presentation.getDisplay() != display)) {
|
||||||
|
presentation.dismiss();
|
||||||
|
presentation = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (presentation == null) {
|
||||||
|
presentation = new GeckoPresentation(getActivity(), display);
|
||||||
|
|
||||||
|
try {
|
||||||
|
presentation.show();
|
||||||
|
} catch (WindowManager.InvalidDisplayException ex) {
|
||||||
|
Log.w(LOGTAG, "Couldn't show presentation! Display was removed in "
|
||||||
|
+ "the meantime.", ex);
|
||||||
|
presentation = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (presentation != null) {
|
||||||
|
presentation.dismiss();
|
||||||
|
presentation = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SurfaceListener implements SurfaceHolder.Callback {
|
||||||
|
@Override
|
||||||
|
public void surfaceChanged(SurfaceHolder holder, int format, int width,
|
||||||
|
int height) {
|
||||||
|
// Surface changed so force a composite
|
||||||
|
GeckoAppShell.scheduleComposite();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceCreated(SurfaceHolder holder) {
|
||||||
|
GeckoAppShell.addPresentationSurface(holder.getSurface());
|
||||||
|
GeckoAppShell.scheduleComposite();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||||
|
GeckoAppShell.removePresentationSurface(holder.getSurface());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static class GeckoPresentation extends Presentation {
|
||||||
|
private SurfaceView mView;
|
||||||
|
public GeckoPresentation(Context context, Display display) {
|
||||||
|
super(context, display);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
mView = new SurfaceView(getContext());
|
||||||
|
setContentView(mView, new ViewGroup.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||||
|
mView.getHolder().addCallback(new SurfaceListener());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -305,6 +305,44 @@ Java_org_mozilla_gecko_GeckoAppShell_getSurfaceBits(JNIEnv * arg0, jclass arg1,
|
|||||||
|
|
||||||
#ifdef JNI_STUBS
|
#ifdef JNI_STUBS
|
||||||
|
|
||||||
|
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface_t)(JNIEnv *, jclass, jobject);
|
||||||
|
static Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface_t f_Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface;
|
||||||
|
extern "C" NS_EXPORT void JNICALL
|
||||||
|
Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface(JNIEnv * arg0, jclass arg1, jobject arg2) {
|
||||||
|
if (!f_Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface) {
|
||||||
|
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
|
||||||
|
"JNI Function called before it was loaded");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
f_Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface(arg0, arg1, arg2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JNI_BINDINGS
|
||||||
|
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface", &f_Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JNI_STUBS
|
||||||
|
|
||||||
|
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface_t)(JNIEnv *, jclass, jobject);
|
||||||
|
static Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface_t f_Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface;
|
||||||
|
extern "C" NS_EXPORT void JNICALL
|
||||||
|
Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface(JNIEnv * arg0, jclass arg1, jobject arg2) {
|
||||||
|
if (!f_Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface) {
|
||||||
|
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
|
||||||
|
"JNI Function called before it was loaded");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
f_Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface(arg0, arg1, arg2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JNI_BINDINGS
|
||||||
|
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface", &f_Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JNI_STUBS
|
||||||
|
|
||||||
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden_t)(JNIEnv *, jclass, jobject);
|
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden_t)(JNIEnv *, jclass, jobject);
|
||||||
static Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden_t f_Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden;
|
static Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden_t f_Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden;
|
||||||
extern "C" NS_EXPORT void JNICALL
|
extern "C" NS_EXPORT void JNICALL
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
|
|
||||||
#include "MediaCodec.h"
|
#include "MediaCodec.h"
|
||||||
#include "SurfaceTexture.h"
|
#include "SurfaceTexture.h"
|
||||||
|
#include "GLContextProvider.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::gfx;
|
using namespace mozilla::gfx;
|
||||||
@@ -821,6 +822,8 @@ AndroidBridge::OpenGraphicsLibraries()
|
|||||||
ANativeWindow_setBuffersGeometry = (int (*)(void*, int, int, int)) dlsym(handle, "ANativeWindow_setBuffersGeometry");
|
ANativeWindow_setBuffersGeometry = (int (*)(void*, int, int, int)) dlsym(handle, "ANativeWindow_setBuffersGeometry");
|
||||||
ANativeWindow_lock = (int (*)(void*, void*, void*)) dlsym(handle, "ANativeWindow_lock");
|
ANativeWindow_lock = (int (*)(void*, void*, void*)) dlsym(handle, "ANativeWindow_lock");
|
||||||
ANativeWindow_unlockAndPost = (int (*)(void*))dlsym(handle, "ANativeWindow_unlockAndPost");
|
ANativeWindow_unlockAndPost = (int (*)(void*))dlsym(handle, "ANativeWindow_unlockAndPost");
|
||||||
|
ANativeWindow_getWidth = (int (*)(void*))dlsym(handle, "ANativeWindow_getWidth");
|
||||||
|
ANativeWindow_getHeight = (int (*)(void*))dlsym(handle, "ANativeWindow_getHeight");
|
||||||
|
|
||||||
// This is only available in Honeycomb and ICS. It was removed in Jelly Bean
|
// This is only available in Honeycomb and ICS. It was removed in Jelly Bean
|
||||||
ANativeWindow_fromSurfaceTexture = (void* (*)(JNIEnv*, jobject))dlsym(handle, "ANativeWindow_fromSurfaceTexture");
|
ANativeWindow_fromSurfaceTexture = (void* (*)(JNIEnv*, jobject))dlsym(handle, "ANativeWindow_fromSurfaceTexture");
|
||||||
@@ -1275,6 +1278,16 @@ AndroidBridge::ReleaseNativeWindow(void *window)
|
|||||||
// have nothing to do here. We should probably ref it.
|
// have nothing to do here. We should probably ref it.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IntSize
|
||||||
|
AndroidBridge::GetNativeWindowSize(void* window)
|
||||||
|
{
|
||||||
|
if (!window || !ANativeWindow_getWidth || !ANativeWindow_getHeight) {
|
||||||
|
return IntSize(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IntSize(ANativeWindow_getWidth(window), ANativeWindow_getHeight(window));
|
||||||
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
AndroidBridge::AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurfaceTexture)
|
AndroidBridge::AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurfaceTexture)
|
||||||
{
|
{
|
||||||
@@ -1508,7 +1521,9 @@ void AndroidBridge::SyncFrameMetrics(const ParentLayerPoint& aScrollOffset, floa
|
|||||||
}
|
}
|
||||||
|
|
||||||
AndroidBridge::AndroidBridge()
|
AndroidBridge::AndroidBridge()
|
||||||
: mLayerClient(nullptr)
|
: mLayerClient(nullptr),
|
||||||
|
mPresentationWindow(nullptr),
|
||||||
|
mPresentationSurface(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2036,6 +2051,51 @@ AndroidBridge::RunDelayedUiThreadTasks()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
AndroidBridge::GetPresentationWindow()
|
||||||
|
{
|
||||||
|
return mPresentationWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AndroidBridge::SetPresentationWindow(void* aPresentationWindow)
|
||||||
|
{
|
||||||
|
if (mPresentationWindow) {
|
||||||
|
const bool wasAlreadyPaused = nsWindow::IsCompositionPaused();
|
||||||
|
if (!wasAlreadyPaused) {
|
||||||
|
nsWindow::SchedulePauseComposition();
|
||||||
|
}
|
||||||
|
|
||||||
|
mPresentationWindow = aPresentationWindow;
|
||||||
|
if (mPresentationSurface) {
|
||||||
|
// destroy the egl surface!
|
||||||
|
// The compositor is paused so it should be okay to destroy
|
||||||
|
// the surface here.
|
||||||
|
mozilla::gl::GLContextProvider::DestroyEGLSurface(mPresentationSurface);
|
||||||
|
mPresentationSurface = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wasAlreadyPaused) {
|
||||||
|
nsWindow::ScheduleResumeComposition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mPresentationWindow = aPresentationWindow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLSurface
|
||||||
|
AndroidBridge::GetPresentationSurface()
|
||||||
|
{
|
||||||
|
return mPresentationSurface;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AndroidBridge::SetPresentationSurface(EGLSurface aPresentationSurface)
|
||||||
|
{
|
||||||
|
mPresentationSurface = aPresentationSurface;
|
||||||
|
}
|
||||||
|
|
||||||
Object::LocalRef AndroidBridge::ChannelCreate(Object::Param stream) {
|
Object::LocalRef AndroidBridge::ChannelCreate(Object::Param stream) {
|
||||||
JNIEnv* const env = GetJNIForThread();
|
JNIEnv* const env = GetJNIForThread();
|
||||||
auto rv = Object::LocalRef::Adopt(env, env->CallStaticObjectMethod(
|
auto rv = Object::LocalRef::Adopt(env, env->CallStaticObjectMethod(
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "nsIMIMEInfo.h"
|
#include "nsIMIMEInfo.h"
|
||||||
#include "nsColor.h"
|
#include "nsColor.h"
|
||||||
#include "gfxRect.h"
|
#include "gfxRect.h"
|
||||||
|
#include "mozilla/gfx/Point.h"
|
||||||
|
|
||||||
#include "nsIAndroidBridge.h"
|
#include "nsIAndroidBridge.h"
|
||||||
#include "nsIMobileMessageCallback.h"
|
#include "nsIMobileMessageCallback.h"
|
||||||
@@ -264,6 +265,7 @@ public:
|
|||||||
|
|
||||||
void *AcquireNativeWindow(JNIEnv* aEnv, jobject aSurface);
|
void *AcquireNativeWindow(JNIEnv* aEnv, jobject aSurface);
|
||||||
void ReleaseNativeWindow(void *window);
|
void ReleaseNativeWindow(void *window);
|
||||||
|
mozilla::gfx::IntSize GetNativeWindowSize(void* window);
|
||||||
|
|
||||||
void *AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurface);
|
void *AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurface);
|
||||||
void ReleaseNativeWindowForSurfaceTexture(void *window);
|
void ReleaseNativeWindowForSurfaceTexture(void *window);
|
||||||
@@ -426,6 +428,8 @@ protected:
|
|||||||
|
|
||||||
int (* ANativeWindow_lock)(void *window, void *outBuffer, void *inOutDirtyBounds);
|
int (* ANativeWindow_lock)(void *window, void *outBuffer, void *inOutDirtyBounds);
|
||||||
int (* ANativeWindow_unlockAndPost)(void *window);
|
int (* ANativeWindow_unlockAndPost)(void *window);
|
||||||
|
int (* ANativeWindow_getWidth)(void * window);
|
||||||
|
int (* ANativeWindow_getHeight)(void * window);
|
||||||
|
|
||||||
int (* Surface_lock)(void* surface, void* surfaceInfo, void* region, bool block);
|
int (* Surface_lock)(void* surface, void* surfaceInfo, void* region, bool block);
|
||||||
int (* Surface_unlockAndPost)(void* surface);
|
int (* Surface_unlockAndPost)(void* surface);
|
||||||
@@ -439,6 +443,15 @@ private:
|
|||||||
public:
|
public:
|
||||||
void PostTaskToUiThread(Task* aTask, int aDelayMs);
|
void PostTaskToUiThread(Task* aTask, int aDelayMs);
|
||||||
int64_t RunDelayedUiThreadTasks();
|
int64_t RunDelayedUiThreadTasks();
|
||||||
|
|
||||||
|
void* GetPresentationWindow();
|
||||||
|
void SetPresentationWindow(void* aPresentationWindow);
|
||||||
|
|
||||||
|
EGLSurface GetPresentationSurface();
|
||||||
|
void SetPresentationSurface(EGLSurface aPresentationSurface);
|
||||||
|
private:
|
||||||
|
void* mPresentationWindow;
|
||||||
|
EGLSurface mPresentationSurface;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AutoJNIClass {
|
class AutoJNIClass {
|
||||||
|
|||||||
@@ -811,6 +811,27 @@ cleanup:
|
|||||||
return surfaceBits;
|
return surfaceBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_EXPORT void JNICALL
|
||||||
|
Java_org_mozilla_gecko_GeckoAppShell_addPresentationSurface(JNIEnv* jenv, jclass, jobject surface)
|
||||||
|
{
|
||||||
|
if (surface != NULL) {
|
||||||
|
void* window = AndroidBridge::Bridge()->AcquireNativeWindow(jenv, surface);
|
||||||
|
if (window) {
|
||||||
|
AndroidBridge::Bridge()->SetPresentationWindow(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_EXPORT void JNICALL
|
||||||
|
Java_org_mozilla_gecko_GeckoAppShell_removePresentationSurface(JNIEnv* jenv, jclass, jobject surface)
|
||||||
|
{
|
||||||
|
void* window = AndroidBridge::Bridge()->GetPresentationWindow();
|
||||||
|
if (window) {
|
||||||
|
AndroidBridge::Bridge()->SetPresentationWindow(nullptr);
|
||||||
|
AndroidBridge::Bridge()->ReleaseNativeWindow(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NS_EXPORT void JNICALL
|
NS_EXPORT void JNICALL
|
||||||
Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden(JNIEnv* jenv, jclass, jobject view)
|
Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden(JNIEnv* jenv, jclass, jobject view)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2454,6 +2454,29 @@ nsWindow::ScheduleComposite()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsWindow::IsCompositionPaused()
|
||||||
|
{
|
||||||
|
return sCompositorPaused;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsWindow::SchedulePauseComposition()
|
||||||
|
{
|
||||||
|
if (sCompositorParent) {
|
||||||
|
sCompositorParent->SchedulePauseOnCompositorThread();
|
||||||
|
sCompositorPaused = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsWindow::ScheduleResumeComposition()
|
||||||
|
{
|
||||||
|
if (sCompositorParent && sCompositorParent->ScheduleResumeOnCompositorThread()) {
|
||||||
|
sCompositorPaused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsWindow::ScheduleResumeComposition(int width, int height)
|
nsWindow::ScheduleResumeComposition(int width, int height)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -156,7 +156,10 @@ public:
|
|||||||
static void SetCompositor(mozilla::layers::LayerManager* aLayerManager,
|
static void SetCompositor(mozilla::layers::LayerManager* aLayerManager,
|
||||||
mozilla::layers::CompositorParent* aCompositorParent,
|
mozilla::layers::CompositorParent* aCompositorParent,
|
||||||
mozilla::layers::CompositorChild* aCompositorChild);
|
mozilla::layers::CompositorChild* aCompositorChild);
|
||||||
|
static bool IsCompositionPaused();
|
||||||
static void ScheduleComposite();
|
static void ScheduleComposite();
|
||||||
|
static void SchedulePauseComposition();
|
||||||
|
static void ScheduleResumeComposition();
|
||||||
static void ScheduleResumeComposition(int width, int height);
|
static void ScheduleResumeComposition(int width, int height);
|
||||||
static void ForceIsFirstPaint();
|
static void ForceIsFirstPaint();
|
||||||
static float ComputeRenderIntegrity();
|
static float ComputeRenderIntegrity();
|
||||||
|
|||||||
Reference in New Issue
Block a user