Created
June 4, 2012 22:30
-
-
Save anantn/2871209 to your computer and use it in GitHub Desktop.
Add popup blocking to android getUserMedia({picture})
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/content/media/MediaEngineDefault.cpp b/content/media/MediaEngineDefault.cpp | |
--- a/content/media/MediaEngineDefault.cpp | |
+++ b/content/media/MediaEngineDefault.cpp | |
@@ -1,13 +1,19 @@ | |
/* This Source Code Form is subject to the terms of the Mozilla Public | |
* 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 "MediaEngineDefault.h" | |
+#include "nsDOMFile.h" | |
+ | |
+#ifdef MOZ_WIDGET_ANDROID | |
+#include "AndroidBridge.h" | |
+#include "nsISupportsUtils.h" | |
+#endif | |
#define WIDTH 320 | |
#define HEIGHT 240 | |
#define FPS 10 | |
#define CHANNELS 1 | |
#define RATE USECS_PER_S | |
namespace mozilla { | |
@@ -144,18 +150,37 @@ MediaEngineDefaultVideoSource::Stop() | |
mState = kStopped; | |
return NS_OK; | |
} | |
nsresult | |
MediaEngineDefaultVideoSource::Snapshot(PRUint32 aDuration, nsIDOMFile** aFile) | |
{ | |
- *aFile = nsnull; | |
- return NS_ERROR_NOT_IMPLEMENTED; | |
+ *aFile = nsnull; | |
+ | |
+#ifndef MOZ_WIDGET_ANDROID | |
+ return NS_ERROR_NOT_IMPLEMENTED; | |
+#else | |
+ if (!AndroidBridge::Bridge()) { | |
+ return NS_ERROR_UNEXPECTED; | |
+ } | |
+ | |
+ nsAutoString filePath; | |
+ AndroidBridge::Bridge()->ShowFilePickerForMimeType(filePath, NS_LITERAL_STRING("image/*")); | |
+ | |
+ nsCOMPtr<nsILocalFile> localFile; | |
+ nsresult rv = NS_NewLocalFile(filePath, false, getter_AddRefs(localFile)); | |
+ if (NS_FAILED(rv)) { | |
+ return rv; | |
+ } | |
+ | |
+ NS_ADDREF(*aFile = new nsDOMFileFile(localFile)); | |
+ return NS_OK; | |
+#endif | |
} | |
NS_IMETHODIMP | |
MediaEngineDefaultVideoSource::Notify(nsITimer* aTimer) | |
{ | |
VideoSegment segment; | |
nsRefPtr<layers::PlanarYCbCrImage> image = mImage; | |
diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp | |
--- a/dom/base/Navigator.cpp | |
+++ b/dom/base/Navigator.cpp | |
@@ -921,17 +921,17 @@ Navigator::MozGetUserMedia(nsIMediaStrea | |
MediaManager *manager = MediaManager::Get(); | |
nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow); | |
if (!win || !win->GetOuterWindow() || | |
win->GetOuterWindow()->GetCurrentInnerWindow() != win) { | |
return NS_ERROR_NOT_AVAILABLE; | |
} | |
- return manager->GetUserMedia(win->WindowID(), aParams, onSuccess, onError); | |
+ return manager->GetUserMedia(win, aParams, onSuccess, onError); | |
} | |
#endif | |
//***************************************************************************** | |
// Navigator::nsIDOMNavigatorDesktopNotification | |
//***************************************************************************** | |
NS_IMETHODIMP Navigator::GetMozNotification(nsIDOMDesktopNotificationCenter** aRetVal) | |
diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp | |
--- a/dom/media/MediaManager.cpp | |
+++ b/dom/media/MediaManager.cpp | |
@@ -5,19 +5,21 @@ | |
#include "MediaManager.h" | |
#include "MediaStreamGraph.h" | |
#include "MediaEngineDefault.h" | |
#include "nsIDOMFile.h" | |
#include "nsIEventTarget.h" | |
#include "nsIScriptGlobalObject.h" | |
+#include "nsIPopupWindowManager.h" | |
#include "nsJSUtils.h" | |
#include "nsDOMFile.h" | |
+#include "nsGlobalWindow.h" | |
namespace mozilla { | |
/** | |
* Send an error back to content. The error is the form a string. | |
* Do this only on the main thread. | |
*/ | |
class ErrorCallbackRunnable : public nsRunnable | |
@@ -163,26 +165,52 @@ private: | |
*/ | |
class GetUserMediaSnapshotCallbackRunable : public nsRunnable | |
{ | |
public: | |
GetUserMediaSnapshotCallbackRunable(MediaEngineSource* aSource, | |
PRUint32 aDuration, | |
nsIDOMGetUserMediaSuccessCallback* aSuccessCallback, | |
nsIDOMGetUserMediaErrorCallback* aErrorCallback, | |
- PRUint64 aWindowID) | |
+ nsPIDOMWindow* aWindow) | |
: mSource(aSource) | |
, mDuration(aDuration) | |
, mSuccessCallback(aSuccessCallback) | |
, mErrorCallback(aErrorCallback) | |
- , mWindowID(aWindowID) {} | |
+ , mWindow(aWindow) {} | |
NS_IMETHOD | |
Run() | |
{ | |
+ mWindowID = mWindow->WindowID(); | |
+ | |
+ // Before getting a snapshot, check if page is allowed to open a popup. | |
+ // We do this because {picture:true} on all platforms will open a new | |
+ // "window" to let the user preview or select an image. | |
+ nsCOMPtr<nsIPopupWindowManager> pm = | |
+ do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID); | |
+ if (!pm) { | |
+ return NS_OK; | |
+ } | |
+ | |
+ if (mWindow->GetPopupControlState() <= openControlled) { | |
+ return NS_OK; | |
+ } | |
+ | |
+ PRUint32 permission; | |
+ nsCOMPtr<nsIDocument> doc = mWindow->GetExtantDoc(); | |
+ pm->TestPermission(doc->GetDocumentURI(), &permission); | |
+ if (permission == nsIPopupWindowManager::DENY_POPUP) { | |
+ nsCOMPtr<nsIDOMDocument> domDoc = mWindow->GetExtantDocument(); | |
+ nsGlobalWindow::FirePopupBlockedEvent( | |
+ domDoc, mWindow, nsnull, EmptyString(), EmptyString() | |
+ ); | |
+ return NS_OK; | |
+ } | |
+ | |
nsCOMPtr<nsDOMMediaStream> comStream = mSource->Allocate(); | |
if (!comStream) { | |
NS_DispatchToMainThread(new ErrorCallbackRunnable( | |
mErrorCallback, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID | |
)); | |
return NS_OK; | |
} | |
@@ -196,16 +224,18 @@ public: | |
return NS_OK; | |
} | |
private: | |
nsCOMPtr<MediaEngineSource> mSource; | |
PRUint32 mDuration; | |
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccessCallback; | |
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mErrorCallback; | |
+ nsCOMPtr<nsPIDOMWindow> mWindow; | |
+ | |
PRUint64 mWindowID; | |
}; | |
/** | |
* Runs on a seperate thread and is responsible for enumerating devices. | |
* Depending on whether a picture or stream was asked for, either | |
* GetUserMediaCallbackRunnable or GetUserMediaSnapshotCallbackRunnable | |
* will be dispatched to the main thread to return the result to DOM. | |
@@ -213,37 +243,38 @@ private: | |
* Do not run this on the main thread. | |
*/ | |
class GetUserMediaRunnable : public nsRunnable | |
{ | |
public: | |
GetUserMediaRunnable(bool aAudio, bool aVideo, bool aPicture, | |
nsIDOMGetUserMediaSuccessCallback* aSuccess, | |
nsIDOMGetUserMediaErrorCallback* aError, | |
- PRUint64 aWindowID, StreamListeners* aListeners) | |
+ nsPIDOMWindow* aWindow, StreamListeners* aListeners) | |
: mAudio(aAudio) | |
, mVideo(aVideo) | |
, mPicture(aPicture) | |
, mSuccess(aSuccess) | |
, mError(aError) | |
- , mWindowID(aWindowID) | |
+ , mWindow(aWindow) | |
, mListeners(aListeners) {} | |
~GetUserMediaRunnable() {} | |
// We only support 1 audio and 1 video track for now. | |
enum { | |
kVideoTrack = 1, | |
kAudioTrack = 2 | |
}; | |
NS_IMETHOD | |
Run() | |
{ | |
mManager = MediaManager::Get(); | |
+ mWindowID = mWindow->WindowID(); | |
if (mPicture) { | |
SendPicture(); | |
return NS_OK; | |
} | |
// XXX: Implement merging two streams (See bug 758391). | |
if (mAudio && mVideo) { | |
@@ -277,17 +308,17 @@ public: | |
if (!count) { | |
NS_DispatchToMainThread(new ErrorCallbackRunnable( | |
mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID | |
)); | |
return; | |
} | |
MediaEngineVideoSource* videoSource = videoSources[count - 1]; | |
NS_DispatchToMainThread(new GetUserMediaSnapshotCallbackRunable( | |
- videoSource, 0 /* duration */, mSuccess, mError, mWindowID | |
+ videoSource, 0 /* duration */, mSuccess, mError, mWindow | |
)); | |
} | |
// {video:true} | |
void | |
SendVideo() | |
{ | |
nsTArray<nsRefPtr<MediaEngineVideoSource> > videoSources; | |
@@ -330,34 +361,35 @@ public: | |
private: | |
bool mAudio; | |
bool mVideo; | |
bool mPicture; | |
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess; | |
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError; | |
- PRUint64 mWindowID; | |
+ nsCOMPtr<nsPIDOMWindow> mWindow; | |
StreamListeners* mListeners; | |
MediaManager* mManager; | |
+ PRUint64 mWindowID; | |
}; | |
nsRefPtr<MediaManager> MediaManager::sSingleton; | |
NS_IMPL_ISUPPORTS1(MediaManager, nsIObserver) | |
/** | |
* The entry point for this file. A call from Navigator::mozGetUserMedia | |
* will end up here. MediaManager is a singleton that is responsible | |
* for handling all incoming getUserMedia calls from every window. | |
*/ | |
nsresult | |
-MediaManager::GetUserMedia(PRUint64 aWindowID, nsIMediaStreamOptions* aParams, | |
+MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, nsIMediaStreamOptions* aParams, | |
nsIDOMGetUserMediaSuccessCallback* onSuccess, | |
nsIDOMGetUserMediaErrorCallback* onError) | |
{ | |
NS_ENSURE_TRUE(aParams, NS_ERROR_NULL_POINTER); | |
bool audio, video, picture; | |
nsresult rv = aParams->GetPicture(&picture); | |
NS_ENSURE_SUCCESS(rv, rv); | |
@@ -370,26 +402,27 @@ MediaManager::GetUserMedia(PRUint64 aWin | |
// We only support "front" or "back". TBD: Send to GetUserMediaRunnable. | |
nsString cameraType; | |
rv = aParams->GetCamera(cameraType); | |
NS_ENSURE_SUCCESS(rv, rv); | |
// Store the WindowID in a hash table and mark as active. The entry is removed | |
// when this window is closed or navigated away from. | |
- StreamListeners* listeners = mActiveWindows.Get(aWindowID); | |
+ PRUint64 windowID = aWindow->WindowID(); | |
+ StreamListeners* listeners = mActiveWindows.Get(windowID); | |
if (!listeners) { | |
listeners = new StreamListeners; | |
- mActiveWindows.Put(aWindowID, listeners); | |
+ mActiveWindows.Put(windowID, listeners); | |
} | |
// Pass runanbles along to GetUserMediaRunnable so it can add the | |
// MediaStreamListener to the runnable list. | |
nsCOMPtr<nsIRunnable> gUMRunnable = new GetUserMediaRunnable( | |
- audio, video, picture, onSuccess, onError, aWindowID, listeners | |
+ audio, video, picture, onSuccess, onError, aWindow, listeners | |
); | |
// Reuse the same thread to save memory. | |
if (!mMediaThread) { | |
rv = NS_NewThread(getter_AddRefs(mMediaThread)); | |
NS_ENSURE_SUCCESS(rv, rv); | |
} | |
diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h | |
--- a/dom/media/MediaManager.h | |
+++ b/dom/media/MediaManager.h | |
@@ -4,20 +4,19 @@ | |
#include "MediaEngine.h" | |
#include "mozilla/Services.h" | |
#include "nsHashKeys.h" | |
#include "nsClassHashtable.h" | |
#include "nsObserverService.h" | |
+#include "nsPIDOMWindow.h" | |
#include "nsIDOMNavigatorUserMedia.h" | |
-#include "stdio.h" | |
- | |
namespace mozilla { | |
/** | |
* This class is an implementation of MediaStreamListener. This is used | |
* to Start() and Stop() the underlying MediaEngineSource when MediaStreams | |
* are assigned and deassigned in content. | |
*/ | |
class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener | |
@@ -91,17 +90,17 @@ public: | |
Mutex* GetLock() { | |
return mLock; | |
} | |
MediaEngine* GetBackend(); | |
WindowTable* GetActiveWindows(); | |
- nsresult GetUserMedia(PRUint64 aWindowID, nsIMediaStreamOptions* aParams, | |
+ nsresult GetUserMedia(nsPIDOMWindow* aWindow, nsIMediaStreamOptions* aParams, | |
nsIDOMGetUserMediaSuccessCallback* onSuccess, | |
nsIDOMGetUserMediaErrorCallback* onError); | |
void OnNavigation(PRUint64 aWindowID); | |
private: | |
// Make private because we want only one instance of this class | |
MediaManager() | |
: mBackend(nsnull) | |
diff --git a/mobile/android/confvars.sh b/mobile/android/confvars.sh | |
--- a/mobile/android/confvars.sh | |
+++ b/mobile/android/confvars.sh | |
@@ -12,16 +12,19 @@ MOZ_BRANDING_DIRECTORY=mobile/android/br | |
MOZ_OFFICIAL_BRANDING_DIRECTORY=mobile/android/branding/official | |
# MOZ_APP_DISPLAYNAME is set by branding/configure.sh | |
MOZ_SAFE_BROWSING= | |
MOZ_SERVICES_SYNC= | |
MOZ_DISABLE_DOMCRYPTO=1 | |
+# Enable getUserMedia | |
+MOZ_MEDIA_NAVIGATOR=1 | |
+ | |
if test "$LIBXUL_SDK"; then | |
MOZ_XULRUNNER=1 | |
else | |
MOZ_XULRUNNER= | |
MOZ_PLACES=1 | |
fi | |
MOZ_CAPTURE=1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment