From f881190c2aba5c231ec7dba656e6fde78d76d773 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Wed, 30 May 2012 12:10:49 -0400 Subject: [PATCH] Bug 727421 - Implement full screen support for Flash on Android r=blassey --- dom/plugins/base/Makefile.in | 1 + dom/plugins/base/android/ANPNativeWindow.cpp | 2 +- dom/plugins/base/android/ANPSurface.cpp | 9 +++ dom/plugins/base/android/ANPWindow.cpp | 57 +++++++++++--- dom/plugins/base/android/android_npapi.h | 22 ++++++ dom/plugins/base/nsNPAPIPluginInstance.cpp | 69 +++++------------ dom/plugins/base/nsNPAPIPluginInstance.h | 11 ++- dom/plugins/base/nsPluginInstanceOwner.cpp | 81 ++++++++++++++++---- dom/plugins/base/nsPluginInstanceOwner.h | 11 ++- mobile/android/base/GeckoApp.java | 64 +++++++++++++++- mobile/android/base/GeckoAppShell.java | 15 ++-- mozglue/android/APKOpen.cpp | 2 + widget/android/AndroidBridge.cpp | 17 ++-- widget/android/AndroidBridge.h | 4 +- widget/android/AndroidJNI.cpp | 27 +++++++ 15 files changed, 300 insertions(+), 92 deletions(-) diff --git a/dom/plugins/base/Makefile.in b/dom/plugins/base/Makefile.in index 925ef70ee1b..dafe2adbd04 100644 --- a/dom/plugins/base/Makefile.in +++ b/dom/plugins/base/Makefile.in @@ -102,6 +102,7 @@ endif LOCAL_INCLUDES += \ -DSK_BUILD_FOR_ANDROID_NDK \ -I$(topsrcdir)/widget/android \ + -I$(topsrcdir)/widget/xpwidgets \ -I$(topsrcdir)/xpcom/base/ \ -I$(topsrcdir)/gfx/skia/include/core \ -I$(topsrcdir)/gfx/skia/include/config \ diff --git a/dom/plugins/base/android/ANPNativeWindow.cpp b/dom/plugins/base/android/ANPNativeWindow.cpp index e89765bae78..b2b948e47e1 100644 --- a/dom/plugins/base/android/ANPNativeWindow.cpp +++ b/dom/plugins/base/android/ANPNativeWindow.cpp @@ -25,7 +25,7 @@ static nsresult GetOwner(NPP instance, nsPluginInstanceOwner** owner) { return pinst->GetOwner((nsIPluginInstanceOwner**)owner); } -static ANPNativeWindow anp_native_window_acquireNativeWindow(NPP instance) { +static ANPNativeWindow anp_native_window_acquireNativeWindow(NPP instance) { nsRefPtr owner; if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner)))) return NULL; diff --git a/dom/plugins/base/android/ANPSurface.cpp b/dom/plugins/base/android/ANPSurface.cpp index 3763b9f7fc6..a638d4c8682 100644 --- a/dom/plugins/base/android/ANPSurface.cpp +++ b/dom/plugins/base/android/ANPSurface.cpp @@ -143,6 +143,14 @@ static bool init() { gSurfaceFunctions.lock = (int (*)(void*, SurfaceInfo*, void*))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionEb"); gSurfaceFunctions.unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv"); + + if (!gSurfaceFunctions.lock) { + // Stuff changed in 3.0/4.0 + handle = dlopen("libgui.so", RTLD_LAZY); + gSurfaceFunctions.lock = (int (*)(void*, SurfaceInfo*, void*))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionE"); + gSurfaceFunctions.unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv"); + } + handle = dlopen("libui.so", RTLD_LAZY); if (!handle) { LOG("Failed to open libui.so"); @@ -158,6 +166,7 @@ static bool init() { return gSurfaceFunctions.initialized; } +// FIXME: All of this should be changed to use the equivalent things in AndroidBridge, bug 758612 static bool anp_surface_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) { if (!bitmap || !surfaceView) { return false; diff --git a/dom/plugins/base/android/ANPWindow.cpp b/dom/plugins/base/android/ANPWindow.cpp index 3b245c2942a..1924bc042cd 100644 --- a/dom/plugins/base/android/ANPWindow.cpp +++ b/dom/plugins/base/android/ANPWindow.cpp @@ -3,6 +3,7 @@ * 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/. */ +#include "base/basictypes.h" #include "assert.h" #include "ANPBase.h" #include @@ -11,12 +12,20 @@ #include "nsIPluginInstanceOwner.h" #include "nsPluginInstanceOwner.h" #include "nsWindow.h" +#include "mozilla/dom/ScreenOrientation.h" #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) #define ASSIGN(obj, name) (obj)->name = anp_window_##name using namespace mozilla; using namespace mozilla::widget; +using namespace mozilla::dom; + +static nsresult GetOwner(NPP instance, nsPluginInstanceOwner** owner) { + nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); + + return pinst->GetOwner((nsIPluginInstanceOwner**)owner); +} void anp_window_setVisibleRects(NPP instance, const ANPRectI rects[], int32_t count) @@ -54,13 +63,27 @@ anp_window_showKeyboard(NPP instance, bool value) void anp_window_requestFullScreen(NPP instance) { - NOT_IMPLEMENTED(); + nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); + + nsRefPtr owner; + if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner)))) { + return; + } + + owner->RequestFullScreen(); } void anp_window_exitFullScreen(NPP instance) { - NOT_IMPLEMENTED(); + nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); + + nsRefPtr owner; + if (NS_FAILED(GetOwner(instance, getter_AddRefs(owner)))) { + return; + } + + owner->ExitFullScreen(); } void @@ -69,12 +92,6 @@ anp_window_requestCenterFitZoom(NPP instance) NOT_IMPLEMENTED(); } -static nsresult GetOwner(NPP instance, nsPluginInstanceOwner** owner) { - nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); - - return pinst->GetOwner((nsIPluginInstanceOwner**)owner); -} - ANPRectI anp_window_visibleRect(NPP instance) { @@ -98,7 +115,29 @@ anp_window_visibleRect(NPP instance) void anp_window_requestFullScreenOrientation(NPP instance, ANPScreenOrientation orientation) { - NOT_IMPLEMENTED(); + short newOrientation; + + // Convert to the ActivityInfo equivalent + switch (orientation) { + case kFixedLandscape_ANPScreenOrientation: + newOrientation = eScreenOrientation_LandscapePrimary; + break; + case kFixedPortrait_ANPScreenOrientation: + newOrientation = eScreenOrientation_PortraitPrimary; + break; + case kLandscape_ANPScreenOrientation: + newOrientation = eScreenOrientation_Landscape; + break; + case kPortrait_ANPScreenOrientation: + newOrientation = eScreenOrientation_Portrait; + break; + default: + newOrientation = eScreenOrientation_None; + break; + } + + nsNPAPIPluginInstance* pinst = static_cast(instance->ndata); + pinst->SetFullScreenOrientation(newOrientation); } void InitWindowInterface(ANPWindowInterfaceV0 *i) { diff --git a/dom/plugins/base/android/android_npapi.h b/dom/plugins/base/android/android_npapi.h index e903e2af0d3..b5a1f0becb9 100644 --- a/dom/plugins/base/android/android_npapi.h +++ b/dom/plugins/base/android/android_npapi.h @@ -698,6 +698,28 @@ struct ANPWindowInterfaceV1 : ANPWindowInterfaceV0 { ANPRectI (*visibleRect)(NPP instance); }; +enum ANPScreenOrientations { + /** No preference specified: let the system decide the best orientation. + */ + kDefault_ANPScreenOrientation = 0, + /** Would like to have the screen in a landscape orientation, but it will + not allow for 180 degree rotations. + */ + kFixedLandscape_ANPScreenOrientation = 1, + /** Would like to have the screen in a portrait orientation, but it will + not allow for 180 degree rotations. + */ + kFixedPortrait_ANPScreenOrientation = 2, + /** Would like to have the screen in landscape orientation, but can use the + sensor to change which direction the screen is facing. + */ + kLandscape_ANPScreenOrientation = 3, + /** Would like to have the screen in portrait orientation, but can use the + sensor to change which direction the screen is facing. + */ + kPortrait_ANPScreenOrientation = 4 +}; + typedef int32_t ANPScreenOrientation; struct ANPWindowInterfaceV2 : ANPWindowInterfaceV1 { diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index d88b5b12837..46ca8ae872f 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -3,6 +3,11 @@ * 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/. */ +#ifdef MOZ_WIDGET_ANDROID +// For ScreenOrientation.h +#include "base/basictypes.h" +#endif + #include "prlog.h" #include "prmem.h" #include "nscore.h" @@ -35,6 +40,7 @@ #include "mozilla/Mutex.h" #include "mozilla/CondVar.h" #include "AndroidBridge.h" +#include "mozilla/dom/ScreenOrientation.h" class PluginEventRunnable : public nsRunnable { @@ -74,6 +80,7 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance() mSurface(nsnull), mANPDrawingModel(0), mOnScreen(true), + mFullScreenOrientation(dom::eScreenOrientation_LandscapePrimary), #endif mRunning(NOT_STARTED), mWindowless(false), @@ -743,63 +750,29 @@ void nsNPAPIPluginInstance::MemoryPressure() SendLifecycleEvent(this, kFreeMemory_ANPLifecycleAction); } +void nsNPAPIPluginInstance::NotifyFullScreen(bool aFullScreen) +{ + PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::NotifyFullScreen this=%p\n",this)); + + if (RUNNING != mRunning) + return; + + SendLifecycleEvent(this, aFullScreen ? kEnterFullScreen_ANPLifecycleAction : kExitFullScreen_ANPLifecycleAction); +} + void nsNPAPIPluginInstance::SetANPDrawingModel(PRUint32 aModel) { mANPDrawingModel = aModel; } -class SurfaceGetter : public nsRunnable { -public: - SurfaceGetter(nsNPAPIPluginInstance* aInstance, NPPluginFuncs* aPluginFunctions, NPP_t aNPP) : - mInstance(aInstance), mPluginFunctions(aPluginFunctions), mNPP(aNPP) { - } - ~SurfaceGetter() { - } - nsresult Run() { - void* surface; - (*mPluginFunctions->getvalue)(&mNPP, kJavaSurface_ANPGetValue, &surface); - mInstance->SetJavaSurface(surface); - return NS_OK; - } - void RequestSurface() { - JNIEnv* env = GetJNIForThread(); - if (!env) - return; - - if (!mozilla::AndroidBridge::Bridge()) { - PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance null AndroidBridge")); - return; - } - mozilla::AndroidBridge::Bridge()->PostToJavaThread(env, this); - } -private: - nsNPAPIPluginInstance* mInstance; - NPP_t mNPP; - NPPluginFuncs* mPluginFunctions; -}; - - void* nsNPAPIPluginInstance::GetJavaSurface() { - if (mANPDrawingModel != kSurface_ANPDrawingModel) + void* surface = nsnull; + nsresult rv = GetValueFromPlugin(kJavaSurface_ANPGetValue, &surface); + if (NS_FAILED(rv)) return nsnull; - - return mSurface; -} -void nsNPAPIPluginInstance::SetJavaSurface(void* aSurface) -{ - mSurface = aSurface; -} - -void nsNPAPIPluginInstance::RequestJavaSurface() -{ - if (mSurfaceGetter.get()) - return; - - mSurfaceGetter = new SurfaceGetter(this, mPlugin->PluginFuncs(), mNPP); - - ((SurfaceGetter*)mSurfaceGetter.get())->RequestSurface(); + return surface; } void nsNPAPIPluginInstance::PostEvent(void* event) diff --git a/dom/plugins/base/nsNPAPIPluginInstance.h b/dom/plugins/base/nsNPAPIPluginInstance.h index 15f005fe494..b6fb40f56d1 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.h +++ b/dom/plugins/base/nsNPAPIPluginInstance.h @@ -123,6 +123,7 @@ public: void NotifyForeground(bool aForeground); void NotifyOnScreen(bool aOnScreen); void MemoryPressure(); + void NotifyFullScreen(bool aFullScreen); bool IsOnScreen() { return mOnScreen; @@ -131,12 +132,14 @@ public: PRUint32 GetANPDrawingModel() { return mANPDrawingModel; } void SetANPDrawingModel(PRUint32 aModel); - // This stuff is for kSurface_ANPDrawingModel void* GetJavaSurface(); - void SetJavaSurface(void* aSurface); - void RequestJavaSurface(); void PostEvent(void* event); + + // These are really mozilla::dom::ScreenOrientation, but it's + // difficult to include that here + PRUint32 FullScreenOrientation() { return mFullScreenOrientation; } + void SetFullScreenOrientation(PRUint32 orientation) { mFullScreenOrientation = orientation; } #endif nsresult NewStreamListener(const char* aURL, void* notifyData, @@ -221,6 +224,8 @@ protected: nsTArray> mPostedEvents; void PopPostedEvent(PluginEventRunnable* r); + + PRUint32 mFullScreenOrientation; #endif enum { diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index f0affa1b82c..8a0deead271 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -87,6 +87,10 @@ static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); #include "ANPBase.h" #include "AndroidBridge.h" #include "AndroidMediaLayer.h" +#include "nsWindow.h" + +static nsPluginInstanceOwner* sFullScreenInstance = nsnull; + using namespace mozilla::dom; #include @@ -305,7 +309,9 @@ nsPluginInstanceOwner::nsPluginInstanceOwner() #ifdef MOZ_WIDGET_ANDROID mInverted = false; + mFullScreen = false; mLayer = nsnull; + mJavaView = nsnull; #endif } @@ -1725,31 +1731,39 @@ void nsPluginInstanceOwner::SendSize(int width, int height) mInstance->HandleEvent(&event, nsnull); } -bool nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect) +bool nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect /* = gfxRect(0, 0, 0, 0) */) { - void* javaSurface = mInstance->GetJavaSurface(); - if (!javaSurface) { - mInstance->RequestJavaSurface(); - return false; + if (!mJavaView) { + mJavaView = mInstance->GetJavaSurface(); + + if (!mJavaView) + return false; + + mJavaView = (void*)AndroidBridge::GetJNIEnv()->NewGlobalRef((jobject)mJavaView); } if (AndroidBridge::Bridge()) - AndroidBridge::Bridge()->AddPluginView((jobject)javaSurface, aRect); + AndroidBridge::Bridge()->AddPluginView((jobject)mJavaView, aRect, mFullScreen, mInstance->FullScreenOrientation()); + + if (mFullScreen) + sFullScreenInstance = this; return true; } void nsPluginInstanceOwner::RemovePluginView() { - if (!mInstance) - return; - - void* surface = mInstance->GetJavaSurface(); - if (!surface) + if (!mInstance || !mJavaView) return; if (AndroidBridge::Bridge()) - AndroidBridge::Bridge()->RemovePluginView((jobject)surface); + AndroidBridge::Bridge()->RemovePluginView((jobject)mJavaView, mFullScreen); + + AndroidBridge::GetJNIEnv()->DeleteGlobalRef((jobject)mJavaView); + mJavaView = nsnull; + + if (mFullScreen) + sFullScreenInstance = nsnull; } void nsPluginInstanceOwner::Invalidate() { @@ -1760,6 +1774,47 @@ void nsPluginInstanceOwner::Invalidate() { InvalidateRect(&rect); } +void nsPluginInstanceOwner::RequestFullScreen() { + if (mFullScreen) + return; + + // Remove whatever view we currently have (if any, fullscreen or otherwise) + RemovePluginView(); + + mFullScreen = true; + AddPluginView(); + + mInstance->NotifyFullScreen(mFullScreen); +} + +void nsPluginInstanceOwner::ExitFullScreen() { + if (!mFullScreen) + return; + + RemovePluginView(); + + mFullScreen = false; + + PRInt32 model = mInstance->GetANPDrawingModel(); + + if (model == kSurface_ANPDrawingModel) { + // We need to invalidate the plugin rect so Paint() gets called above. + // This will cause the view to be re-added. Gross. + Invalidate(); + } + + mInstance->NotifyFullScreen(mFullScreen); +} + +void nsPluginInstanceOwner::ExitFullScreen(jobject view) { + JNIEnv* env = AndroidBridge::GetJNIEnv(); + + if (env && sFullScreenInstance && sFullScreenInstance->mInstance && + env->IsSameObject(view, (jobject)sFullScreenInstance->mInstance->GetJavaSurface())) { + sFullScreenInstance->ExitFullScreen(); + } +} + #endif nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent) @@ -2871,7 +2926,7 @@ void nsPluginInstanceOwner::Paint(gfxContext* aContext, const gfxRect& aFrameRect, const gfxRect& aDirtyRect) { - if (!mInstance || !mObjectFrame || !mPluginDocumentActiveState) + if (!mInstance || !mObjectFrame || !mPluginDocumentActiveState || mFullScreen) return; PRInt32 model = mInstance->GetANPDrawingModel(); diff --git a/dom/plugins/base/nsPluginInstanceOwner.h b/dom/plugins/base/nsPluginInstanceOwner.h index 1d10712488c..4c6dfbc084a 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.h +++ b/dom/plugins/base/nsPluginInstanceOwner.h @@ -277,6 +277,12 @@ public: } void Invalidate(); + + void RequestFullScreen(); + void ExitFullScreen(); + + // Called from AndroidJNI when we removed the fullscreen view. + static void ExitFullScreen(jobject view); #endif private: @@ -293,10 +299,13 @@ private: #ifdef MOZ_WIDGET_ANDROID void SendSize(int width, int height); - bool AddPluginView(const gfxRect& aRect); + bool AddPluginView(const gfxRect& aRect = gfxRect(0, 0, 0, 0)); void RemovePluginView(); bool mInverted; + bool mFullScreen; + + void* mJavaView; // For kOpenGL_ANPDrawingModel nsRefPtr mLayer; diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 37d14c8b435..f4075ef2d15 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -109,6 +109,8 @@ abstract public class GeckoApp private AboutHomeContent mAboutHomeContent; private static AbsoluteLayout mPluginContainer; + private View mFullScreenPluginView; + private int mRestoreMode = GeckoAppShell.RESTORE_NONE; private boolean mInitialized = false; @@ -1350,12 +1352,38 @@ abstract public class GeckoApp tabs.closeTab(tab); } - void addPluginView(final View view, final Rect rect) { + private void addFullScreenPluginView(View view, int orientation) { + if (mFullScreenPluginView != null) { + Log.w(LOGTAG, "Already have a fullscreen plugin view"); + return; + } + + setFullScreen(true); + mBrowserToolbar.hide(); + + if (orientation != GeckoScreenOrientationListener.eScreenOrientation_None) + GeckoScreenOrientationListener.getInstance().lockScreenOrientation(orientation); + + view.setWillNotDraw(false); + if (view instanceof SurfaceView) { + ((SurfaceView) view).setZOrderOnTop(true); + } + + mPluginContainer.addView(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + mFullScreenPluginView = view; + } + + void addPluginView(final View view, final Rect rect, final boolean isFullScreen, final int orientation) { mMainHandler.post(new Runnable() { public void run() { Tabs tabs = Tabs.getInstance(); Tab tab = tabs.getSelectedTab(); + if (isFullScreen) { + addFullScreenPluginView(view, orientation); + return; + } + PluginLayer layer = (PluginLayer) tab.getPluginLayer(view); if (layer == null) { layer = new PluginLayer(view, rect, mLayerController.getView().getRenderer().getMaxTextureSize()); @@ -1370,12 +1398,39 @@ abstract public class GeckoApp }); } - void removePluginView(final View view) { + private void removeFullScreenPluginView(View view) { + if (mFullScreenPluginView == null) { + Log.w(LOGTAG, "Don't have a fullscreen plugin view"); + return; + } + + if (mFullScreenPluginView != view) { + Log.w(LOGTAG, "Passed view is not the current full screen view"); + return; + } + + GeckoAppShell.onFullScreenPluginHidden(view); + + GeckoScreenOrientationListener.getInstance().unlockScreenOrientation(); + + setFullScreen(false); + mBrowserToolbar.show(); + + mPluginContainer.removeView(view); + mFullScreenPluginView = null; + } + + void removePluginView(final View view, final boolean isFullScreen) { mMainHandler.post(new Runnable() { public void run() { Tabs tabs = Tabs.getInstance(); Tab tab = tabs.getSelectedTab(); + if (isFullScreen) { + removeFullScreenPluginView(view); + return; + } + PluginLayer layer = (PluginLayer) tab.removePluginLayer(view); if (layer != null) { layer.destroy(); @@ -2601,6 +2656,11 @@ abstract public class GeckoApp return; } + if (mFullScreenPluginView != null) { + removePluginView(mFullScreenPluginView, true); + return; + } + SiteIdentityPopup identityPopup = SiteIdentityPopup.getInstance(); if (identityPopup.isShowing()) { identityPopup.dismiss(); diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 0fe585a2a59..08c075268e0 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -207,6 +207,8 @@ public class GeckoAppShell public static native SurfaceBits getSurfaceBits(Surface surface); + public static native void onFullScreenPluginHidden(View view); + private static class GeckoMediaScannerClient implements MediaScannerConnectionClient { private String mFile = ""; private String mMimeType = ""; @@ -1514,18 +1516,19 @@ public class GeckoAppShell public static void addPluginView(View view, int x, int y, - int w, int h) + int w, int h, + boolean isFullScreen, int orientation) { ImmutableViewportMetrics pluginViewport; - Log.i(LOGTAG, "addPluginView:" + view + " @ x:" + x + " y:" + y + " w:" + w + " h:" + h); + Log.i(LOGTAG, "addPluginView:" + view + " @ x:" + x + " y:" + y + " w:" + w + " h:" + h + "fullscreen: " + isFullScreen + " orientation: " + orientation); - GeckoApp.mAppContext.addPluginView(view, new Rect(x, y, x + w, y + h)); + GeckoApp.mAppContext.addPluginView(view, new Rect(x, y, x + w, y + h), isFullScreen, orientation); } - public static void removePluginView(View view) { - Log.i(LOGTAG, "removePluginView:" + view); - GeckoApp.mAppContext.removePluginView(view); + public static void removePluginView(View view, boolean isFullScreen) { + Log.i(LOGTAG, "removePluginView:" + view + " fullscreen: " + isFullScreen); + GeckoApp.mAppContext.removePluginView(view, isFullScreen); } public static Surface createSurface() { diff --git a/mozglue/android/APKOpen.cpp b/mozglue/android/APKOpen.cpp index c6398f22098..208b557c951 100644 --- a/mozglue/android/APKOpen.cpp +++ b/mozglue/android/APKOpen.cpp @@ -319,6 +319,7 @@ SHELL_WRAPPER7(notifyGotNextMessage, jint, jstring, jstring, jstring, jlong, jin SHELL_WRAPPER3(notifyReadingMessageListFailed, jint, jint, jlong) SHELL_WRAPPER2(notifyFilePickerResult, jstring, jlong) SHELL_WRAPPER1_WITH_RETURN(getSurfaceBits, jobject, jobject) +SHELL_WRAPPER1(onFullScreenPluginHidden, jobject) static void * xul_handle = NULL; static void * sqlite_handle = NULL; @@ -736,6 +737,7 @@ loadGeckoLibs(const char *apkName) GETFUNC(notifyReadingMessageListFailed); GETFUNC(notifyFilePickerResult); GETFUNC(getSurfaceBits); + GETFUNC(onFullScreenPluginHidden); #undef GETFUNC sStartupTimeline = (uint64_t *)__wrap_dlsym(xul_handle, "_ZN7mozilla15StartupTimeline16sStartupTimelineE"); gettimeofday(&t1, 0); diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 25cd972502c..fa875d10581 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -136,7 +136,6 @@ AndroidBridge::Init(JNIEnv *jEnv, jEnableBatteryNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableBatteryNotifications", "()V"); jDisableBatteryNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableBatteryNotifications", "()V"); jGetCurrentBatteryInformation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getCurrentBatteryInformation", "()[D"); - jRemovePluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "removePluginView", "(Landroid/view/View;)V"); jNotifyPaintedRect = jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyPaintedRect", "(FFFF)V"); jHandleGeckoMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "handleGeckoMessage", "(Ljava/lang/String;)Ljava/lang/String;"); @@ -185,7 +184,9 @@ AndroidBridge::Init(JNIEnv *jEnv, #ifdef MOZ_JAVA_COMPOSITOR jPumpMessageLoop = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "pumpMessageLoop", "()V"); - jAddPluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "addPluginView", "(Landroid/view/View;IIII)V"); + jAddPluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "addPluginView", "(Landroid/view/View;IIIIZI)V"); + jRemovePluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "removePluginView", "(Landroid/view/View;Z)V"); + jCreateSurface = jEnv->GetStaticMethodID(jGeckoAppShellClass, "createSurface", "()Landroid/view/Surface;"); jShowSurface = jEnv->GetStaticMethodID(jGeckoAppShellClass, "showSurface", "(Landroid/view/Surface;IIIIZZ)V"); jHideSurface = jEnv->GetStaticMethodID(jGeckoAppShellClass, "hideSurface", "(Landroid/view/Surface;)V"); @@ -196,7 +197,8 @@ AndroidBridge::Init(JNIEnv *jEnv, AndroidGLController::Init(jEnv); AndroidEGLObject::Init(jEnv); #else - jAddPluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "addPluginView", "(Landroid/view/View;DDDD)V"); + jAddPluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "addPluginView", "(Landroid/view/View;DDDD)V"); + jRemovePluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "removePluginView", "(Landroid/view/View;)V"); #endif InitAndroidJavaWrappers(jEnv); @@ -2310,7 +2312,7 @@ NS_IMETHODIMP nsAndroidBridge::SetBrowserApp(nsIAndroidBrowserApp *aBrowserApp) } void -AndroidBridge::AddPluginView(jobject view, const gfxRect& rect) { +AndroidBridge::AddPluginView(jobject view, const gfxRect& rect, bool isFullScreen, int orientation) { JNIEnv *env = GetJNIEnv(); if (!env) return; @@ -2320,7 +2322,8 @@ AndroidBridge::AddPluginView(jobject view, const gfxRect& rect) { #if MOZ_JAVA_COMPOSITOR env->CallStaticVoidMethod(sBridge->mGeckoAppShellClass, sBridge->jAddPluginView, view, - (int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height); + (int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height, + isFullScreen, orientation); #else env->CallStaticVoidMethod(sBridge->mGeckoAppShellClass, sBridge->jAddPluginView, view, @@ -2329,14 +2332,14 @@ AndroidBridge::AddPluginView(jobject view, const gfxRect& rect) { } void -AndroidBridge::RemovePluginView(jobject view) +AndroidBridge::RemovePluginView(jobject view, bool isFullScreen) { JNIEnv *env = GetJNIEnv(); if (!env) return; AutoLocalJNIFrame jniFrame(env, 0); - env->CallStaticVoidMethod(mGeckoAppShellClass, jRemovePluginView, view); + env->CallStaticVoidMethod(mGeckoAppShellClass, jRemovePluginView, view, isFullScreen); } extern "C" diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index e844a10ebab..5f3f383bfb0 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -340,8 +340,8 @@ public: void ShowSurface(jobject surface, const gfxRect& aRect, bool aInverted, bool aBlend); void HideSurface(jobject surface); - void AddPluginView(jobject view, const gfxRect& rect); - void RemovePluginView(jobject view); + void AddPluginView(jobject view, const gfxRect& rect, bool isFullScreen, int orientation); + void RemovePluginView(jobject view, bool isFullScreen); // These methods don't use a ScreenOrientation because it's an // enum and that would require including the header which requires diff --git a/widget/android/AndroidJNI.cpp b/widget/android/AndroidJNI.cpp index 45a5fe4418d..3fe4be76426 100644 --- a/widget/android/AndroidJNI.cpp +++ b/widget/android/AndroidJNI.cpp @@ -37,6 +37,7 @@ #include "mozilla/dom/sms/SmsParent.h" #include "nsISmsRequestManager.h" #include "nsISmsDatabaseService.h" +#include "nsPluginInstanceOwner.h" using namespace mozilla; using namespace mozilla::dom::sms; @@ -974,6 +975,32 @@ cleanup: return surfaceBits; } +NS_EXPORT void JNICALL +Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden(JNIEnv* jenv, jclass, jobject view) +{ + class ExitFullScreenRunnable : public nsRunnable { + public: + ExitFullScreenRunnable(jobject view) : mView(view) {} + + NS_IMETHODIMP Run() { + JNIEnv* env = AndroidBridge::GetJNIEnv(); + if (!env) { + NS_WARNING("Failed to acquire JNI env, can't exit plugin fullscreen mode"); + return NS_OK; + } + + nsPluginInstanceOwner::ExitFullScreen(mView); + env->DeleteGlobalRef(mView); + return NS_OK; + } + + private: + jobject mView; + }; + + nsCOMPtr runnable = new ExitFullScreenRunnable(jenv->NewGlobalRef(view)); + NS_DispatchToMainThread(runnable); +} #endif }