mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1090501 - pre-emptively open the camera hardware for certified apps with 'camera' permission, r=fabrice
This commit is contained in:
parent
2eb72ef33a
commit
68d7d6cd25
@ -5,10 +5,14 @@
|
||||
|
||||
#include "CameraPreferences.h"
|
||||
#include "CameraCommon.h"
|
||||
#include "DOMCameraManager.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "nsIObserverService.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -26,6 +30,12 @@ uint32_t CameraPreferences::sPrefCameraControlLowMemoryThresholdMB = 0;
|
||||
|
||||
bool CameraPreferences::sPrefCameraParametersIsLowMemory = false;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
StaticRefPtr<CameraPreferences> CameraPreferences::sObserver;
|
||||
|
||||
NS_IMPL_ISUPPORTS(CameraPreferences, nsIObserver);
|
||||
#endif
|
||||
|
||||
#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
|
||||
/* static */
|
||||
nsresult
|
||||
@ -205,6 +215,19 @@ CameraPreferences::Initialize()
|
||||
|
||||
nsresult rv;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
sObserver = new CameraPreferences();
|
||||
rv = obs->AddObserver(sObserver, "init-camera-hw", false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
sObserver = nullptr;
|
||||
}
|
||||
} else {
|
||||
DOM_CAMERA_LOGE("Could not get observer service\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
sPrefMonitor = new Monitor("CameraPreferences.sPrefMonitor");
|
||||
|
||||
sPrefTestEnabled = new nsCString();
|
||||
@ -239,9 +262,42 @@ CameraPreferences::Shutdown()
|
||||
sPrefGonkParameters = nullptr;
|
||||
sPrefMonitor = nullptr;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
nsresult rv = obs->RemoveObserver(sObserver , "init-camera-hw");
|
||||
if (NS_FAILED(rv)) {
|
||||
DOM_CAMERA_LOGE("Failed to remove CameraPreferences observer (0x%x)\n", rv);
|
||||
}
|
||||
sObserver = nullptr;
|
||||
} else {
|
||||
DOM_CAMERA_LOGE("Could not get observer service\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
DOM_CAMERA_LOGI("Camera preferences shut down\n");
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsresult
|
||||
CameraPreferences::PreinitCameraHardware()
|
||||
{
|
||||
nsDOMCameraManager::PreinitCameraHardware();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CameraPreferences::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
|
||||
{
|
||||
if (strcmp(aTopic, "init-camera-hw") == 0) {
|
||||
return PreinitCameraHardware();
|
||||
}
|
||||
|
||||
DOM_CAMERA_LOGE("Got unhandled topic '%s'\n", aTopic);
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* static */
|
||||
bool
|
||||
CameraPreferences::GetPref(const char* aPref, nsACString& aVal)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#define DOM_CAMERA_CAMERAPREFERENCES_H
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
#if defined(MOZ_HAVE_CXX11_STRONG_ENUMS) || defined(MOZ_HAVE_CXX11_ENUM_TYPE)
|
||||
// Older compilers that don't support strongly-typed enums
|
||||
@ -20,8 +21,16 @@ namespace mozilla {
|
||||
template<class T> class StaticAutoPtr;
|
||||
|
||||
class CameraPreferences
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
: public nsIObserver
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
#endif
|
||||
|
||||
static bool Initialize();
|
||||
static void Shutdown();
|
||||
|
||||
@ -79,10 +88,21 @@ protected:
|
||||
|
||||
static bool sPrefCameraParametersIsLowMemory;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
static StaticRefPtr<CameraPreferences> sObserver;
|
||||
|
||||
nsresult PreinitCameraHardware();
|
||||
|
||||
protected:
|
||||
// Objects may be instantiated for use as observers.
|
||||
CameraPreferences() { }
|
||||
~CameraPreferences() { }
|
||||
#else
|
||||
private:
|
||||
// static class only
|
||||
// Static class only.
|
||||
CameraPreferences();
|
||||
~CameraPreferences();
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -46,6 +46,12 @@ using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
StaticRefPtr<ICameraControl> nsDOMCameraControl::sCachedCameraControl;
|
||||
/* static */ nsresult nsDOMCameraControl::sCachedCameraControlStartResult = NS_OK;
|
||||
/* static */ nsCOMPtr<nsITimer> nsDOMCameraControl::sDiscardCachedCameraControlTimer;
|
||||
#endif
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
|
||||
@ -144,6 +150,60 @@ nsDOMCameraControl::DOMCameraConfiguration::~DOMCameraConfiguration()
|
||||
MOZ_COUNT_DTOR(nsDOMCameraControl::DOMCameraConfiguration);
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// This shoudl be long enough for even our slowest platforms.
|
||||
static const unsigned long kCachedCameraTimeoutMs = 3500;
|
||||
|
||||
// Open the battery-door-facing camera by default.
|
||||
static const uint32_t kDefaultCameraId = 0;
|
||||
|
||||
/* static */ void
|
||||
nsDOMCameraControl::PreinitCameraHardware()
|
||||
{
|
||||
// Assume a default, minimal configuration. This should initialize the
|
||||
// hardware, but won't (can't) start the preview.
|
||||
nsRefPtr<ICameraControl> cameraControl = ICameraControl::Create(kDefaultCameraId);
|
||||
if (NS_WARN_IF(!cameraControl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sCachedCameraControlStartResult = cameraControl->Start();
|
||||
if (NS_WARN_IF(NS_FAILED(sCachedCameraControlStartResult))) {
|
||||
return;
|
||||
}
|
||||
|
||||
sCachedCameraControl = cameraControl;
|
||||
|
||||
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
if (NS_WARN_IF(!timer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = timer->InitWithFuncCallback(DiscardCachedCameraInstance,
|
||||
nullptr,
|
||||
kCachedCameraTimeoutMs,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
// If we can't start the timer, it's possible for an app to never grab the
|
||||
// camera, leaving the hardware tied up indefinitely. Better to take the
|
||||
// performance hit.
|
||||
sCachedCameraControl = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
sDiscardCachedCameraControlTimer = timer;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsDOMCameraControl::DiscardCachedCameraInstance(nsITimer* aTimer, void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
sDiscardCachedCameraControlTimer = nullptr;
|
||||
sCachedCameraControl = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
|
||||
const CameraConfiguration& aInitialConfig,
|
||||
GetCameraCallback* aOnSuccess,
|
||||
@ -214,7 +274,19 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
|
||||
config.mRecorderProfile = aInitialConfig.mRecorderProfile;
|
||||
}
|
||||
|
||||
mCameraControl = ICameraControl::Create(aCameraId);
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
bool gotCached = false;
|
||||
if (sCachedCameraControl && aCameraId == kDefaultCameraId) {
|
||||
mCameraControl = sCachedCameraControl;
|
||||
sCachedCameraControl = nullptr;
|
||||
gotCached = true;
|
||||
} else {
|
||||
sCachedCameraControl = nullptr;
|
||||
#endif
|
||||
mCameraControl = ICameraControl::Create(aCameraId);
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
}
|
||||
#endif
|
||||
mCurrentConfiguration = initialConfig.forget();
|
||||
|
||||
// Attach our DOM-facing media stream to our viewfinder stream.
|
||||
@ -228,12 +300,20 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
|
||||
mListener = new DOMCameraControlListener(this, mInput);
|
||||
mCameraControl->AddListener(mListener);
|
||||
|
||||
// Start the camera...
|
||||
if (haveInitialConfig) {
|
||||
rv = mCameraControl->Start(&config);
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if (!gotCached || NS_FAILED(sCachedCameraControlStartResult)) {
|
||||
#endif
|
||||
// Start the camera...
|
||||
if (haveInitialConfig) {
|
||||
rv = mCameraControl->Start(&config);
|
||||
} else {
|
||||
rv = mCameraControl->Start();
|
||||
}
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
} else {
|
||||
rv = mCameraControl->Start();
|
||||
rv = mCameraControl->SetConfiguration(config);
|
||||
}
|
||||
#endif
|
||||
if (NS_FAILED(rv)) {
|
||||
mListener->OnUserError(DOMCameraControlListener::kInStartCamera, rv);
|
||||
}
|
||||
|
@ -18,6 +18,9 @@
|
||||
#include "nsHashPropertyBag.h"
|
||||
#include "DeviceStorage.h"
|
||||
#include "DOMCameraControlListener.h"
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "nsITimer.h"
|
||||
#endif
|
||||
|
||||
class nsDOMDeviceStorage;
|
||||
class nsPIDOMWindow;
|
||||
@ -140,6 +143,11 @@ public:
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
static void PreinitCameraHardware();
|
||||
static void DiscardCachedCameraInstance(nsITimer* aTimer, void* aClosure);
|
||||
#endif
|
||||
|
||||
IMPL_EVENT_HANDLER(facesdetected)
|
||||
IMPL_EVENT_HANDLER(shutter)
|
||||
IMPL_EVENT_HANDLER(close)
|
||||
@ -253,6 +261,13 @@ protected:
|
||||
nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
|
||||
DOMCameraControlListener::PreviewState mPreviewState;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// cached camera control, to improve start-up time
|
||||
static StaticRefPtr<ICameraControl> sCachedCameraControl;
|
||||
static nsresult sCachedCameraControlStartResult;
|
||||
static nsCOMPtr<nsITimer> sDiscardCachedCameraControlTimer;
|
||||
#endif
|
||||
|
||||
private:
|
||||
nsDOMCameraControl(const nsDOMCameraControl&) MOZ_DELETE;
|
||||
nsDOMCameraControl& operator=(const nsDOMCameraControl&) MOZ_DELETE;
|
||||
|
@ -264,6 +264,14 @@ CameraPermissionRequest::GetTypes(nsIArray** aTypes)
|
||||
aTypes);
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
/* static */ void
|
||||
nsDOMCameraManager::PreinitCameraHardware()
|
||||
{
|
||||
nsDOMCameraControl::PreinitCameraHardware();
|
||||
}
|
||||
#endif
|
||||
|
||||
already_AddRefed<Promise>
|
||||
nsDOMCameraManager::GetCamera(const nsAString& aCamera,
|
||||
const CameraConfiguration& aInitialConfig,
|
||||
|
@ -89,6 +89,10 @@ public:
|
||||
virtual JSObject* WrapObject(JSContext* aCx)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
static void PreinitCameraHardware();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void XpComShutdown();
|
||||
void Shutdown(uint64_t aWindowId);
|
||||
|
@ -1814,6 +1814,64 @@ TabChild::DoFakeShow()
|
||||
mDidFakeShow = true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
void
|
||||
TabChild::MaybeRequestPreinitCamera()
|
||||
{
|
||||
// Check if this tab will use the `camera` permission.
|
||||
nsCOMPtr<nsIAppsService> appsService = do_GetService("@mozilla.org/AppsService;1");
|
||||
if (NS_WARN_IF(!appsService)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsString manifestUrl = EmptyString();
|
||||
appsService->GetManifestURLByLocalId(OwnAppId(), manifestUrl);
|
||||
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
||||
if (NS_WARN_IF(!secMan)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(uri), manifestUrl);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = secMan->GetAppCodebasePrincipal(uri, OwnAppId(), false,
|
||||
getter_AddRefs(principal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t status = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
|
||||
principal->GetAppStatus(&status);
|
||||
bool isCertified = status == nsIPrincipal::APP_STATUS_CERTIFIED;
|
||||
if (!isCertified) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
|
||||
if (NS_WARN_IF(!permMgr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t permission = nsIPermissionManager::DENY_ACTION;
|
||||
permMgr->TestPermissionFromPrincipal(principal, "camera", &permission);
|
||||
bool hasPermission = permission == nsIPermissionManager::ALLOW_ACTION;
|
||||
if (!hasPermission) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
||||
if (NS_WARN_IF(!observerService)) {
|
||||
return;
|
||||
}
|
||||
|
||||
observerService->NotifyObservers(nullptr, "init-camera-hw", nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
TabChild::RecvShow(const nsIntSize& size)
|
||||
{
|
||||
@ -1838,6 +1896,10 @@ TabChild::RecvShow(const nsIntSize& size)
|
||||
|
||||
baseWindow->SetVisibility(true);
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
MaybeRequestPreinitCamera();
|
||||
#endif
|
||||
|
||||
return InitTabChildGlobal();
|
||||
}
|
||||
|
||||
|
@ -498,6 +498,10 @@ protected:
|
||||
|
||||
virtual bool RecvRequestNotifyAfterRemotePaint();
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
void MaybeRequestPreinitCamera();
|
||||
#endif
|
||||
|
||||
private:
|
||||
/**
|
||||
* Create a new TabChild object.
|
||||
|
Loading…
Reference in New Issue
Block a user