diff options
Diffstat (limited to 'widget/android/nsScreenManagerAndroid.cpp')
-rw-r--r-- | widget/android/nsScreenManagerAndroid.cpp | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/widget/android/nsScreenManagerAndroid.cpp b/widget/android/nsScreenManagerAndroid.cpp new file mode 100644 index 000000000..4a79b9dab --- /dev/null +++ b/widget/android/nsScreenManagerAndroid.cpp @@ -0,0 +1,264 @@ +/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set sw=4 ts=4 expandtab: + * 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/. */ + +#define MOZ_FATAL_ASSERTIONS_FOR_THREAD_SAFETY + +#include "mozilla/SyncRunnable.h" +#include "nsScreenManagerAndroid.h" +#include "nsServiceManagerUtils.h" +#include "AndroidRect.h" +#include "FennecJNINatives.h" +#include "nsAppShell.h" +#include "nsThreadUtils.h" + +#include <android/log.h> +#include <mozilla/jni/Refs.h> + +#define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "nsScreenManagerAndroid", ## args) + +using namespace mozilla; +using namespace mozilla::java; + +static uint32_t sScreenId = 0; +const uint32_t PRIMARY_SCREEN_ID = 0; + +nsScreenAndroid::nsScreenAndroid(DisplayType aDisplayType, nsIntRect aRect) + : mId(sScreenId++) + , mDisplayType(aDisplayType) + , mRect(aRect) + , mDensity(0.0) +{ + // ensure that the ID of the primary screen would be PRIMARY_SCREEN_ID. + if (mDisplayType == DisplayType::DISPLAY_PRIMARY) { + mId = PRIMARY_SCREEN_ID; + } +} + +nsScreenAndroid::~nsScreenAndroid() +{ +} + +float +nsScreenAndroid::GetDensity() { + if (mDensity != 0.0) { + return mDensity; + } + if (mDisplayType == DisplayType::DISPLAY_PRIMARY) { + mDensity = mozilla::jni::IsAvailable() ? GeckoAppShell::GetDensity() + : 1.0; // xpcshell most likely + return mDensity; + } + return 1.0; +} + +NS_IMETHODIMP +nsScreenAndroid::GetId(uint32_t *outId) +{ + *outId = mId; + return NS_OK; +} + +NS_IMETHODIMP +nsScreenAndroid::GetRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) +{ + if (mDisplayType != DisplayType::DISPLAY_PRIMARY) { + *outLeft = mRect.x; + *outTop = mRect.y; + *outWidth = mRect.width; + *outHeight = mRect.height; + + return NS_OK; + } + + if (!mozilla::jni::IsAvailable()) { + // xpcshell most likely + *outLeft = *outTop = *outWidth = *outHeight = 0; + return NS_ERROR_FAILURE; + } + + java::sdk::Rect::LocalRef rect = java::GeckoAppShell::GetScreenSize(); + rect->Left(outLeft); + rect->Top(outTop); + rect->Width(outWidth); + rect->Height(outHeight); + + return NS_OK; +} + + +NS_IMETHODIMP +nsScreenAndroid::GetAvailRect(int32_t *outLeft, int32_t *outTop, int32_t *outWidth, int32_t *outHeight) +{ + return GetRect(outLeft, outTop, outWidth, outHeight); +} + + + +NS_IMETHODIMP +nsScreenAndroid::GetPixelDepth(int32_t *aPixelDepth) +{ + if (!mozilla::jni::IsAvailable()) { + // xpcshell most likely + *aPixelDepth = 16; + return NS_ERROR_FAILURE; + } + + *aPixelDepth = java::GeckoAppShell::GetScreenDepth(); + return NS_OK; +} + + +NS_IMETHODIMP +nsScreenAndroid::GetColorDepth(int32_t *aColorDepth) +{ + return GetPixelDepth(aColorDepth); +} + + +void +nsScreenAndroid::ApplyMinimumBrightness(uint32_t aBrightness) +{ + if (mDisplayType == DisplayType::DISPLAY_PRIMARY && + mozilla::jni::IsAvailable()) { + java::GeckoAppShell::SetKeepScreenOn(aBrightness == BRIGHTNESS_FULL); + } +} + +class nsScreenManagerAndroid::ScreenManagerHelperSupport final + : public ScreenManagerHelper::Natives<ScreenManagerHelperSupport> +{ +public: + typedef ScreenManagerHelper::Natives<ScreenManagerHelperSupport> Base; + + static int32_t AddDisplay(int32_t aDisplayType, int32_t aWidth, int32_t aHeight, float aDensity) { + int32_t screenId = -1; // return value + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); + SyncRunnable::DispatchToThread(mainThread, NS_NewRunnableFunction( + [&aDisplayType, &aWidth, &aHeight, &aDensity, &screenId] { + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr<nsIScreenManager> screenMgr = + do_GetService("@mozilla.org/gfx/screenmanager;1"); + MOZ_ASSERT(screenMgr, "Failed to get nsIScreenManager"); + + RefPtr<nsScreenManagerAndroid> screenMgrAndroid = + (nsScreenManagerAndroid*) screenMgr.get(); + RefPtr<nsScreenAndroid> screen = + screenMgrAndroid->AddScreen(static_cast<DisplayType>(aDisplayType), + nsIntRect(0, 0, aWidth, aHeight)); + MOZ_ASSERT(screen); + screen->SetDensity(aDensity); + screenId = static_cast<int32_t>(screen->GetId()); + }).take()); + return screenId; + } + + static void RemoveDisplay(int32_t aScreenId) { + nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); + SyncRunnable::DispatchToThread(mainThread, NS_NewRunnableFunction( + [&aScreenId] { + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr<nsIScreenManager> screenMgr = + do_GetService("@mozilla.org/gfx/screenmanager;1"); + MOZ_ASSERT(screenMgr, "Failed to get nsIScreenManager"); + + RefPtr<nsScreenManagerAndroid> screenMgrAndroid = + (nsScreenManagerAndroid*) screenMgr.get(); + screenMgrAndroid->RemoveScreen(aScreenId); + }).take()); + } +}; + +NS_IMPL_ISUPPORTS(nsScreenManagerAndroid, nsIScreenManager) + +nsScreenManagerAndroid::nsScreenManagerAndroid() +{ + if (mozilla::jni::IsAvailable()) { + ScreenManagerHelperSupport::Base::Init(); + } + nsCOMPtr<nsIScreen> screen = AddScreen(DisplayType::DISPLAY_PRIMARY); + MOZ_ASSERT(screen); +} + +nsScreenManagerAndroid::~nsScreenManagerAndroid() +{ +} + +NS_IMETHODIMP +nsScreenManagerAndroid::GetPrimaryScreen(nsIScreen **outScreen) +{ + ScreenForId(PRIMARY_SCREEN_ID, outScreen); + return NS_OK; +} + +NS_IMETHODIMP +nsScreenManagerAndroid::ScreenForId(uint32_t aId, + nsIScreen **outScreen) +{ + for (size_t i = 0; i < mScreens.Length(); ++i) { + if (aId == mScreens[i]->GetId()) { + nsCOMPtr<nsIScreen> screen = (nsIScreen*) mScreens[i]; + screen.forget(outScreen); + return NS_OK; + } + } + + *outScreen = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsScreenManagerAndroid::ScreenForRect(int32_t inLeft, + int32_t inTop, + int32_t inWidth, + int32_t inHeight, + nsIScreen **outScreen) +{ + // Not support to query non-primary screen with rect. + return GetPrimaryScreen(outScreen); +} + +NS_IMETHODIMP +nsScreenManagerAndroid::ScreenForNativeWidget(void *aWidget, nsIScreen **outScreen) +{ + // Not support to query non-primary screen with native widget. + return GetPrimaryScreen(outScreen); +} + +NS_IMETHODIMP +nsScreenManagerAndroid::GetNumberOfScreens(uint32_t *aNumberOfScreens) +{ + *aNumberOfScreens = mScreens.Length(); + return NS_OK; +} + +NS_IMETHODIMP +nsScreenManagerAndroid::GetSystemDefaultScale(float *aDefaultScale) +{ + *aDefaultScale = 1.0f; + return NS_OK; +} + +already_AddRefed<nsScreenAndroid> +nsScreenManagerAndroid::AddScreen(DisplayType aDisplayType, nsIntRect aRect) +{ + ALOG("nsScreenManagerAndroid: add %s screen", + (aDisplayType == DisplayType::DISPLAY_PRIMARY ? "PRIMARY" : + (aDisplayType == DisplayType::DISPLAY_EXTERNAL ? "EXTERNAL" : + "VIRTUAL"))); + RefPtr<nsScreenAndroid> screen = new nsScreenAndroid(aDisplayType, aRect); + mScreens.AppendElement(screen); + return screen.forget(); +} + +void +nsScreenManagerAndroid::RemoveScreen(uint32_t aScreenId) +{ + for (size_t i = 0; i < mScreens.Length(); i++) { + if (aScreenId == mScreens[i]->GetId()) { + mScreens.RemoveElementAt(i); + } + } +} |