summaryrefslogtreecommitdiff
path: root/widget/android/AndroidBridge.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'widget/android/AndroidBridge.cpp')
-rw-r--r--widget/android/AndroidBridge.cpp1126
1 files changed, 0 insertions, 1126 deletions
diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp
deleted file mode 100644
index dd2cce39a7..0000000000
--- a/widget/android/AndroidBridge.cpp
+++ /dev/null
@@ -1,1126 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * 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 <android/log.h>
-#include <dlfcn.h>
-#include <math.h>
-#include <GLES2/gl2.h>
-
-#include "mozilla/layers/CompositorBridgeChild.h"
-#include "mozilla/layers/CompositorBridgeParent.h"
-
-#include "mozilla/Hal.h"
-#include "nsXULAppAPI.h"
-#include <prthread.h>
-#include "nsXPCOMStrings.h"
-#include "AndroidBridge.h"
-#include "AndroidJNIWrapper.h"
-#include "AndroidBridgeUtilities.h"
-#include "nsAlertsUtils.h"
-#include "nsAppShell.h"
-#include "nsOSHelperAppService.h"
-#include "nsWindow.h"
-#include "mozilla/Preferences.h"
-#include "nsThreadUtils.h"
-#include "nsIThreadManager.h"
-#include "gfxPlatform.h"
-#include "gfxContext.h"
-#include "mozilla/gfx/2D.h"
-#include "gfxUtils.h"
-#include "nsPresContext.h"
-#include "nsIDocShell.h"
-#include "nsPIDOMWindow.h"
-#include "mozilla/dom/ScreenOrientation.h"
-#include "nsIDOMWindowUtils.h"
-#include "nsIDOMClientRect.h"
-#include "mozilla/ClearOnShutdown.h"
-#include "nsPrintfCString.h"
-#include "NativeJSContainer.h"
-#include "nsContentUtils.h"
-#include "nsIScriptError.h"
-#include "nsIHttpChannel.h"
-
-#include "MediaCodec.h"
-#include "SurfaceTexture.h"
-#include "GLContextProvider.h"
-
-#include "mozilla/TimeStamp.h"
-#include "mozilla/UniquePtr.h"
-#include "mozilla/dom/ContentChild.h"
-#include "nsIObserverService.h"
-#include "nsISupportsPrimitives.h"
-#include "MediaPrefs.h"
-#include "WidgetUtils.h"
-
-#include "FennecJNIWrappers.h"
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::jni;
-using namespace mozilla::java;
-
-AndroidBridge* AndroidBridge::sBridge = nullptr;
-static jobject sGlobalContext = nullptr;
-nsDataHashtable<nsStringHashKey, nsString> AndroidBridge::sStoragePaths;
-
-jmethodID AndroidBridge::GetMethodID(JNIEnv* env, jclass jClass,
- const char* methodName, const char* methodType)
-{
- jmethodID methodID = env->GetMethodID(jClass, methodName, methodType);
- if (!methodID) {
- ALOG(">>> FATAL JNI ERROR! GetMethodID(methodName=\"%s\", "
- "methodType=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
- methodName, methodType);
- env->ExceptionDescribe();
- MOZ_CRASH();
- }
- return methodID;
-}
-
-jmethodID AndroidBridge::GetStaticMethodID(JNIEnv* env, jclass jClass,
- const char* methodName, const char* methodType)
-{
- jmethodID methodID = env->GetStaticMethodID(jClass, methodName, methodType);
- if (!methodID) {
- ALOG(">>> FATAL JNI ERROR! GetStaticMethodID(methodName=\"%s\", "
- "methodType=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
- methodName, methodType);
- env->ExceptionDescribe();
- MOZ_CRASH();
- }
- return methodID;
-}
-
-jfieldID AndroidBridge::GetFieldID(JNIEnv* env, jclass jClass,
- const char* fieldName, const char* fieldType)
-{
- jfieldID fieldID = env->GetFieldID(jClass, fieldName, fieldType);
- if (!fieldID) {
- ALOG(">>> FATAL JNI ERROR! GetFieldID(fieldName=\"%s\", "
- "fieldType=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
- fieldName, fieldType);
- env->ExceptionDescribe();
- MOZ_CRASH();
- }
- return fieldID;
-}
-
-jfieldID AndroidBridge::GetStaticFieldID(JNIEnv* env, jclass jClass,
- const char* fieldName, const char* fieldType)
-{
- jfieldID fieldID = env->GetStaticFieldID(jClass, fieldName, fieldType);
- if (!fieldID) {
- ALOG(">>> FATAL JNI ERROR! GetStaticFieldID(fieldName=\"%s\", "
- "fieldType=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
- fieldName, fieldType);
- env->ExceptionDescribe();
- MOZ_CRASH();
- }
- return fieldID;
-}
-
-void
-AndroidBridge::ConstructBridge()
-{
- /* NSS hack -- bionic doesn't handle recursive unloads correctly,
- * because library finalizer functions are called with the dynamic
- * linker lock still held. This results in a deadlock when trying
- * to call dlclose() while we're already inside dlclose().
- * Conveniently, NSS has an env var that can prevent it from unloading.
- */
- putenv("NSS_DISABLE_UNLOAD=1");
-
- MOZ_ASSERT(!sBridge);
- sBridge = new AndroidBridge();
-
- MediaPrefs::GetSingleton();
-}
-
-void
-AndroidBridge::DeconstructBridge()
-{
- if (sBridge) {
- delete sBridge;
- // AndroidBridge destruction requires sBridge to still be valid,
- // so we set sBridge to nullptr after deleting it.
- sBridge = nullptr;
- }
-}
-
-AndroidBridge::~AndroidBridge()
-{
-}
-
-AndroidBridge::AndroidBridge()
- : mUiTaskQueueLock("UiTaskQueue")
-{
- ALOG_BRIDGE("AndroidBridge::Init");
-
- JNIEnv* const jEnv = jni::GetGeckoThreadEnv();
- AutoLocalJNIFrame jniFrame(jEnv);
-
- mMessageQueue = java::GeckoThread::MsgQueue();
- auto msgQueueClass = Class::LocalRef::Adopt(
- jEnv, jEnv->GetObjectClass(mMessageQueue.Get()));
- // mMessageQueueNext must not be null
- mMessageQueueNext = GetMethodID(
- jEnv, msgQueueClass.Get(), "next", "()Landroid/os/Message;");
- // mMessageQueueMessages may be null (e.g. due to proguard optimization)
- mMessageQueueMessages = jEnv->GetFieldID(
- msgQueueClass.Get(), "mMessages", "Landroid/os/Message;");
-
- AutoJNIClass string(jEnv, "java/lang/String");
- jStringClass = string.getGlobalRef();
-
- if (!GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &mAPIVersion, jEnv)) {
- ALOG_BRIDGE("Failed to find API version");
- }
-
- AutoJNIClass channels(jEnv, "java/nio/channels/Channels");
- jChannels = channels.getGlobalRef();
- jChannelCreate = channels.getStaticMethod("newChannel", "(Ljava/io/InputStream;)Ljava/nio/channels/ReadableByteChannel;");
-
- AutoJNIClass readableByteChannel(jEnv, "java/nio/channels/ReadableByteChannel");
- jReadableByteChannel = readableByteChannel.getGlobalRef();
- jByteBufferRead = readableByteChannel.getMethod("read", "(Ljava/nio/ByteBuffer;)I");
-
- AutoJNIClass inputStream(jEnv, "java/io/InputStream");
- jInputStream = inputStream.getGlobalRef();
- jClose = inputStream.getMethod("close", "()V");
- jAvailable = inputStream.getMethod("available", "()I");
-}
-
-// Raw JNIEnv variants.
-jstring AndroidBridge::NewJavaString(JNIEnv* env, const char16_t* string, uint32_t len) {
- jstring ret = env->NewString(reinterpret_cast<const jchar*>(string), len);
- if (env->ExceptionCheck()) {
- ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
- env->ExceptionDescribe();
- env->ExceptionClear();
- return nullptr;
- }
- return ret;
-}
-
-jstring AndroidBridge::NewJavaString(JNIEnv* env, const nsAString& string) {
- return NewJavaString(env, string.BeginReading(), string.Length());
-}
-
-jstring AndroidBridge::NewJavaString(JNIEnv* env, const char* string) {
- return NewJavaString(env, NS_ConvertUTF8toUTF16(string));
-}
-
-jstring AndroidBridge::NewJavaString(JNIEnv* env, const nsACString& string) {
- return NewJavaString(env, NS_ConvertUTF8toUTF16(string));
-}
-
-// AutoLocalJNIFrame variants..
-jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const char16_t* string, uint32_t len) {
- return NewJavaString(frame->GetEnv(), string, len);
-}
-
-jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const nsAString& string) {
- return NewJavaString(frame, string.BeginReading(), string.Length());
-}
-
-jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const char* string) {
- return NewJavaString(frame, NS_ConvertUTF8toUTF16(string));
-}
-
-jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const nsACString& string) {
- return NewJavaString(frame, NS_ConvertUTF8toUTF16(string));
-}
-
-static void
-getHandlersFromStringArray(JNIEnv *aJNIEnv, jobjectArray jArr, jsize aLen,
- nsIMutableArray *aHandlersArray,
- nsIHandlerApp **aDefaultApp,
- const nsAString& aAction = EmptyString(),
- const nsACString& aMimeType = EmptyCString())
-{
- nsString empty = EmptyString();
- for (jsize i = 0; i < aLen; i+=4) {
-
- AutoLocalJNIFrame jniFrame(aJNIEnv, 4);
- nsJNIString name(
- static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i)), aJNIEnv);
- nsJNIString isDefault(
- static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i + 1)), aJNIEnv);
- nsJNIString packageName(
- static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i + 2)), aJNIEnv);
- nsJNIString className(
- static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i + 3)), aJNIEnv);
- nsIHandlerApp* app = nsOSHelperAppService::
- CreateAndroidHandlerApp(name, className, packageName,
- className, aMimeType, aAction);
-
- aHandlersArray->AppendElement(app, false);
- if (aDefaultApp && isDefault.Length() > 0)
- *aDefaultApp = app;
- }
-}
-
-bool
-AndroidBridge::GetHandlersForMimeType(const nsAString& aMimeType,
- nsIMutableArray *aHandlersArray,
- nsIHandlerApp **aDefaultApp,
- const nsAString& aAction)
-{
- ALOG_BRIDGE("AndroidBridge::GetHandlersForMimeType");
-
- auto arr = GeckoAppShell::GetHandlersForMimeType(aMimeType, aAction);
- if (!arr)
- return false;
-
- JNIEnv* const env = arr.Env();
- jsize len = env->GetArrayLength(arr.Get());
-
- if (!aHandlersArray)
- return len > 0;
-
- getHandlersFromStringArray(env, arr.Get(), len, aHandlersArray,
- aDefaultApp, aAction,
- NS_ConvertUTF16toUTF8(aMimeType));
- return true;
-}
-
-bool
-AndroidBridge::GetHWEncoderCapability()
-{
- ALOG_BRIDGE("AndroidBridge::GetHWEncoderCapability");
-
- bool value = GeckoAppShell::GetHWEncoderCapability();
-
- return value;
-}
-
-
-bool
-AndroidBridge::GetHWDecoderCapability()
-{
- ALOG_BRIDGE("AndroidBridge::GetHWDecoderCapability");
-
- bool value = GeckoAppShell::GetHWDecoderCapability();
-
- return value;
-}
-
-bool
-AndroidBridge::GetHandlersForURL(const nsAString& aURL,
- nsIMutableArray* aHandlersArray,
- nsIHandlerApp **aDefaultApp,
- const nsAString& aAction)
-{
- ALOG_BRIDGE("AndroidBridge::GetHandlersForURL");
-
- auto arr = GeckoAppShell::GetHandlersForURL(aURL, aAction);
- if (!arr)
- return false;
-
- JNIEnv* const env = arr.Env();
- jsize len = env->GetArrayLength(arr.Get());
-
- if (!aHandlersArray)
- return len > 0;
-
- getHandlersFromStringArray(env, arr.Get(), len, aHandlersArray,
- aDefaultApp, aAction);
- return true;
-}
-
-void
-AndroidBridge::GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType)
-{
- ALOG_BRIDGE("AndroidBridge::GetMimeTypeFromExtensions");
-
- auto jstrType = GeckoAppShell::GetMimeTypeFromExtensions(aFileExt);
-
- if (jstrType) {
- aMimeType = jstrType->ToCString();
- }
-}
-
-void
-AndroidBridge::GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt)
-{
- ALOG_BRIDGE("AndroidBridge::GetExtensionFromMimeType");
-
- auto jstrExt = GeckoAppShell::GetExtensionFromMimeType(aMimeType);
-
- if (jstrExt) {
- aFileExt = jstrExt->ToCString();
- }
-}
-
-bool
-AndroidBridge::GetClipboardText(nsAString& aText)
-{
- ALOG_BRIDGE("AndroidBridge::GetClipboardText");
-
- auto text = Clipboard::GetText();
-
- if (text) {
- aText = text->ToString();
- }
- return !!text;
-}
-
-int
-AndroidBridge::GetDPI()
-{
- static int sDPI = 0;
- if (sDPI)
- return sDPI;
-
- const int DEFAULT_DPI = 160;
-
- sDPI = GeckoAppShell::GetDpi();
- if (!sDPI) {
- return DEFAULT_DPI;
- }
-
- return sDPI;
-}
-
-int
-AndroidBridge::GetScreenDepth()
-{
- ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
-
- static int sDepth = 0;
- if (sDepth)
- return sDepth;
-
- const int DEFAULT_DEPTH = 16;
-
- if (jni::IsAvailable()) {
- sDepth = GeckoAppShell::GetScreenDepth();
- }
- if (!sDepth)
- return DEFAULT_DEPTH;
-
- return sDepth;
-}
-void
-AndroidBridge::Vibrate(const nsTArray<uint32_t>& aPattern)
-{
- ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
-
- uint32_t len = aPattern.Length();
- if (!len) {
- ALOG_BRIDGE(" invalid 0-length array");
- return;
- }
-
- // It's clear if this worth special-casing, but it creates less
- // java junk, so dodges the GC.
- if (len == 1) {
- jlong d = aPattern[0];
- if (d < 0) {
- ALOG_BRIDGE(" invalid vibration duration < 0");
- return;
- }
- GeckoAppShell::Vibrate(d);
- return;
- }
-
- // First element of the array vibrate() expects is how long to wait
- // *before* vibrating. For us, this is always 0.
-
- JNIEnv* const env = jni::GetGeckoThreadEnv();
- AutoLocalJNIFrame jniFrame(env, 1);
-
- jlongArray array = env->NewLongArray(len + 1);
- if (!array) {
- ALOG_BRIDGE(" failed to allocate array");
- return;
- }
-
- jlong* elts = env->GetLongArrayElements(array, nullptr);
- elts[0] = 0;
- for (uint32_t i = 0; i < aPattern.Length(); ++i) {
- jlong d = aPattern[i];
- if (d < 0) {
- ALOG_BRIDGE(" invalid vibration duration < 0");
- env->ReleaseLongArrayElements(array, elts, JNI_ABORT);
- return;
- }
- elts[i + 1] = d;
- }
- env->ReleaseLongArrayElements(array, elts, 0);
-
- GeckoAppShell::Vibrate(LongArray::Ref::From(array), -1 /* don't repeat */);
-}
-
-void
-AndroidBridge::GetSystemColors(AndroidSystemColors *aColors)
-{
-
- NS_ASSERTION(aColors != nullptr, "AndroidBridge::GetSystemColors: aColors is null!");
- if (!aColors)
- return;
-
- auto arr = GeckoAppShell::GetSystemColors();
- if (!arr)
- return;
-
- JNIEnv* const env = arr.Env();
- uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr.Get()));
- jint *elements = env->GetIntArrayElements(arr.Get(), 0);
-
- uint32_t colorsCount = sizeof(AndroidSystemColors) / sizeof(nscolor);
- if (len < colorsCount)
- colorsCount = len;
-
- // Convert Android colors to nscolor by switching R and B in the ARGB 32 bit value
- nscolor *colors = (nscolor*)aColors;
-
- for (uint32_t i = 0; i < colorsCount; i++) {
- uint32_t androidColor = static_cast<uint32_t>(elements[i]);
- uint8_t r = (androidColor & 0x00ff0000) >> 16;
- uint8_t b = (androidColor & 0x000000ff);
- colors[i] = (androidColor & 0xff00ff00) | (b << 16) | r;
- }
-
- env->ReleaseIntArrayElements(arr.Get(), elements, 0);
-}
-
-void
-AndroidBridge::GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize, uint8_t * const aBuf)
-{
- ALOG_BRIDGE("AndroidBridge::GetIconForExtension");
- NS_ASSERTION(aBuf != nullptr, "AndroidBridge::GetIconForExtension: aBuf is null!");
- if (!aBuf)
- return;
-
- auto arr = GeckoAppShell::GetIconForExtension(NS_ConvertUTF8toUTF16(aFileExt), aIconSize);
-
- NS_ASSERTION(arr != nullptr, "AndroidBridge::GetIconForExtension: Returned pixels array is null!");
- if (!arr)
- return;
-
- JNIEnv* const env = arr.Env();
- uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr.Get()));
- jbyte *elements = env->GetByteArrayElements(arr.Get(), 0);
-
- uint32_t bufSize = aIconSize * aIconSize * 4;
- NS_ASSERTION(len == bufSize, "AndroidBridge::GetIconForExtension: Pixels array is incomplete!");
- if (len == bufSize)
- memcpy(aBuf, elements, bufSize);
-
- env->ReleaseByteArrayElements(arr.Get(), elements, 0);
-}
-
-bool
-AndroidBridge::GetStaticIntField(const char *className, const char *fieldName, int32_t* aInt, JNIEnv* jEnv /* = nullptr */)
-{
- ALOG_BRIDGE("AndroidBridge::GetStaticIntField %s", fieldName);
-
- if (!jEnv) {
- if (!jni::IsAvailable()) {
- return false;
- }
- jEnv = jni::GetGeckoThreadEnv();
- }
-
- AutoJNIClass cls(jEnv, className);
- jfieldID field = cls.getStaticField(fieldName, "I");
-
- if (!field) {
- return false;
- }
-
- *aInt = static_cast<int32_t>(jEnv->GetStaticIntField(cls.getRawRef(), field));
- return true;
-}
-
-bool
-AndroidBridge::GetStaticStringField(const char *className, const char *fieldName, nsAString &result, JNIEnv* jEnv /* = nullptr */)
-{
- ALOG_BRIDGE("AndroidBridge::GetStaticStringField %s", fieldName);
-
- if (!jEnv) {
- if (!jni::IsAvailable()) {
- return false;
- }
- jEnv = jni::GetGeckoThreadEnv();
- }
-
- AutoLocalJNIFrame jniFrame(jEnv, 1);
- AutoJNIClass cls(jEnv, className);
- jfieldID field = cls.getStaticField(fieldName, "Ljava/lang/String;");
-
- if (!field) {
- return false;
- }
-
- jstring jstr = (jstring) jEnv->GetStaticObjectField(cls.getRawRef(), field);
- if (!jstr)
- return false;
-
- result.Assign(nsJNIString(jstr, jEnv));
- return true;
-}
-
-namespace mozilla {
- class TracerRunnable : public Runnable{
- public:
- TracerRunnable() {
- mTracerLock = new Mutex("TracerRunnable");
- mTracerCondVar = new CondVar(*mTracerLock, "TracerRunnable");
- mMainThread = do_GetMainThread();
-
- }
- ~TracerRunnable() {
- delete mTracerCondVar;
- delete mTracerLock;
- mTracerLock = nullptr;
- mTracerCondVar = nullptr;
- }
-
- virtual nsresult Run() {
- MutexAutoLock lock(*mTracerLock);
- if (!AndroidBridge::Bridge())
- return NS_OK;
-
- mHasRun = true;
- mTracerCondVar->Notify();
- return NS_OK;
- }
-
- bool Fire() {
- if (!mTracerLock || !mTracerCondVar)
- return false;
- MutexAutoLock lock(*mTracerLock);
- mHasRun = false;
- mMainThread->Dispatch(this, NS_DISPATCH_NORMAL);
- while (!mHasRun)
- mTracerCondVar->Wait();
- return true;
- }
-
- void Signal() {
- MutexAutoLock lock(*mTracerLock);
- mHasRun = true;
- mTracerCondVar->Notify();
- }
- private:
- Mutex* mTracerLock;
- CondVar* mTracerCondVar;
- bool mHasRun;
- nsCOMPtr<nsIThread> mMainThread;
-
- };
- StaticRefPtr<TracerRunnable> sTracerRunnable;
-
- bool InitWidgetTracing() {
- if (!sTracerRunnable)
- sTracerRunnable = new TracerRunnable();
- return true;
- }
-
- void CleanUpWidgetTracing() {
- sTracerRunnable = nullptr;
- }
-
- bool FireAndWaitForTracerEvent() {
- if (sTracerRunnable)
- return sTracerRunnable->Fire();
- return false;
- }
-
- void SignalTracerThread()
- {
- if (sTracerRunnable)
- return sTracerRunnable->Signal();
- }
-
-}
-
-
-void
-AndroidBridge::GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
-{
- ALOG_BRIDGE("AndroidBridge::GetCurrentBatteryInformation");
-
- // To prevent calling too many methods through JNI, the Java method returns
- // an array of double even if we actually want a double and a boolean.
- auto arr = GeckoAppShell::GetCurrentBatteryInformation();
-
- JNIEnv* const env = arr.Env();
- if (!arr || env->GetArrayLength(arr.Get()) != 3) {
- return;
- }
-
- jdouble* info = env->GetDoubleArrayElements(arr.Get(), 0);
-
- aBatteryInfo->level() = info[0];
- aBatteryInfo->charging() = info[1] == 1.0f;
- aBatteryInfo->remainingTime() = info[2];
-
- env->ReleaseDoubleArrayElements(arr.Get(), info, 0);
-}
-
-void
-AndroidBridge::HandleGeckoMessage(JSContext* cx, JS::HandleObject object)
-{
- ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
-
- auto message = widget::CreateNativeJSContainer(cx, object);
- GeckoAppShell::HandleGeckoMessage(message);
-}
-
-void
-AndroidBridge::GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
-{
- ALOG_BRIDGE("AndroidBridge::GetCurrentNetworkInformation");
-
- // To prevent calling too many methods through JNI, the Java method returns
- // an array of double even if we actually want an integer, a boolean, and an integer.
-
- auto arr = GeckoAppShell::GetCurrentNetworkInformation();
-
- JNIEnv* const env = arr.Env();
- if (!arr || env->GetArrayLength(arr.Get()) != 3) {
- return;
- }
-
- jdouble* info = env->GetDoubleArrayElements(arr.Get(), 0);
-
- aNetworkInfo->type() = info[0];
- aNetworkInfo->isWifi() = info[1] == 1.0f;
- aNetworkInfo->dhcpGateway() = info[2];
-
- env->ReleaseDoubleArrayElements(arr.Get(), info, 0);
-}
-
-jobject
-AndroidBridge::GetGlobalContextRef() {
- if (sGlobalContext) {
- return sGlobalContext;
- }
-
- JNIEnv* const env = GetEnvForThread();
- AutoLocalJNIFrame jniFrame(env, 4);
-
- auto context = GeckoAppShell::GetContext();
- if (!context) {
- ALOG_BRIDGE("%s: Could not GetContext()", __FUNCTION__);
- return 0;
- }
- jclass contextClass = env->FindClass("android/content/Context");
- if (!contextClass) {
- ALOG_BRIDGE("%s: Could not find Context class.", __FUNCTION__);
- return 0;
- }
- jmethodID mid = env->GetMethodID(contextClass, "getApplicationContext",
- "()Landroid/content/Context;");
- if (!mid) {
- ALOG_BRIDGE("%s: Could not find getApplicationContext.", __FUNCTION__);
- return 0;
- }
- jobject appContext = env->CallObjectMethod(context.Get(), mid);
- if (!appContext) {
- ALOG_BRIDGE("%s: getApplicationContext failed.", __FUNCTION__);
- return 0;
- }
-
- sGlobalContext = env->NewGlobalRef(appContext);
- MOZ_ASSERT(sGlobalContext);
- return sGlobalContext;
-}
-
-/* Implementation file */
-NS_IMPL_ISUPPORTS(nsAndroidBridge, nsIAndroidBridge)
-
-nsAndroidBridge::nsAndroidBridge()
-{
- AddObservers();
-}
-
-nsAndroidBridge::~nsAndroidBridge()
-{
- RemoveObservers();
-}
-
-NS_IMETHODIMP nsAndroidBridge::HandleGeckoMessage(JS::HandleValue val,
- JSContext *cx)
-{
- if (val.isObject()) {
- JS::RootedObject object(cx, &val.toObject());
- AndroidBridge::Bridge()->HandleGeckoMessage(cx, object);
- return NS_OK;
- }
-
- // Now handle legacy JSON messages.
- if (!val.isString()) {
- return NS_ERROR_INVALID_ARG;
- }
- JS::RootedString jsonStr(cx, val.toString());
-
- JS::RootedValue jsonVal(cx);
- if (!JS_ParseJSON(cx, jsonStr, &jsonVal) || !jsonVal.isObject()) {
- return NS_ERROR_INVALID_ARG;
- }
-
- // Spit out a warning before sending the message.
- nsContentUtils::ReportToConsoleNonLocalized(
- NS_LITERAL_STRING("Use of JSON is deprecated. "
- "Please pass Javascript objects directly to handleGeckoMessage."),
- nsIScriptError::warningFlag,
- NS_LITERAL_CSTRING("nsIAndroidBridge"),
- nullptr);
-
- JS::RootedObject object(cx, &jsonVal.toObject());
- AndroidBridge::Bridge()->HandleGeckoMessage(cx, object);
- return NS_OK;
-}
-
-NS_IMETHODIMP nsAndroidBridge::ContentDocumentChanged(mozIDOMWindowProxy* aWindow)
-{
- AndroidBridge::Bridge()->ContentDocumentChanged(aWindow);
- return NS_OK;
-}
-
-NS_IMETHODIMP nsAndroidBridge::IsContentDocumentDisplayed(mozIDOMWindowProxy* aWindow,
- bool *aRet)
-{
- *aRet = AndroidBridge::Bridge()->IsContentDocumentDisplayed(aWindow);
- return NS_OK;
-}
-
-NS_IMETHODIMP
-nsAndroidBridge::Observe(nsISupports* aSubject, const char* aTopic,
- const char16_t* aData)
-{
- if (!strcmp(aTopic, "xpcom-shutdown")) {
- RemoveObservers();
- } else if (!strcmp(aTopic, "media-playback")) {
- ALOG_BRIDGE("nsAndroidBridge::Observe, get media-playback event.");
-
- nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
- if (!wrapper) {
- return NS_OK;
- }
-
- uint64_t windowId = 0;
- nsresult rv = wrapper->GetData(&windowId);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- nsAutoString activeStr(aData);
- bool isPlaying = activeStr.EqualsLiteral("active");
- UpdateAudioPlayingWindows(windowId, isPlaying);
- }
- return NS_OK;
-}
-
-void
-nsAndroidBridge::UpdateAudioPlayingWindows(uint64_t aWindowId,
- bool aPlaying)
-{
- // Request audio focus for the first audio playing window and abandon focus
- // for the last audio playing window.
- if (aPlaying && !mAudioPlayingWindows.Contains(aWindowId)) {
- mAudioPlayingWindows.AppendElement(aWindowId);
- if (mAudioPlayingWindows.Length() == 1) {
- ALOG_BRIDGE("nsAndroidBridge, request audio focus.");
- AudioFocusAgent::NotifyStartedPlaying();
- }
- } else if (!aPlaying && mAudioPlayingWindows.Contains(aWindowId)) {
- mAudioPlayingWindows.RemoveElement(aWindowId);
- if (mAudioPlayingWindows.Length() == 0) {
- ALOG_BRIDGE("nsAndroidBridge, abandon audio focus.");
- AudioFocusAgent::NotifyStoppedPlaying();
- }
- }
-}
-
-void
-nsAndroidBridge::AddObservers()
-{
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- if (obs) {
- obs->AddObserver(this, "xpcom-shutdown", false);
- if (jni::IsFennec()) { // No AudioFocusAgent in non-Fennec environment.
- obs->AddObserver(this, "media-playback", false);
- }
- }
-}
-
-void
-nsAndroidBridge::RemoveObservers()
-{
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- if (obs) {
- obs->RemoveObserver(this, "xpcom-shutdown");
- if (jni::IsFennec()) { // No AudioFocusAgent in non-Fennec environment.
- obs->RemoveObserver(this, "media-playback");
- }
- }
-}
-
-uint32_t
-AndroidBridge::GetScreenOrientation()
-{
- ALOG_BRIDGE("AndroidBridge::GetScreenOrientation");
-
- int16_t orientation = GeckoAppShell::GetScreenOrientation();
-
- if (!orientation)
- return dom::eScreenOrientation_None;
-
- return static_cast<dom::ScreenOrientationInternal>(orientation);
-}
-
-uint16_t
-AndroidBridge::GetScreenAngle()
-{
- return GeckoAppShell::GetScreenAngle();
-}
-
-nsresult
-AndroidBridge::GetProxyForURI(const nsACString & aSpec,
- const nsACString & aScheme,
- const nsACString & aHost,
- const int32_t aPort,
- nsACString & aResult)
-{
- if (!jni::IsAvailable()) {
- return NS_ERROR_FAILURE;
- }
-
- auto jstrRet = GeckoAppShell::GetProxyForURI(aSpec, aScheme, aHost, aPort);
-
- if (!jstrRet)
- return NS_ERROR_FAILURE;
-
- aResult = jstrRet->ToCString();
- return NS_OK;
-}
-
-bool
-AndroidBridge::PumpMessageLoop()
-{
- JNIEnv* const env = jni::GetGeckoThreadEnv();
-
- if (mMessageQueueMessages) {
- auto msg = Object::LocalRef::Adopt(env,
- env->GetObjectField(mMessageQueue.Get(),
- mMessageQueueMessages));
- // if queue.mMessages is null, queue.next() will block, which we don't
- // want. It turns out to be an order of magnitude more performant to do
- // this extra check here and block less vs. one fewer checks here and
- // more blocking.
- if (!msg) {
- return false;
- }
- }
-
- auto msg = Object::LocalRef::Adopt(
- env, env->CallObjectMethod(mMessageQueue.Get(), mMessageQueueNext));
- if (!msg) {
- return false;
- }
-
- return GeckoThread::PumpMessageLoop(msg);
-}
-
-NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp)
-{
- nsAppShell* const appShell = nsAppShell::Get();
- if (appShell)
- NS_IF_ADDREF(*aBrowserApp = appShell->GetBrowserApp());
- return NS_OK;
-}
-
-NS_IMETHODIMP nsAndroidBridge::SetBrowserApp(nsIAndroidBrowserApp *aBrowserApp)
-{
- nsAppShell* const appShell = nsAppShell::Get();
- if (appShell)
- appShell->SetBrowserApp(aBrowserApp);
- return NS_OK;
-}
-
-extern "C"
-__attribute__ ((visibility("default")))
-jobject JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *env, jclass, jlong size);
-
-static jni::DependentRef<java::GeckoLayerClient>
-GetJavaLayerClient(mozIDOMWindowProxy* aWindow)
-{
- MOZ_ASSERT(aWindow);
-
- nsCOMPtr<nsPIDOMWindowOuter> domWindow = nsPIDOMWindowOuter::From(aWindow);
- nsCOMPtr<nsIWidget> widget =
- widget::WidgetUtils::DOMWindowToWidget(domWindow);
- MOZ_ASSERT(widget);
-
- return static_cast<nsWindow*>(widget.get())->GetLayerClient();
-}
-
-void
-AndroidBridge::ContentDocumentChanged(mozIDOMWindowProxy* aWindow)
-{
- auto layerClient = GetJavaLayerClient(aWindow);
- if (!layerClient) {
- return;
- }
- layerClient->ContentDocumentChanged();
-}
-
-bool
-AndroidBridge::IsContentDocumentDisplayed(mozIDOMWindowProxy* aWindow)
-{
- auto layerClient = GetJavaLayerClient(aWindow);
- if (!layerClient) {
- return false;
- }
- return layerClient->IsContentDocumentDisplayed();
-}
-
-class AndroidBridge::DelayedTask
-{
- using TimeStamp = mozilla::TimeStamp;
- using TimeDuration = mozilla::TimeDuration;
-
-public:
- DelayedTask(already_AddRefed<Runnable> aTask)
- : mTask(aTask)
- , mRunTime() // Null timestamp representing no delay.
- {}
-
- DelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs)
- : mTask(aTask)
- , mRunTime(TimeStamp::Now() + TimeDuration::FromMilliseconds(aDelayMs))
- {}
-
- bool IsEarlierThan(const DelayedTask& aOther) const
- {
- if (mRunTime) {
- return aOther.mRunTime ? mRunTime < aOther.mRunTime : false;
- }
- // In the case of no delay, we're earlier if aOther has a delay.
- // Otherwise, we're not earlier, to maintain task order.
- return !!aOther.mRunTime;
- }
-
- int64_t MillisecondsToRunTime() const
- {
- if (mRunTime) {
- return int64_t((mRunTime - TimeStamp::Now()).ToMilliseconds());
- }
- return 0;
- }
-
- already_AddRefed<Runnable> TakeTask()
- {
- return mTask.forget();
- }
-
-private:
- RefPtr<Runnable> mTask;
- const TimeStamp mRunTime;
-};
-
-
-void
-AndroidBridge::PostTaskToUiThread(already_AddRefed<Runnable> aTask, int aDelayMs)
-{
- // add the new task into the mUiTaskQueue, sorted with
- // the earliest task first in the queue
- size_t i;
- DelayedTask newTask(aDelayMs ? DelayedTask(mozilla::Move(aTask), aDelayMs)
- : DelayedTask(mozilla::Move(aTask)));
-
- {
- MutexAutoLock lock(mUiTaskQueueLock);
-
- for (i = 0; i < mUiTaskQueue.Length(); i++) {
- if (newTask.IsEarlierThan(mUiTaskQueue[i])) {
- mUiTaskQueue.InsertElementAt(i, mozilla::Move(newTask));
- break;
- }
- }
-
- if (i == mUiTaskQueue.Length()) {
- // We didn't insert the task, which means we should append it.
- mUiTaskQueue.AppendElement(mozilla::Move(newTask));
- }
- }
-
- if (i == 0) {
- // if we're inserting it at the head of the queue, notify Java because
- // we need to get a callback at an earlier time than the last scheduled
- // callback
- GeckoThread::RequestUiThreadCallback(int64_t(aDelayMs));
- }
-}
-
-int64_t
-AndroidBridge::RunDelayedUiThreadTasks()
-{
- MutexAutoLock lock(mUiTaskQueueLock);
-
- while (!mUiTaskQueue.IsEmpty()) {
- const int64_t timeLeft = mUiTaskQueue[0].MillisecondsToRunTime();
- if (timeLeft > 0) {
- // this task (and therefore all remaining tasks)
- // have not yet reached their runtime. return the
- // time left until we should be called again
- return timeLeft;
- }
-
- // Retrieve task before unlocking/running.
- RefPtr<Runnable> nextTask(mUiTaskQueue[0].TakeTask());
- mUiTaskQueue.RemoveElementAt(0);
-
- // Unlock to allow posting new tasks reentrantly.
- MutexAutoUnlock unlock(mUiTaskQueueLock);
- nextTask->Run();
- }
- return -1;
-}
-
-Object::LocalRef AndroidBridge::ChannelCreate(Object::Param stream) {
- JNIEnv* const env = GetEnvForThread();
- auto rv = Object::LocalRef::Adopt(env, env->CallStaticObjectMethod(
- sBridge->jChannels, sBridge->jChannelCreate, stream.Get()));
- MOZ_CATCH_JNI_EXCEPTION(env);
- return rv;
-}
-
-void AndroidBridge::InputStreamClose(Object::Param obj) {
- JNIEnv* const env = GetEnvForThread();
- env->CallVoidMethod(obj.Get(), sBridge->jClose);
- MOZ_CATCH_JNI_EXCEPTION(env);
-}
-
-uint32_t AndroidBridge::InputStreamAvailable(Object::Param obj) {
- JNIEnv* const env = GetEnvForThread();
- auto rv = env->CallIntMethod(obj.Get(), sBridge->jAvailable);
- MOZ_CATCH_JNI_EXCEPTION(env);
- return rv;
-}
-
-nsresult AndroidBridge::InputStreamRead(Object::Param obj, char *aBuf, uint32_t aCount, uint32_t *aRead) {
- JNIEnv* const env = GetEnvForThread();
- auto arr = ByteBuffer::New(aBuf, aCount);
- jint read = env->CallIntMethod(obj.Get(), sBridge->jByteBufferRead, arr.Get());
-
- if (env->ExceptionCheck()) {
- env->ExceptionClear();
- return NS_ERROR_FAILURE;
- }
-
- if (read <= 0) {
- *aRead = 0;
- return NS_OK;
- }
- *aRead = read;
- return NS_OK;
-}