2010-06-03 20:56:36 +00:00
|
|
|
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
2012-05-21 11:12:37 +00:00
|
|
|
* 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/. */
|
2010-06-03 20:56:36 +00:00
|
|
|
|
|
|
|
#include <android/log.h>
|
2011-06-16 09:03:00 +00:00
|
|
|
#include <dlfcn.h>
|
2014-05-06 05:33:29 +00:00
|
|
|
#include <math.h>
|
2015-08-04 21:47:28 +00:00
|
|
|
#include <GLES2/gl2.h>
|
|
|
|
|
2016-03-22 18:08:38 +00:00
|
|
|
#include "mozilla/layers/CompositorBridgeChild.h"
|
|
|
|
#include "mozilla/layers/CompositorBridgeParent.h"
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2011-11-02 15:35:11 +00:00
|
|
|
#include "mozilla/Hal.h"
|
2010-08-17 08:07:45 +00:00
|
|
|
#include "nsXULAppAPI.h"
|
2010-06-03 20:56:36 +00:00
|
|
|
#include <prthread.h>
|
2010-06-30 02:22:08 +00:00
|
|
|
#include "nsXPCOMStrings.h"
|
2010-06-03 20:56:36 +00:00
|
|
|
#include "AndroidBridge.h"
|
2013-02-09 23:50:28 +00:00
|
|
|
#include "AndroidJNIWrapper.h"
|
2013-09-09 12:57:36 +00:00
|
|
|
#include "AndroidBridgeUtilities.h"
|
2015-12-03 15:56:04 +00:00
|
|
|
#include "nsAlertsUtils.h"
|
2010-06-15 02:17:37 +00:00
|
|
|
#include "nsAppShell.h"
|
2010-09-30 15:37:36 +00:00
|
|
|
#include "nsOSHelperAppService.h"
|
2011-04-11 20:41:03 +00:00
|
|
|
#include "nsWindow.h"
|
2011-06-07 07:38:00 +00:00
|
|
|
#include "mozilla/Preferences.h"
|
2011-08-04 07:32:57 +00:00
|
|
|
#include "nsThreadUtils.h"
|
2012-01-29 20:39:30 +00:00
|
|
|
#include "nsIThreadManager.h"
|
2013-03-01 08:38:47 +00:00
|
|
|
#include "mozilla/dom/mobilemessage/PSms.h"
|
2013-10-15 03:23:20 +00:00
|
|
|
#include "gfxPlatform.h"
|
2012-02-04 06:48:26 +00:00
|
|
|
#include "gfxContext.h"
|
2013-10-15 03:23:20 +00:00
|
|
|
#include "mozilla/gfx/2D.h"
|
2013-07-24 13:18:05 +00:00
|
|
|
#include "gfxUtils.h"
|
2012-02-04 06:48:26 +00:00
|
|
|
#include "nsPresContext.h"
|
|
|
|
#include "nsIDocShell.h"
|
|
|
|
#include "nsPIDOMWindow.h"
|
2012-03-20 13:09:45 +00:00
|
|
|
#include "mozilla/dom/ScreenOrientation.h"
|
2012-06-02 03:50:57 +00:00
|
|
|
#include "nsIDOMWindowUtils.h"
|
|
|
|
#include "nsIDOMClientRect.h"
|
2012-11-06 21:32:07 +00:00
|
|
|
#include "mozilla/ClearOnShutdown.h"
|
2013-04-26 17:26:46 +00:00
|
|
|
#include "nsPrintfCString.h"
|
2014-04-04 16:33:49 +00:00
|
|
|
#include "NativeJSContainer.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsIScriptError.h"
|
2014-05-06 05:33:29 +00:00
|
|
|
#include "nsIHttpChannel.h"
|
2014-11-13 18:47:24 +00:00
|
|
|
|
|
|
|
#include "MediaCodec.h"
|
|
|
|
#include "SurfaceTexture.h"
|
2015-04-11 02:14:00 +00:00
|
|
|
#include "GLContextProvider.h"
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2016-02-10 23:54:55 +00:00
|
|
|
#include "mozilla/TimeStamp.h"
|
|
|
|
#include "mozilla/UniquePtr.h"
|
2015-09-15 18:01:07 +00:00
|
|
|
#include "mozilla/dom/ContentChild.h"
|
2016-04-18 10:48:19 +00:00
|
|
|
#include "nsIObserverService.h"
|
2016-09-09 01:49:25 +00:00
|
|
|
#include "nsISupportsPrimitives.h"
|
2016-06-21 20:23:58 +00:00
|
|
|
#include "MediaPrefs.h"
|
2016-10-03 16:26:00 +00:00
|
|
|
#include "WidgetUtils.h"
|
2015-09-15 18:01:07 +00:00
|
|
|
|
2016-09-16 19:13:48 +00:00
|
|
|
#include "FennecJNIWrappers.h"
|
|
|
|
|
2010-06-03 20:56:36 +00:00
|
|
|
using namespace mozilla;
|
2013-10-15 03:23:20 +00:00
|
|
|
using namespace mozilla::gfx;
|
2015-01-10 00:33:57 +00:00
|
|
|
using namespace mozilla::jni;
|
2016-07-21 17:49:04 +00:00
|
|
|
using namespace mozilla::java;
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2015-02-18 21:50:31 +00:00
|
|
|
AndroidBridge* AndroidBridge::sBridge = nullptr;
|
2013-09-25 06:06:21 +00:00
|
|
|
static jobject sGlobalContext = nullptr;
|
2015-09-15 18:01:07 +00:00
|
|
|
nsDataHashtable<nsStringHashKey, nsString> AndroidBridge::sStoragePaths;
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2013-09-09 12:57:36 +00:00
|
|
|
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\", "
|
2013-11-19 01:30:00 +00:00
|
|
|
"methodType=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
|
|
|
|
methodName, methodType);
|
2013-09-09 12:57:36 +00:00
|
|
|
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\", "
|
2013-11-19 01:30:00 +00:00
|
|
|
"methodType=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
|
|
|
|
methodName, methodType);
|
2013-09-09 12:57:36 +00:00
|
|
|
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\", "
|
2013-11-19 01:30:00 +00:00
|
|
|
"fieldType=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
|
|
|
|
fieldName, fieldType);
|
2013-09-09 12:57:36 +00:00
|
|
|
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\", "
|
2013-11-19 01:30:00 +00:00
|
|
|
"fieldType=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
|
|
|
|
fieldName, fieldType);
|
2013-09-09 12:57:36 +00:00
|
|
|
env->ExceptionDescribe();
|
|
|
|
MOZ_CRASH();
|
|
|
|
}
|
|
|
|
return fieldID;
|
|
|
|
}
|
|
|
|
|
2012-07-31 21:34:06 +00:00
|
|
|
void
|
2015-08-13 04:53:39 +00:00
|
|
|
AndroidBridge::ConstructBridge()
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
|
|
|
/* 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.
|
|
|
|
*/
|
2012-07-02 19:32:34 +00:00
|
|
|
putenv("NSS_DISABLE_UNLOAD=1");
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2015-02-18 21:50:31 +00:00
|
|
|
MOZ_ASSERT(!sBridge);
|
2015-08-13 04:53:39 +00:00
|
|
|
sBridge = new AndroidBridge();
|
2015-04-28 00:52:52 +00:00
|
|
|
|
2016-06-21 20:23:58 +00:00
|
|
|
MediaPrefs::GetSingleton();
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 21:50:31 +00:00
|
|
|
void
|
2015-08-13 04:53:39 +00:00
|
|
|
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()
|
2016-02-10 23:54:55 +00:00
|
|
|
: mLayerClient(nullptr)
|
|
|
|
, mUiTaskQueueLock("UiTaskQueue")
|
2010-06-03 20:56:36 +00:00
|
|
|
{
|
2011-12-06 06:56:04 +00:00
|
|
|
ALOG_BRIDGE("AndroidBridge::Init");
|
2010-06-03 20:56:36 +00:00
|
|
|
|
2015-08-13 04:53:39 +00:00
|
|
|
JNIEnv* const jEnv = jni::GetGeckoThreadEnv();
|
2012-05-04 15:08:47 +00:00
|
|
|
AutoLocalJNIFrame jniFrame(jEnv);
|
2012-04-27 20:04:47 +00:00
|
|
|
|
2016-07-21 17:49:04 +00:00
|
|
|
mMessageQueue = java::GeckoThread::MsgQueue();
|
2016-02-09 22:27:28 +00:00
|
|
|
auto msgQueueClass = Class::LocalRef::Adopt(
|
2015-08-13 04:53:39 +00:00
|
|
|
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;");
|
|
|
|
|
2013-05-29 04:52:40 +00:00
|
|
|
#ifdef MOZ_WEBSMS_BACKEND
|
2015-01-10 00:33:56 +00:00
|
|
|
AutoJNIClass smsMessage(jEnv, "android/telephony/SmsMessage");
|
|
|
|
mAndroidSmsMessageClass = smsMessage.getGlobalRef();
|
|
|
|
jCalculateLength = smsMessage.getStaticMethod("calculateLength", "(Ljava/lang/CharSequence;Z)[I");
|
2013-05-29 04:52:40 +00:00
|
|
|
#endif
|
2013-01-04 06:26:27 +00:00
|
|
|
|
2015-01-10 00:33:56 +00:00
|
|
|
AutoJNIClass string(jEnv, "java/lang/String");
|
|
|
|
jStringClass = string.getGlobalRef();
|
2013-09-09 12:57:36 +00:00
|
|
|
|
|
|
|
if (!GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &mAPIVersion, jEnv)) {
|
2012-04-27 20:04:47 +00:00
|
|
|
ALOG_BRIDGE("Failed to find API version");
|
2013-09-09 12:57:36 +00:00
|
|
|
}
|
2012-04-27 20:04:47 +00:00
|
|
|
|
2015-01-10 00:33:56 +00:00
|
|
|
AutoJNIClass channels(jEnv, "java/nio/channels/Channels");
|
|
|
|
jChannels = channels.getGlobalRef();
|
|
|
|
jChannelCreate = channels.getStaticMethod("newChannel", "(Ljava/io/InputStream;)Ljava/nio/channels/ReadableByteChannel;");
|
2014-06-04 19:28:04 +00:00
|
|
|
|
2015-01-10 00:33:56 +00:00
|
|
|
AutoJNIClass readableByteChannel(jEnv, "java/nio/channels/ReadableByteChannel");
|
|
|
|
jReadableByteChannel = readableByteChannel.getGlobalRef();
|
|
|
|
jByteBufferRead = readableByteChannel.getMethod("read", "(Ljava/nio/ByteBuffer;)I");
|
2014-06-04 19:28:04 +00:00
|
|
|
|
2015-01-10 00:33:56 +00:00
|
|
|
AutoJNIClass inputStream(jEnv, "java/io/InputStream");
|
|
|
|
jInputStream = inputStream.getGlobalRef();
|
|
|
|
jClose = inputStream.getMethod("close", "()V");
|
|
|
|
jAvailable = inputStream.getMethod("available", "()I");
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2013-09-09 12:57:37 +00:00
|
|
|
// Raw JNIEnv variants.
|
2014-01-04 15:02:17 +00:00
|
|
|
jstring AndroidBridge::NewJavaString(JNIEnv* env, const char16_t* string, uint32_t len) {
|
2013-10-08 18:00:40 +00:00
|
|
|
jstring ret = env->NewString(reinterpret_cast<const jchar*>(string), len);
|
2013-09-09 12:57:37 +00:00
|
|
|
if (env->ExceptionCheck()) {
|
|
|
|
ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
|
|
|
|
env->ExceptionDescribe();
|
|
|
|
env->ExceptionClear();
|
2013-10-10 20:42:52 +00:00
|
|
|
return nullptr;
|
2013-09-09 12:57:37 +00:00
|
|
|
}
|
2012-09-05 04:23:02 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-09-09 12:57:37 +00:00
|
|
|
jstring AndroidBridge::NewJavaString(JNIEnv* env, const nsAString& string) {
|
|
|
|
return NewJavaString(env, string.BeginReading(), string.Length());
|
2011-03-02 17:23:02 +00:00
|
|
|
}
|
|
|
|
|
2013-09-09 12:57:37 +00:00
|
|
|
jstring AndroidBridge::NewJavaString(JNIEnv* env, const char* string) {
|
|
|
|
return NewJavaString(env, NS_ConvertUTF8toUTF16(string));
|
2010-06-04 21:14:43 +00:00
|
|
|
}
|
|
|
|
|
2013-09-09 12:57:37 +00:00
|
|
|
jstring AndroidBridge::NewJavaString(JNIEnv* env, const nsACString& string) {
|
|
|
|
return NewJavaString(env, NS_ConvertUTF8toUTF16(string));
|
2012-03-21 17:52:35 +00:00
|
|
|
}
|
|
|
|
|
2013-09-09 12:57:37 +00:00
|
|
|
// AutoLocalJNIFrame variants..
|
2014-01-04 15:02:17 +00:00
|
|
|
jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const char16_t* string, uint32_t len) {
|
2013-09-09 12:57:37 +00:00
|
|
|
return NewJavaString(frame->GetEnv(), string, len);
|
2012-02-05 19:51:05 +00:00
|
|
|
}
|
|
|
|
|
2013-09-09 12:57:37 +00:00
|
|
|
jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const nsAString& string) {
|
|
|
|
return NewJavaString(frame, string.BeginReading(), string.Length());
|
2012-02-05 19:51:05 +00:00
|
|
|
}
|
|
|
|
|
2013-09-09 12:57:37 +00:00
|
|
|
jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const char* string) {
|
|
|
|
return NewJavaString(frame, NS_ConvertUTF8toUTF16(string));
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2013-09-09 12:57:37 +00:00
|
|
|
jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const nsACString& string) {
|
|
|
|
return NewJavaString(frame, NS_ConvertUTF8toUTF16(string));
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2012-07-02 19:32:34 +00:00
|
|
|
static void
|
2010-09-30 15:37:36 +00:00
|
|
|
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) {
|
2014-01-06 17:54:22 +00:00
|
|
|
|
|
|
|
AutoLocalJNIFrame jniFrame(aJNIEnv, 4);
|
2012-07-02 19:32:34 +00:00
|
|
|
nsJNIString name(
|
2012-04-16 22:31:05 +00:00
|
|
|
static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i)), aJNIEnv);
|
2010-09-30 15:37:36 +00:00
|
|
|
nsJNIString isDefault(
|
2012-04-16 22:31:05 +00:00
|
|
|
static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i + 1)), aJNIEnv);
|
2012-07-02 19:32:34 +00:00
|
|
|
nsJNIString packageName(
|
2012-04-16 22:31:05 +00:00
|
|
|
static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i + 2)), aJNIEnv);
|
2012-07-02 19:32:34 +00:00
|
|
|
nsJNIString className(
|
2012-04-16 22:31:05 +00:00
|
|
|
static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i + 3)), aJNIEnv);
|
2010-09-30 15:37:36 +00:00
|
|
|
nsIHandlerApp* app = nsOSHelperAppService::
|
|
|
|
CreateAndroidHandlerApp(name, className, packageName,
|
|
|
|
className, aMimeType, aAction);
|
2012-07-02 19:32:34 +00:00
|
|
|
|
2011-10-17 14:59:28 +00:00
|
|
|
aHandlersArray->AppendElement(app, false);
|
2010-09-30 15:37:36 +00:00
|
|
|
if (aDefaultApp && isDefault.Length() > 0)
|
|
|
|
*aDefaultApp = app;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-09-09 12:57:36 +00:00
|
|
|
AndroidBridge::GetHandlersForMimeType(const nsAString& aMimeType,
|
2010-09-30 15:37:36 +00:00
|
|
|
nsIMutableArray *aHandlersArray,
|
|
|
|
nsIHandlerApp **aDefaultApp,
|
|
|
|
const nsAString& aAction)
|
2010-06-14 19:04:16 +00:00
|
|
|
{
|
2011-03-01 04:25:11 +00:00
|
|
|
ALOG_BRIDGE("AndroidBridge::GetHandlersForMimeType");
|
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
auto arr = GeckoAppShell::GetHandlersForMimeType(aMimeType, aAction);
|
2010-06-15 23:39:43 +00:00
|
|
|
if (!arr)
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-06-30 02:22:08 +00:00
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
JNIEnv* const env = arr.Env();
|
|
|
|
jsize len = env->GetArrayLength(arr.Get());
|
2010-06-30 02:22:08 +00:00
|
|
|
|
2010-09-30 15:37:36 +00:00
|
|
|
if (!aHandlersArray)
|
2010-06-30 02:22:08 +00:00
|
|
|
return len > 0;
|
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
getHandlersFromStringArray(env, arr.Get(), len, aHandlersArray,
|
2010-09-30 15:37:36 +00:00
|
|
|
aDefaultApp, aAction,
|
2013-09-09 12:57:36 +00:00
|
|
|
NS_ConvertUTF16toUTF8(aMimeType));
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2010-06-30 02:22:08 +00:00
|
|
|
}
|
|
|
|
|
2015-07-24 19:45:55 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-09-09 12:57:36 +00:00
|
|
|
AndroidBridge::GetHandlersForURL(const nsAString& aURL,
|
2011-09-30 07:00:48 +00:00
|
|
|
nsIMutableArray* aHandlersArray,
|
|
|
|
nsIHandlerApp **aDefaultApp,
|
|
|
|
const nsAString& aAction)
|
2010-06-30 02:22:08 +00:00
|
|
|
{
|
2011-03-01 04:25:11 +00:00
|
|
|
ALOG_BRIDGE("AndroidBridge::GetHandlersForURL");
|
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
auto arr = GeckoAppShell::GetHandlersForURL(aURL, aAction);
|
2010-06-30 02:22:08 +00:00
|
|
|
if (!arr)
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-06-30 02:22:08 +00:00
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
JNIEnv* const env = arr.Env();
|
|
|
|
jsize len = env->GetArrayLength(arr.Get());
|
2010-06-30 02:22:08 +00:00
|
|
|
|
2010-09-30 15:37:36 +00:00
|
|
|
if (!aHandlersArray)
|
2010-06-30 02:22:08 +00:00
|
|
|
return len > 0;
|
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
getHandlersFromStringArray(env, arr.Get(), len, aHandlersArray,
|
2010-09-30 15:37:36 +00:00
|
|
|
aDefaultApp, aAction);
|
2013-09-09 12:57:37 +00:00
|
|
|
return true;
|
2010-06-14 19:04:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-03-01 04:25:11 +00:00
|
|
|
AndroidBridge::GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType)
|
|
|
|
{
|
|
|
|
ALOG_BRIDGE("AndroidBridge::GetMimeTypeFromExtensions");
|
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
auto jstrType = GeckoAppShell::GetMimeTypeFromExtensions(aFileExt);
|
2012-01-29 20:39:30 +00:00
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
if (jstrType) {
|
2016-02-09 22:27:28 +00:00
|
|
|
aMimeType = jstrType->ToCString();
|
2013-09-09 12:57:37 +00:00
|
|
|
}
|
2010-06-14 19:04:16 +00:00
|
|
|
}
|
|
|
|
|
2011-03-08 05:45:43 +00:00
|
|
|
void
|
2011-09-15 07:40:17 +00:00
|
|
|
AndroidBridge::GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt)
|
2011-03-08 05:45:43 +00:00
|
|
|
{
|
|
|
|
ALOG_BRIDGE("AndroidBridge::GetExtensionFromMimeType");
|
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
auto jstrExt = GeckoAppShell::GetExtensionFromMimeType(aMimeType);
|
2012-01-29 20:39:30 +00:00
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
if (jstrExt) {
|
2016-02-09 22:27:28 +00:00
|
|
|
aFileExt = jstrExt->ToCString();
|
2013-09-09 12:57:37 +00:00
|
|
|
}
|
2010-06-16 17:20:54 +00:00
|
|
|
}
|
|
|
|
|
2010-08-26 23:43:23 +00:00
|
|
|
bool
|
|
|
|
AndroidBridge::GetClipboardText(nsAString& aText)
|
|
|
|
{
|
2011-03-01 04:25:11 +00:00
|
|
|
ALOG_BRIDGE("AndroidBridge::GetClipboardText");
|
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
auto text = Clipboard::GetText();
|
2012-01-29 20:39:30 +00:00
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
if (text) {
|
2016-02-09 22:27:28 +00:00
|
|
|
aText = text->ToString();
|
2015-01-10 00:33:57 +00:00
|
|
|
}
|
|
|
|
return !!text;
|
2010-08-26 23:43:23 +00:00
|
|
|
}
|
|
|
|
|
2010-10-07 17:28:27 +00:00
|
|
|
int
|
|
|
|
AndroidBridge::GetDPI()
|
|
|
|
{
|
2012-09-28 19:05:50 +00:00
|
|
|
static int sDPI = 0;
|
|
|
|
if (sDPI)
|
|
|
|
return sDPI;
|
|
|
|
|
|
|
|
const int DEFAULT_DPI = 160;
|
2012-01-29 20:39:30 +00:00
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
sDPI = GeckoAppShell::GetDpi();
|
2013-09-09 12:57:37 +00:00
|
|
|
if (!sDPI) {
|
2012-05-04 15:08:47 +00:00
|
|
|
return DEFAULT_DPI;
|
2012-09-28 19:05:50 +00:00
|
|
|
}
|
2012-05-04 15:08:47 +00:00
|
|
|
|
2012-09-28 19:05:50 +00:00
|
|
|
return sDPI;
|
2010-10-07 17:28:27 +00:00
|
|
|
}
|
|
|
|
|
2013-07-04 13:53:25 +00:00
|
|
|
int
|
|
|
|
AndroidBridge::GetScreenDepth()
|
|
|
|
{
|
2013-09-09 12:57:37 +00:00
|
|
|
ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
|
|
|
|
|
2013-07-04 13:53:25 +00:00
|
|
|
static int sDepth = 0;
|
|
|
|
if (sDepth)
|
|
|
|
return sDepth;
|
|
|
|
|
|
|
|
const int DEFAULT_DEPTH = 16;
|
|
|
|
|
2015-08-13 04:53:39 +00:00
|
|
|
if (jni::IsAvailable()) {
|
2016-08-13 03:15:52 +00:00
|
|
|
sDepth = GeckoAppShell::GetScreenDepth();
|
2014-01-18 05:32:24 +00:00
|
|
|
}
|
2013-09-09 12:57:37 +00:00
|
|
|
if (!sDepth)
|
2013-07-04 13:53:25 +00:00
|
|
|
return DEFAULT_DEPTH;
|
|
|
|
|
|
|
|
return sDepth;
|
|
|
|
}
|
2010-11-22 16:38:02 +00:00
|
|
|
void
|
2013-09-09 12:57:37 +00:00
|
|
|
AndroidBridge::Vibrate(const nsTArray<uint32_t>& aPattern)
|
2010-11-22 16:38:02 +00:00
|
|
|
{
|
2013-09-09 12:57:37 +00:00
|
|
|
ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
|
2012-01-29 20:39:30 +00:00
|
|
|
|
2013-09-09 12:57:37 +00:00
|
|
|
uint32_t len = aPattern.Length();
|
|
|
|
if (!len) {
|
|
|
|
ALOG_BRIDGE(" invalid 0-length array");
|
2012-01-29 20:39:30 +00:00
|
|
|
return;
|
2013-09-09 12:57:37 +00:00
|
|
|
}
|
2012-01-29 20:39:30 +00:00
|
|
|
|
2011-09-30 07:00:48 +00:00
|
|
|
// 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;
|
|
|
|
}
|
2016-08-13 03:15:52 +00:00
|
|
|
GeckoAppShell::Vibrate(d);
|
2012-05-04 15:08:45 +00:00
|
|
|
return;
|
2011-09-30 07:00:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// First element of the array vibrate() expects is how long to wait
|
|
|
|
// *before* vibrating. For us, this is always 0.
|
|
|
|
|
2015-08-13 04:53:39 +00:00
|
|
|
JNIEnv* const env = jni::GetGeckoThreadEnv();
|
2015-01-10 00:33:57 +00:00
|
|
|
AutoLocalJNIFrame jniFrame(env, 1);
|
|
|
|
|
2012-01-29 20:39:30 +00:00
|
|
|
jlongArray array = env->NewLongArray(len + 1);
|
2011-09-30 07:00:48 +00:00
|
|
|
if (!array) {
|
|
|
|
ALOG_BRIDGE(" failed to allocate array");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
jlong* elts = env->GetLongArrayElements(array, nullptr);
|
2011-09-30 07:00:48 +00:00
|
|
|
elts[0] = 0;
|
2012-08-22 15:56:38 +00:00
|
|
|
for (uint32_t i = 0; i < aPattern.Length(); ++i) {
|
2011-09-30 07:00:48 +00:00
|
|
|
jlong d = aPattern[i];
|
|
|
|
if (d < 0) {
|
|
|
|
ALOG_BRIDGE(" invalid vibration duration < 0");
|
2012-01-29 20:39:30 +00:00
|
|
|
env->ReleaseLongArrayElements(array, elts, JNI_ABORT);
|
2011-09-30 07:00:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
elts[i + 1] = d;
|
|
|
|
}
|
2012-01-29 20:39:30 +00:00
|
|
|
env->ReleaseLongArrayElements(array, elts, 0);
|
2011-09-30 07:00:48 +00:00
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
GeckoAppShell::Vibrate(LongArray::Ref::From(array), -1 /* don't repeat */);
|
2011-02-27 15:50:56 +00:00
|
|
|
}
|
|
|
|
|
2011-03-30 18:04:41 +00:00
|
|
|
void
|
|
|
|
AndroidBridge::GetSystemColors(AndroidSystemColors *aColors)
|
|
|
|
{
|
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
NS_ASSERTION(aColors != nullptr, "AndroidBridge::GetSystemColors: aColors is null!");
|
2011-03-30 18:04:41 +00:00
|
|
|
if (!aColors)
|
|
|
|
return;
|
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
auto arr = GeckoAppShell::GetSystemColors();
|
2011-03-30 18:04:41 +00:00
|
|
|
if (!arr)
|
|
|
|
return;
|
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
JNIEnv* const env = arr.Env();
|
|
|
|
uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr.Get()));
|
|
|
|
jint *elements = env->GetIntArrayElements(arr.Get(), 0);
|
2011-03-30 18:04:41 +00:00
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t colorsCount = sizeof(AndroidSystemColors) / sizeof(nscolor);
|
2011-03-30 18:04:41 +00:00
|
|
|
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;
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
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);
|
2012-07-12 16:52:52 +00:00
|
|
|
colors[i] = (androidColor & 0xff00ff00) | (b << 16) | r;
|
2011-03-30 18:04:41 +00:00
|
|
|
}
|
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
env->ReleaseIntArrayElements(arr.Get(), elements, 0);
|
2011-03-30 18:04:41 +00:00
|
|
|
}
|
|
|
|
|
2011-06-13 21:02:13 +00:00
|
|
|
void
|
2012-08-22 15:56:38 +00:00
|
|
|
AndroidBridge::GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize, uint8_t * const aBuf)
|
2011-06-13 21:02:13 +00:00
|
|
|
{
|
|
|
|
ALOG_BRIDGE("AndroidBridge::GetIconForExtension");
|
2012-07-30 14:20:58 +00:00
|
|
|
NS_ASSERTION(aBuf != nullptr, "AndroidBridge::GetIconForExtension: aBuf is null!");
|
2011-06-13 21:02:13 +00:00
|
|
|
if (!aBuf)
|
|
|
|
return;
|
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
auto arr = GeckoAppShell::GetIconForExtension(NS_ConvertUTF8toUTF16(aFileExt), aIconSize);
|
2012-05-04 15:08:47 +00:00
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
NS_ASSERTION(arr != nullptr, "AndroidBridge::GetIconForExtension: Returned pixels array is null!");
|
2011-06-13 21:02:13 +00:00
|
|
|
if (!arr)
|
|
|
|
return;
|
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
JNIEnv* const env = arr.Env();
|
|
|
|
uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr.Get()));
|
|
|
|
jbyte *elements = env->GetByteArrayElements(arr.Get(), 0);
|
2011-06-13 21:02:13 +00:00
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t bufSize = aIconSize * aIconSize * 4;
|
2011-06-13 21:02:13 +00:00
|
|
|
NS_ASSERTION(len == bufSize, "AndroidBridge::GetIconForExtension: Pixels array is incomplete!");
|
|
|
|
if (len == bufSize)
|
|
|
|
memcpy(aBuf, elements, bufSize);
|
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
env->ReleaseByteArrayElements(arr.Get(), elements, 0);
|
2011-06-13 21:02:13 +00:00
|
|
|
}
|
|
|
|
|
2010-06-03 20:56:36 +00:00
|
|
|
void
|
2015-01-10 00:33:57 +00:00
|
|
|
AndroidBridge::SetLayerClient(GeckoLayerClient::Param jobj)
|
2012-02-17 14:16:14 +00:00
|
|
|
{
|
2015-01-10 00:33:57 +00:00
|
|
|
mLayerClient = jobj;
|
2010-06-03 20:56:36 +00:00
|
|
|
}
|
|
|
|
|
2011-02-28 16:32:05 +00:00
|
|
|
bool
|
2013-09-09 12:57:36 +00:00
|
|
|
AndroidBridge::GetStaticIntField(const char *className, const char *fieldName, int32_t* aInt, JNIEnv* jEnv /* = nullptr */)
|
2011-02-28 16:32:05 +00:00
|
|
|
{
|
2011-03-01 04:25:11 +00:00
|
|
|
ALOG_BRIDGE("AndroidBridge::GetStaticIntField %s", fieldName);
|
2012-04-27 20:04:47 +00:00
|
|
|
|
2013-09-09 12:57:36 +00:00
|
|
|
if (!jEnv) {
|
2015-08-13 04:53:39 +00:00
|
|
|
if (!jni::IsAvailable()) {
|
2014-01-18 05:32:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-08-13 04:53:39 +00:00
|
|
|
jEnv = jni::GetGeckoThreadEnv();
|
2012-04-27 20:04:47 +00:00
|
|
|
}
|
2012-01-29 20:39:30 +00:00
|
|
|
|
2015-01-10 00:33:56 +00:00
|
|
|
AutoJNIClass cls(jEnv, className);
|
|
|
|
jfieldID field = cls.getStaticField(fieldName, "I");
|
2011-02-28 16:32:05 +00:00
|
|
|
|
2013-09-09 12:57:36 +00:00
|
|
|
if (!field) {
|
2011-02-28 16:32:05 +00:00
|
|
|
return false;
|
2013-09-09 12:57:36 +00:00
|
|
|
}
|
2011-02-28 16:32:05 +00:00
|
|
|
|
2015-01-10 00:33:56 +00:00
|
|
|
*aInt = static_cast<int32_t>(jEnv->GetStaticIntField(cls.getRawRef(), field));
|
2011-02-28 16:32:05 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-09-11 13:20:20 +00:00
|
|
|
bool
|
2013-09-09 12:57:36 +00:00
|
|
|
AndroidBridge::GetStaticStringField(const char *className, const char *fieldName, nsAString &result, JNIEnv* jEnv /* = nullptr */)
|
2010-09-11 13:20:20 +00:00
|
|
|
{
|
2012-05-04 15:08:47 +00:00
|
|
|
ALOG_BRIDGE("AndroidBridge::GetStaticStringField %s", fieldName);
|
2011-03-01 04:25:11 +00:00
|
|
|
|
2013-09-09 12:57:36 +00:00
|
|
|
if (!jEnv) {
|
2015-08-13 04:53:39 +00:00
|
|
|
if (!jni::IsAvailable()) {
|
2014-01-18 05:32:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-08-13 04:53:39 +00:00
|
|
|
jEnv = jni::GetGeckoThreadEnv();
|
2012-04-27 20:04:47 +00:00
|
|
|
}
|
2012-01-29 20:39:30 +00:00
|
|
|
|
2014-01-06 17:54:22 +00:00
|
|
|
AutoLocalJNIFrame jniFrame(jEnv, 1);
|
2015-01-10 00:33:56 +00:00
|
|
|
AutoJNIClass cls(jEnv, className);
|
|
|
|
jfieldID field = cls.getStaticField(fieldName, "Ljava/lang/String;");
|
2010-09-11 13:20:20 +00:00
|
|
|
|
2013-09-09 12:57:36 +00:00
|
|
|
if (!field) {
|
2010-09-11 13:20:20 +00:00
|
|
|
return false;
|
2013-09-09 12:57:36 +00:00
|
|
|
}
|
2010-09-11 13:20:20 +00:00
|
|
|
|
2015-01-10 00:33:56 +00:00
|
|
|
jstring jstr = (jstring) jEnv->GetStaticObjectField(cls.getRawRef(), field);
|
2010-09-11 13:20:20 +00:00
|
|
|
if (!jstr)
|
|
|
|
return false;
|
|
|
|
|
2013-09-09 12:57:36 +00:00
|
|
|
result.Assign(nsJNIString(jstr, jEnv));
|
2010-09-11 13:20:20 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-08-04 07:32:57 +00:00
|
|
|
namespace mozilla {
|
2016-04-26 00:23:21 +00:00
|
|
|
class TracerRunnable : public Runnable{
|
2011-08-04 07:32:57 +00:00
|
|
|
public:
|
|
|
|
TracerRunnable() {
|
|
|
|
mTracerLock = new Mutex("TracerRunnable");
|
|
|
|
mTracerCondVar = new CondVar(*mTracerLock, "TracerRunnable");
|
|
|
|
mMainThread = do_GetMainThread();
|
2012-07-02 19:32:34 +00:00
|
|
|
|
2011-08-04 07:32:57 +00:00
|
|
|
}
|
|
|
|
~TracerRunnable() {
|
|
|
|
delete mTracerCondVar;
|
|
|
|
delete mTracerLock;
|
2012-07-30 14:20:58 +00:00
|
|
|
mTracerLock = nullptr;
|
|
|
|
mTracerCondVar = nullptr;
|
2011-08-04 07:32:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual nsresult Run() {
|
|
|
|
MutexAutoLock lock(*mTracerLock);
|
|
|
|
if (!AndroidBridge::Bridge())
|
|
|
|
return NS_OK;
|
2012-07-02 19:32:34 +00:00
|
|
|
|
2012-04-04 09:15:10 +00:00
|
|
|
mHasRun = true;
|
2011-08-04 07:32:57 +00:00
|
|
|
mTracerCondVar->Notify();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-07-02 19:32:34 +00:00
|
|
|
|
2011-08-04 07:32:57 +00:00
|
|
|
bool Fire() {
|
|
|
|
if (!mTracerLock || !mTracerCondVar)
|
|
|
|
return false;
|
|
|
|
MutexAutoLock lock(*mTracerLock);
|
2012-04-04 09:15:10 +00:00
|
|
|
mHasRun = false;
|
2011-08-04 07:32:57 +00:00
|
|
|
mMainThread->Dispatch(this, NS_DISPATCH_NORMAL);
|
|
|
|
while (!mHasRun)
|
|
|
|
mTracerCondVar->Wait();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Signal() {
|
|
|
|
MutexAutoLock lock(*mTracerLock);
|
2012-04-04 09:15:10 +00:00
|
|
|
mHasRun = true;
|
2011-08-04 07:32:57 +00:00
|
|
|
mTracerCondVar->Notify();
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
Mutex* mTracerLock;
|
|
|
|
CondVar* mTracerCondVar;
|
2012-04-04 09:15:10 +00:00
|
|
|
bool mHasRun;
|
2011-08-04 07:32:57 +00:00
|
|
|
nsCOMPtr<nsIThread> mMainThread;
|
|
|
|
|
|
|
|
};
|
2013-08-12 14:58:36 +00:00
|
|
|
StaticRefPtr<TracerRunnable> sTracerRunnable;
|
2011-08-04 07:32:57 +00:00
|
|
|
|
|
|
|
bool InitWidgetTracing() {
|
|
|
|
if (!sTracerRunnable)
|
|
|
|
sTracerRunnable = new TracerRunnable();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CleanUpWidgetTracing() {
|
2012-07-30 14:20:58 +00:00
|
|
|
sTracerRunnable = nullptr;
|
2011-08-04 07:32:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool FireAndWaitForTracerEvent() {
|
|
|
|
if (sTracerRunnable)
|
|
|
|
return sTracerRunnable->Fire();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-07-02 19:32:34 +00:00
|
|
|
void SignalTracerThread()
|
|
|
|
{
|
|
|
|
if (sTracerRunnable)
|
|
|
|
return sTracerRunnable->Signal();
|
|
|
|
}
|
2011-08-04 07:32:57 +00:00
|
|
|
|
|
|
|
}
|
2011-06-16 09:03:00 +00:00
|
|
|
|
|
|
|
|
2011-11-02 15:35:11 +00:00
|
|
|
void
|
|
|
|
AndroidBridge::GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
|
|
|
|
{
|
|
|
|
ALOG_BRIDGE("AndroidBridge::GetCurrentBatteryInformation");
|
|
|
|
|
|
|
|
// To prevent calling too many methods through JNI, the Java method returns
|
2011-11-09 08:56:37 +00:00
|
|
|
// an array of double even if we actually want a double and a boolean.
|
2016-08-13 03:15:52 +00:00
|
|
|
auto arr = GeckoAppShell::GetCurrentBatteryInformation();
|
2015-01-10 00:33:57 +00:00
|
|
|
|
|
|
|
JNIEnv* const env = arr.Env();
|
|
|
|
if (!arr || env->GetArrayLength(arr.Get()) != 3) {
|
2011-11-02 15:35:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
jdouble* info = env->GetDoubleArrayElements(arr.Get(), 0);
|
2011-11-02 15:35:11 +00:00
|
|
|
|
|
|
|
aBatteryInfo->level() = info[0];
|
|
|
|
aBatteryInfo->charging() = info[1] == 1.0f;
|
2011-11-09 14:13:37 +00:00
|
|
|
aBatteryInfo->remainingTime() = info[2];
|
2011-11-02 15:35:11 +00:00
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
env->ReleaseDoubleArrayElements(arr.Get(), info, 0);
|
2011-11-02 15:35:11 +00:00
|
|
|
}
|
|
|
|
|
2011-11-15 03:12:14 +00:00
|
|
|
void
|
2014-04-04 16:33:49 +00:00
|
|
|
AndroidBridge::HandleGeckoMessage(JSContext* cx, JS::HandleObject object)
|
2011-11-15 03:12:14 +00:00
|
|
|
{
|
|
|
|
ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
|
2012-01-29 20:39:30 +00:00
|
|
|
|
2016-07-21 17:49:04 +00:00
|
|
|
auto message = widget::CreateNativeJSContainer(cx, object);
|
2016-08-13 03:15:52 +00:00
|
|
|
GeckoAppShell::HandleGeckoMessage(message);
|
2011-11-15 03:12:14 +00:00
|
|
|
}
|
|
|
|
|
2013-01-04 06:26:27 +00:00
|
|
|
nsresult
|
|
|
|
AndroidBridge::GetSegmentInfoForText(const nsAString& aText,
|
2013-08-09 13:25:53 +00:00
|
|
|
nsIMobileMessageCallback* aRequest)
|
2011-11-25 09:48:51 +00:00
|
|
|
{
|
2013-05-29 04:52:40 +00:00
|
|
|
#ifndef MOZ_WEBSMS_BACKEND
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
#else
|
2013-01-04 06:26:27 +00:00
|
|
|
ALOG_BRIDGE("AndroidBridge::GetSegmentInfoForText");
|
|
|
|
|
2014-08-04 09:01:36 +00:00
|
|
|
int32_t segments, charsPerSegment, charsAvailableInLastSegment;
|
2011-11-25 09:48:51 +00:00
|
|
|
|
2015-08-13 04:53:39 +00:00
|
|
|
JNIEnv* const env = jni::GetGeckoThreadEnv();
|
2012-01-29 20:39:30 +00:00
|
|
|
|
2014-01-06 17:54:22 +00:00
|
|
|
AutoLocalJNIFrame jniFrame(env, 2);
|
2012-12-13 22:03:44 +00:00
|
|
|
jstring jText = NewJavaString(&jniFrame, aText);
|
2013-01-04 06:26:27 +00:00
|
|
|
jobject obj = env->CallStaticObjectMethod(mAndroidSmsMessageClass,
|
|
|
|
jCalculateLength, jText, JNI_FALSE);
|
2012-05-04 15:08:47 +00:00
|
|
|
if (jniFrame.CheckForException())
|
2013-01-04 06:26:27 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
2012-05-04 15:08:47 +00:00
|
|
|
|
2013-01-04 06:26:27 +00:00
|
|
|
jintArray arr = static_cast<jintArray>(obj);
|
|
|
|
if (!arr || env->GetArrayLength(arr) != 4)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
jint* info = env->GetIntArrayElements(arr, JNI_FALSE);
|
|
|
|
|
2014-08-04 09:01:36 +00:00
|
|
|
segments = info[0]; // msgCount
|
|
|
|
charsPerSegment = info[2]; // codeUnitsRemaining
|
2013-01-04 06:26:27 +00:00
|
|
|
// segmentChars = (codeUnitCount + codeUnitsRemaining) / msgCount
|
2014-08-04 09:01:36 +00:00
|
|
|
charsAvailableInLastSegment = (info[1] + info[2]) / info[0];
|
2013-01-04 06:26:27 +00:00
|
|
|
|
|
|
|
env->ReleaseIntArrayElements(arr, info, JNI_ABORT);
|
2013-08-09 13:25:53 +00:00
|
|
|
|
|
|
|
// TODO Bug 908598 - Should properly use |QueueSmsRequest(...)| to queue up
|
|
|
|
// the nsIMobileMessageCallback just like other functions.
|
2014-08-04 09:01:36 +00:00
|
|
|
return aRequest->NotifySegmentInfoForTextGot(segments,
|
|
|
|
charsPerSegment,
|
|
|
|
charsAvailableInLastSegment);
|
2013-05-29 04:52:40 +00:00
|
|
|
#endif
|
2011-11-25 09:48:51 +00:00
|
|
|
}
|
|
|
|
|
2011-11-20 23:00:46 +00:00
|
|
|
void
|
2013-03-09 07:22:02 +00:00
|
|
|
AndroidBridge::SendMessage(const nsAString& aNumber,
|
|
|
|
const nsAString& aMessage,
|
|
|
|
nsIMobileMessageCallback* aRequest)
|
2011-11-20 23:00:46 +00:00
|
|
|
{
|
|
|
|
ALOG_BRIDGE("AndroidBridge::SendMessage");
|
|
|
|
|
2013-01-25 19:00:00 +00:00
|
|
|
uint32_t requestId;
|
|
|
|
if (!QueueSmsRequest(aRequest, &requestId))
|
|
|
|
return;
|
2012-11-06 21:32:07 +00:00
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
GeckoAppShell::SendMessage(aNumber, aMessage, requestId);
|
2011-11-20 23:00:46 +00:00
|
|
|
}
|
|
|
|
|
2011-12-22 22:08:58 +00:00
|
|
|
void
|
2013-03-09 07:22:02 +00:00
|
|
|
AndroidBridge::GetMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest)
|
2011-12-22 22:08:58 +00:00
|
|
|
{
|
|
|
|
ALOG_BRIDGE("AndroidBridge::GetMessage");
|
|
|
|
|
2013-01-25 19:00:00 +00:00
|
|
|
uint32_t requestId;
|
|
|
|
if (!QueueSmsRequest(aRequest, &requestId))
|
|
|
|
return;
|
2012-11-06 21:32:07 +00:00
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
GeckoAppShell::GetMessage(aMessageId, requestId);
|
2011-12-22 22:08:58 +00:00
|
|
|
}
|
|
|
|
|
2011-12-22 22:15:28 +00:00
|
|
|
void
|
2013-03-09 07:22:02 +00:00
|
|
|
AndroidBridge::DeleteMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest)
|
2011-12-22 22:15:28 +00:00
|
|
|
{
|
|
|
|
ALOG_BRIDGE("AndroidBridge::DeleteMessage");
|
|
|
|
|
2013-01-25 19:00:00 +00:00
|
|
|
uint32_t requestId;
|
|
|
|
if (!QueueSmsRequest(aRequest, &requestId))
|
|
|
|
return;
|
2012-11-06 21:32:07 +00:00
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
GeckoAppShell::DeleteMessage(aMessageId, requestId);
|
2011-12-22 22:15:28 +00:00
|
|
|
}
|
|
|
|
|
2015-10-13 04:08:51 +00:00
|
|
|
void
|
|
|
|
AndroidBridge::MarkMessageRead(int32_t aMessageId,
|
|
|
|
bool aValue,
|
|
|
|
bool aSendReadReport,
|
|
|
|
nsIMobileMessageCallback* aRequest)
|
|
|
|
{
|
|
|
|
ALOG_BRIDGE("AndroidBridge::MarkMessageRead");
|
|
|
|
|
|
|
|
uint32_t requestId;
|
|
|
|
if (!QueueSmsRequest(aRequest, &requestId)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
GeckoAppShell::MarkMessageRead(aMessageId,
|
|
|
|
aValue,
|
|
|
|
aSendReadReport,
|
|
|
|
requestId);
|
|
|
|
}
|
|
|
|
|
2015-10-06 22:40:38 +00:00
|
|
|
NS_IMPL_ISUPPORTS0(MessageCursorContinueCallback)
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
MessageCursorContinueCallback::HandleContinue()
|
2015-10-06 22:40:38 +00:00
|
|
|
{
|
2016-08-13 03:15:52 +00:00
|
|
|
GeckoAppShell::GetNextMessage(mRequestId);
|
2015-10-06 22:40:38 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<nsICursorContinueCallback>
|
|
|
|
AndroidBridge::CreateMessageCursor(bool aHasStartDate,
|
|
|
|
uint64_t aStartDate,
|
|
|
|
bool aHasEndDate,
|
|
|
|
uint64_t aEndDate,
|
|
|
|
const char16_t** aNumbers,
|
|
|
|
uint32_t aNumbersCount,
|
|
|
|
const nsAString& aDelivery,
|
|
|
|
bool aHasRead,
|
|
|
|
bool aRead,
|
|
|
|
bool aHasThreadId,
|
|
|
|
uint64_t aThreadId,
|
|
|
|
bool aReverse,
|
|
|
|
nsIMobileMessageCursorCallback* aRequest)
|
|
|
|
{
|
|
|
|
ALOG_BRIDGE("AndroidBridge::CreateMessageCursor");
|
2011-12-20 08:07:25 +00:00
|
|
|
|
2015-08-13 04:53:39 +00:00
|
|
|
JNIEnv* const env = jni::GetGeckoThreadEnv();
|
2012-01-29 20:39:30 +00:00
|
|
|
|
2013-01-25 19:00:00 +00:00
|
|
|
uint32_t requestId;
|
2015-10-06 22:40:38 +00:00
|
|
|
if (!QueueSmsCursorRequest(aRequest, &requestId))
|
|
|
|
return nullptr;
|
2012-11-06 21:32:07 +00:00
|
|
|
|
2014-01-06 17:54:22 +00:00
|
|
|
AutoLocalJNIFrame jniFrame(env, 2);
|
2011-12-20 08:07:25 +00:00
|
|
|
|
|
|
|
jobjectArray numbers =
|
2015-10-06 22:40:38 +00:00
|
|
|
(jobjectArray)env->NewObjectArray(aNumbersCount,
|
2012-07-02 19:32:34 +00:00
|
|
|
jStringClass,
|
2012-12-13 22:03:44 +00:00
|
|
|
NewJavaString(&jniFrame, EmptyString()));
|
2011-12-20 08:07:25 +00:00
|
|
|
|
2015-10-06 22:40:38 +00:00
|
|
|
for (uint32_t i = 0; i < aNumbersCount; ++i) {
|
|
|
|
jstring elem = NewJavaString(&jniFrame, nsDependentString(aNumbers[i]));
|
2014-01-06 17:54:22 +00:00
|
|
|
env->SetObjectArrayElement(numbers, i, elem);
|
|
|
|
env->DeleteLocalRef(elem);
|
2013-09-09 12:57:37 +00:00
|
|
|
}
|
2012-11-06 21:32:07 +00:00
|
|
|
|
2015-10-06 22:40:38 +00:00
|
|
|
int64_t startDate = aHasStartDate ? aStartDate : -1;
|
|
|
|
int64_t endDate = aHasEndDate ? aEndDate : -1;
|
2016-08-13 03:15:52 +00:00
|
|
|
GeckoAppShell::CreateMessageCursor(startDate, endDate,
|
|
|
|
ObjectArray::Ref::From(numbers),
|
|
|
|
aNumbersCount,
|
|
|
|
aDelivery,
|
|
|
|
aHasRead, aRead,
|
|
|
|
aHasThreadId, aThreadId,
|
|
|
|
aReverse,
|
|
|
|
requestId);
|
2015-10-06 22:40:38 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsICursorContinueCallback> callback =
|
|
|
|
new MessageCursorContinueCallback(requestId);
|
|
|
|
return callback.forget();
|
2015-10-06 22:40:38 +00:00
|
|
|
}
|
|
|
|
|
2015-10-06 22:40:38 +00:00
|
|
|
NS_IMPL_ISUPPORTS0(ThreadCursorContinueCallback)
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
ThreadCursorContinueCallback::HandleContinue()
|
|
|
|
{
|
2016-08-13 03:15:52 +00:00
|
|
|
GeckoAppShell::GetNextThread(mRequestId);
|
2015-10-06 22:40:38 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<nsICursorContinueCallback>
|
|
|
|
AndroidBridge::CreateThreadCursor(nsIMobileMessageCursorCallback* aRequest)
|
2012-01-17 18:43:08 +00:00
|
|
|
{
|
2015-10-06 22:40:38 +00:00
|
|
|
ALOG_BRIDGE("AndroidBridge::CreateThreadCursor");
|
2012-01-17 18:43:08 +00:00
|
|
|
|
2013-09-09 12:57:37 +00:00
|
|
|
uint32_t requestId;
|
2015-10-06 22:40:38 +00:00
|
|
|
if (!QueueSmsCursorRequest(aRequest, &requestId)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-10-06 22:40:38 +00:00
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
GeckoAppShell::CreateThreadCursor(requestId);
|
2015-10-06 22:40:38 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsICursorContinueCallback> callback =
|
|
|
|
new ThreadCursorContinueCallback(requestId);
|
|
|
|
return callback.forget();
|
2012-01-17 18:43:08 +00:00
|
|
|
}
|
|
|
|
|
2013-01-25 19:00:00 +00:00
|
|
|
bool
|
2013-03-09 07:22:02 +00:00
|
|
|
AndroidBridge::QueueSmsRequest(nsIMobileMessageCallback* aRequest, uint32_t* aRequestIdOut)
|
2012-11-06 21:32:07 +00:00
|
|
|
{
|
2013-01-25 19:00:00 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
MOZ_ASSERT(aRequest && aRequestIdOut);
|
2012-11-08 16:37:13 +00:00
|
|
|
|
2013-04-08 14:29:34 +00:00
|
|
|
const uint32_t length = mSmsRequests.Length();
|
2013-01-25 19:00:00 +00:00
|
|
|
for (uint32_t i = 0; i < length; i++) {
|
2013-04-08 14:29:34 +00:00
|
|
|
if (!(mSmsRequests)[i]) {
|
|
|
|
(mSmsRequests)[i] = aRequest;
|
2013-01-25 19:00:00 +00:00
|
|
|
*aRequestIdOut = i;
|
|
|
|
return true;
|
2012-11-06 21:32:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-08 14:29:34 +00:00
|
|
|
mSmsRequests.AppendElement(aRequest);
|
2012-11-06 21:32:07 +00:00
|
|
|
|
2013-01-25 19:00:00 +00:00
|
|
|
// After AppendElement(), previous `length` points to the new tail element.
|
|
|
|
*aRequestIdOut = length;
|
|
|
|
return true;
|
2012-11-06 21:32:07 +00:00
|
|
|
}
|
|
|
|
|
2013-03-09 07:22:02 +00:00
|
|
|
already_AddRefed<nsIMobileMessageCallback>
|
2013-01-25 19:00:00 +00:00
|
|
|
AndroidBridge::DequeueSmsRequest(uint32_t aRequestId)
|
2012-11-06 21:32:07 +00:00
|
|
|
{
|
2013-01-25 19:00:00 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
|
2013-04-08 14:29:34 +00:00
|
|
|
MOZ_ASSERT(aRequestId < mSmsRequests.Length());
|
|
|
|
if (aRequestId >= mSmsRequests.Length()) {
|
2012-11-06 21:32:07 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-04-08 14:29:34 +00:00
|
|
|
return mSmsRequests[aRequestId].forget();
|
2012-11-06 21:32:07 +00:00
|
|
|
}
|
|
|
|
|
2015-10-06 22:40:38 +00:00
|
|
|
bool
|
|
|
|
AndroidBridge::QueueSmsCursorRequest(nsIMobileMessageCursorCallback* aRequest,
|
|
|
|
uint32_t* aRequestIdOut)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
MOZ_ASSERT(aRequest && aRequestIdOut);
|
|
|
|
|
|
|
|
const uint32_t length = mSmsCursorRequests.Length();
|
|
|
|
for (uint32_t i = 0; i < length; i++) {
|
|
|
|
if (!(mSmsCursorRequests)[i]) {
|
|
|
|
(mSmsCursorRequests)[i] = aRequest;
|
|
|
|
*aRequestIdOut = i;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mSmsCursorRequests.AppendElement(aRequest);
|
|
|
|
|
|
|
|
// After AppendElement(), previous `length` points to the new tail element.
|
|
|
|
*aRequestIdOut = length;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIMobileMessageCursorCallback>
|
|
|
|
AndroidBridge::GetSmsCursorRequest(uint32_t aRequestId)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
|
|
|
|
MOZ_ASSERT(aRequestId < mSmsCursorRequests.Length());
|
|
|
|
if (aRequestId >= mSmsCursorRequests.Length()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: remove on final dequeue
|
|
|
|
return mSmsCursorRequests[aRequestId];
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<nsIMobileMessageCursorCallback>
|
|
|
|
AndroidBridge::DequeueSmsCursorRequest(uint32_t aRequestId)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
|
|
|
|
MOZ_ASSERT(aRequestId < mSmsCursorRequests.Length());
|
|
|
|
if (aRequestId >= mSmsCursorRequests.Length()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: remove on final dequeue
|
|
|
|
return mSmsCursorRequests[aRequestId].forget();
|
|
|
|
}
|
|
|
|
|
2012-01-16 13:44:07 +00:00
|
|
|
void
|
|
|
|
AndroidBridge::GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
|
|
|
|
{
|
|
|
|
ALOG_BRIDGE("AndroidBridge::GetCurrentNetworkInformation");
|
|
|
|
|
|
|
|
// To prevent calling too many methods through JNI, the Java method returns
|
2014-03-05 09:42:42 +00:00
|
|
|
// an array of double even if we actually want an integer, a boolean, and an integer.
|
2012-05-04 15:08:47 +00:00
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
auto arr = GeckoAppShell::GetCurrentNetworkInformation();
|
2015-01-10 00:33:57 +00:00
|
|
|
|
|
|
|
JNIEnv* const env = arr.Env();
|
|
|
|
if (!arr || env->GetArrayLength(arr.Get()) != 3) {
|
2012-01-16 13:44:07 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
jdouble* info = env->GetDoubleArrayElements(arr.Get(), 0);
|
2012-01-16 13:44:07 +00:00
|
|
|
|
2014-03-05 09:42:42 +00:00
|
|
|
aNetworkInfo->type() = info[0];
|
|
|
|
aNetworkInfo->isWifi() = info[1] == 1.0f;
|
|
|
|
aNetworkInfo->dhcpGateway() = info[2];
|
2012-01-16 13:44:07 +00:00
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
env->ReleaseDoubleArrayElements(arr.Get(), info, 0);
|
2012-01-16 13:44:07 +00:00
|
|
|
}
|
|
|
|
|
2013-05-28 16:49:04 +00:00
|
|
|
jobject
|
|
|
|
AndroidBridge::GetGlobalContextRef() {
|
2015-01-10 00:33:57 +00:00
|
|
|
if (sGlobalContext) {
|
|
|
|
return sGlobalContext;
|
|
|
|
}
|
2013-05-28 16:49:04 +00:00
|
|
|
|
2015-08-13 04:53:39 +00:00
|
|
|
JNIEnv* const env = GetEnvForThread();
|
2015-01-10 00:33:57 +00:00
|
|
|
AutoLocalJNIFrame jniFrame(env, 4);
|
2013-05-28 16:49:04 +00:00
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
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;
|
2013-09-25 06:06:21 +00:00
|
|
|
}
|
2013-02-09 21:38:08 +00:00
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
sGlobalContext = env->NewGlobalRef(appContext);
|
|
|
|
MOZ_ASSERT(sGlobalContext);
|
2013-09-25 06:06:21 +00:00
|
|
|
return sGlobalContext;
|
2013-02-09 21:38:08 +00:00
|
|
|
}
|
|
|
|
|
2012-03-12 15:50:21 +00:00
|
|
|
void
|
2013-06-21 21:03:56 +00:00
|
|
|
AndroidBridge::SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect)
|
2012-03-12 15:50:21 +00:00
|
|
|
{
|
2015-01-10 00:33:57 +00:00
|
|
|
if (!mLayerClient) {
|
2012-03-12 15:50:21 +00:00
|
|
|
return;
|
2015-01-10 00:33:57 +00:00
|
|
|
}
|
2012-03-12 15:50:21 +00:00
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
mLayerClient->SetFirstPaintViewport(float(aOffset.x), float(aOffset.y), aZoom.scale,
|
|
|
|
aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
|
2012-03-12 15:50:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-06-03 13:52:44 +00:00
|
|
|
AndroidBridge::SetPageRect(const CSSRect& aCssPageRect)
|
2012-03-12 15:50:21 +00:00
|
|
|
{
|
2015-01-10 00:33:57 +00:00
|
|
|
if (!mLayerClient) {
|
2012-03-12 15:50:21 +00:00
|
|
|
return;
|
2015-01-10 00:33:57 +00:00
|
|
|
}
|
2012-03-12 15:50:21 +00:00
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
mLayerClient->SetPageRect(aCssPageRect.x, aCssPageRect.y,
|
|
|
|
aCssPageRect.XMost(), aCssPageRect.YMost());
|
2012-03-12 15:50:21 +00:00
|
|
|
}
|
|
|
|
|
2012-02-04 02:35:58 +00:00
|
|
|
void
|
2013-06-21 21:03:56 +00:00
|
|
|
AndroidBridge::SyncViewportInfo(const LayerIntRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
|
2015-08-18 18:27:20 +00:00
|
|
|
bool aLayersUpdated, int32_t aPaintSyncId, ParentLayerRect& aScrollRect, CSSToParentLayerScale& aScale,
|
2015-08-18 18:27:19 +00:00
|
|
|
ScreenMargin& aFixedLayerMargins)
|
2012-02-04 02:35:58 +00:00
|
|
|
{
|
2015-01-10 00:33:57 +00:00
|
|
|
if (!mLayerClient) {
|
2013-11-12 18:41:01 +00:00
|
|
|
ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
ViewTransform::LocalRef viewTransform = mLayerClient->SyncViewportInfo(
|
|
|
|
aDisplayPort.x, aDisplayPort.y,
|
|
|
|
aDisplayPort.width, aDisplayPort.height,
|
2015-08-18 18:27:20 +00:00
|
|
|
aDisplayResolution.scale, aLayersUpdated, aPaintSyncId);
|
2013-11-12 18:41:01 +00:00
|
|
|
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(viewTransform, "No view transform object!");
|
2012-03-14 04:15:11 +00:00
|
|
|
|
2015-08-18 18:27:20 +00:00
|
|
|
aScrollRect = ParentLayerRect(viewTransform->X(), viewTransform->Y(),
|
|
|
|
viewTransform->Width(), viewTransform->Height());
|
2015-01-10 00:33:57 +00:00
|
|
|
aScale.scale = viewTransform->Scale();
|
|
|
|
aFixedLayerMargins.top = viewTransform->FixedLayerMarginTop();
|
|
|
|
aFixedLayerMargins.right = viewTransform->FixedLayerMarginRight();
|
|
|
|
aFixedLayerMargins.bottom = viewTransform->FixedLayerMarginBottom();
|
|
|
|
aFixedLayerMargins.left = viewTransform->FixedLayerMarginLeft();
|
2012-02-04 02:35:58 +00:00
|
|
|
}
|
|
|
|
|
2015-09-12 01:58:16 +00:00
|
|
|
void AndroidBridge::SyncFrameMetrics(const ParentLayerPoint& aScrollOffset,
|
|
|
|
const CSSToParentLayerScale& aZoom,
|
|
|
|
const CSSRect& aCssPageRect,
|
|
|
|
const CSSRect& aDisplayPort,
|
|
|
|
const CSSToLayerScale& aPaintedResolution,
|
|
|
|
bool aLayersUpdated, int32_t aPaintSyncId,
|
|
|
|
ScreenMargin& aFixedLayerMargins)
|
2013-04-26 17:26:39 +00:00
|
|
|
{
|
2015-01-10 00:33:57 +00:00
|
|
|
if (!mLayerClient) {
|
2013-11-12 18:41:01 +00:00
|
|
|
ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
|
2013-04-26 17:26:39 +00:00
|
|
|
return;
|
2013-11-12 18:41:01 +00:00
|
|
|
}
|
2013-04-26 17:26:39 +00:00
|
|
|
|
2015-09-12 01:58:16 +00:00
|
|
|
// convert the displayport rect from document-relative CSS pixels to
|
|
|
|
// document-relative device pixels
|
|
|
|
LayerIntRect dp = gfx::RoundedToInt(aDisplayPort * aPaintedResolution);
|
2015-01-10 00:33:57 +00:00
|
|
|
ViewTransform::LocalRef viewTransform = mLayerClient->SyncFrameMetrics(
|
2015-09-12 01:58:16 +00:00
|
|
|
aScrollOffset.x, aScrollOffset.y, aZoom.scale,
|
2015-01-10 00:33:57 +00:00
|
|
|
aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost(),
|
2015-09-12 01:58:16 +00:00
|
|
|
dp.x, dp.y, dp.width, dp.height, aPaintedResolution.scale,
|
|
|
|
aLayersUpdated, aPaintSyncId);
|
2013-11-12 18:41:01 +00:00
|
|
|
|
2015-02-09 22:34:50 +00:00
|
|
|
MOZ_ASSERT(viewTransform, "No view transform object!");
|
2013-11-12 18:41:01 +00:00
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
aFixedLayerMargins.top = viewTransform->FixedLayerMarginTop();
|
|
|
|
aFixedLayerMargins.right = viewTransform->FixedLayerMarginRight();
|
|
|
|
aFixedLayerMargins.bottom = viewTransform->FixedLayerMarginBottom();
|
|
|
|
aFixedLayerMargins.left = viewTransform->FixedLayerMarginLeft();
|
2013-04-26 17:26:39 +00:00
|
|
|
}
|
|
|
|
|
2011-10-11 00:40:17 +00:00
|
|
|
/* Implementation file */
|
2014-04-27 07:06:00 +00:00
|
|
|
NS_IMPL_ISUPPORTS(nsAndroidBridge, nsIAndroidBridge)
|
2011-10-11 00:40:17 +00:00
|
|
|
|
|
|
|
nsAndroidBridge::nsAndroidBridge()
|
|
|
|
{
|
2016-04-18 10:48:19 +00:00
|
|
|
AddObservers();
|
2011-10-11 00:40:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsAndroidBridge::~nsAndroidBridge()
|
|
|
|
{
|
2016-04-18 10:48:19 +00:00
|
|
|
RemoveObservers();
|
2011-10-11 00:40:17 +00:00
|
|
|
}
|
|
|
|
|
2014-04-04 16:33:49 +00:00
|
|
|
NS_IMETHODIMP nsAndroidBridge::HandleGeckoMessage(JS::HandleValue val,
|
|
|
|
JSContext *cx)
|
2011-10-11 00:40:17 +00:00
|
|
|
{
|
2014-04-04 16:33:49 +00:00
|
|
|
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);
|
2014-07-14 13:01:32 +00:00
|
|
|
if (!JS_ParseJSON(cx, jsonStr, &jsonVal) || !jsonVal.isObject()) {
|
2014-04-04 16:33:49 +00:00
|
|
|
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);
|
2011-10-11 00:40:17 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2011-11-18 03:20:29 +00:00
|
|
|
|
2016-10-03 16:26:00 +00:00
|
|
|
NS_IMETHODIMP nsAndroidBridge::ContentDocumentChanged(mozIDOMWindowProxy* aWindow)
|
2013-05-30 13:55:23 +00:00
|
|
|
{
|
2016-10-03 16:26:00 +00:00
|
|
|
AndroidBridge::Bridge()->ContentDocumentChanged(aWindow);
|
2013-05-30 13:55:23 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-10-03 16:26:00 +00:00
|
|
|
NS_IMETHODIMP nsAndroidBridge::IsContentDocumentDisplayed(mozIDOMWindowProxy* aWindow,
|
|
|
|
bool *aRet)
|
2013-05-30 13:55:23 +00:00
|
|
|
{
|
2016-10-03 16:26:00 +00:00
|
|
|
*aRet = AndroidBridge::Bridge()->IsContentDocumentDisplayed(aWindow);
|
2013-05-30 13:55:23 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-04-18 10:48:19 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsAndroidBridge::Observe(nsISupports* aSubject, const char* aTopic,
|
|
|
|
const char16_t* aData)
|
|
|
|
{
|
|
|
|
if (!strcmp(aTopic, "xpcom-shutdown")) {
|
|
|
|
RemoveObservers();
|
2016-09-09 01:49:25 +00:00
|
|
|
} else if (!strcmp(aTopic, "media-playback")) {
|
|
|
|
ALOG_BRIDGE("nsAndroidBridge::Observe, get media-playback event.");
|
2016-06-01 02:21:58 +00:00
|
|
|
|
2016-09-09 01:49:25 +00:00
|
|
|
nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
|
|
|
|
if (!wrapper) {
|
2016-06-01 02:26:14 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-09-09 01:49:25 +00:00
|
|
|
uint64_t windowId = 0;
|
|
|
|
nsresult rv = wrapper->GetData(&windowId);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
2016-06-01 02:21:58 +00:00
|
|
|
|
2016-09-09 01:49:25 +00:00
|
|
|
nsAutoString activeStr(aData);
|
|
|
|
bool isPlaying = activeStr.EqualsLiteral("active");
|
|
|
|
UpdateAudioPlayingWindows(windowId, isPlaying);
|
2016-06-01 02:21:58 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-09-09 01:49:25 +00:00
|
|
|
nsAndroidBridge::UpdateAudioPlayingWindows(uint64_t aWindowId,
|
2016-06-01 02:21:58 +00:00
|
|
|
bool aPlaying)
|
|
|
|
{
|
|
|
|
// Request audio focus for the first audio playing window and abandon focus
|
|
|
|
// for the last audio playing window.
|
2016-09-09 01:49:25 +00:00
|
|
|
if (aPlaying && !mAudioPlayingWindows.Contains(aWindowId)) {
|
|
|
|
mAudioPlayingWindows.AppendElement(aWindowId);
|
2016-06-01 02:21:58 +00:00
|
|
|
if (mAudioPlayingWindows.Length() == 1) {
|
|
|
|
ALOG_BRIDGE("nsAndroidBridge, request audio focus.");
|
2016-04-18 10:48:19 +00:00
|
|
|
AudioFocusAgent::NotifyStartedPlaying();
|
2016-06-01 02:21:58 +00:00
|
|
|
}
|
2016-09-09 01:49:25 +00:00
|
|
|
} else if (!aPlaying && mAudioPlayingWindows.Contains(aWindowId)) {
|
|
|
|
mAudioPlayingWindows.RemoveElement(aWindowId);
|
2016-06-01 02:21:58 +00:00
|
|
|
if (mAudioPlayingWindows.Length() == 0) {
|
|
|
|
ALOG_BRIDGE("nsAndroidBridge, abandon audio focus.");
|
2016-04-18 10:48:19 +00:00
|
|
|
AudioFocusAgent::NotifyStoppedPlaying();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsAndroidBridge::AddObservers()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->AddObserver(this, "xpcom-shutdown", false);
|
2016-09-29 03:49:25 +00:00
|
|
|
if (jni::IsFennec()) { // No AudioFocusAgent in non-Fennec environment.
|
|
|
|
obs->AddObserver(this, "media-playback", false);
|
|
|
|
}
|
2016-04-18 10:48:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsAndroidBridge::RemoveObservers()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
|
|
if (obs) {
|
|
|
|
obs->RemoveObserver(this, "xpcom-shutdown");
|
2016-09-29 03:49:25 +00:00
|
|
|
if (jni::IsFennec()) { // No AudioFocusAgent in non-Fennec environment.
|
|
|
|
obs->RemoveObserver(this, "media-playback");
|
|
|
|
}
|
2016-04-18 10:48:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 21:36:07 +00:00
|
|
|
uint32_t
|
|
|
|
AndroidBridge::GetScreenOrientation()
|
2012-03-20 13:09:45 +00:00
|
|
|
{
|
|
|
|
ALOG_BRIDGE("AndroidBridge::GetScreenOrientation");
|
2012-05-04 15:08:47 +00:00
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
int16_t orientation = GeckoAppShell::GetScreenOrientation();
|
2012-05-04 15:08:47 +00:00
|
|
|
|
2013-09-09 12:57:37 +00:00
|
|
|
if (!orientation)
|
2012-05-08 21:36:07 +00:00
|
|
|
return dom::eScreenOrientation_None;
|
2012-05-04 15:08:47 +00:00
|
|
|
|
2015-08-18 21:55:09 +00:00
|
|
|
return static_cast<dom::ScreenOrientationInternal>(orientation);
|
2012-03-20 13:09:45 +00:00
|
|
|
}
|
|
|
|
|
2015-08-18 21:55:15 +00:00
|
|
|
uint16_t
|
|
|
|
AndroidBridge::GetScreenAngle()
|
|
|
|
{
|
|
|
|
return GeckoAppShell::GetScreenAngle();
|
|
|
|
}
|
|
|
|
|
2012-11-13 19:25:18 +00:00
|
|
|
nsresult
|
|
|
|
AndroidBridge::GetProxyForURI(const nsACString & aSpec,
|
|
|
|
const nsACString & aScheme,
|
|
|
|
const nsACString & aHost,
|
|
|
|
const int32_t aPort,
|
|
|
|
nsACString & aResult)
|
|
|
|
{
|
2015-08-13 04:53:39 +00:00
|
|
|
if (!jni::IsAvailable()) {
|
2014-01-18 05:32:24 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2012-11-13 19:25:18 +00:00
|
|
|
|
2016-08-13 03:15:52 +00:00
|
|
|
auto jstrRet = GeckoAppShell::GetProxyForURI(aSpec, aScheme, aHost, aPort);
|
2012-11-13 19:25:18 +00:00
|
|
|
|
2013-09-09 12:57:37 +00:00
|
|
|
if (!jstrRet)
|
2012-11-13 19:25:18 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2016-02-09 22:27:28 +00:00
|
|
|
aResult = jstrRet->ToCString();
|
2012-11-13 19:25:18 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-04-28 00:52:52 +00:00
|
|
|
bool
|
|
|
|
AndroidBridge::PumpMessageLoop()
|
|
|
|
{
|
2015-08-13 04:53:39 +00:00
|
|
|
JNIEnv* const env = jni::GetGeckoThreadEnv();
|
2015-04-28 00:52:52 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-08-13 04:53:39 +00:00
|
|
|
return GeckoThread::PumpMessageLoop(msg);
|
2015-04-28 00:52:52 +00:00
|
|
|
}
|
2012-11-13 19:25:18 +00:00
|
|
|
|
2012-02-17 18:52:26 +00:00
|
|
|
NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp)
|
|
|
|
{
|
2015-12-24 03:03:35 +00:00
|
|
|
nsAppShell* const appShell = nsAppShell::Get();
|
|
|
|
if (appShell)
|
2016-07-21 17:49:04 +00:00
|
|
|
NS_IF_ADDREF(*aBrowserApp = appShell->GetBrowserApp());
|
2012-02-17 18:52:26 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-05-04 15:08:47 +00:00
|
|
|
|
2012-02-17 18:52:26 +00:00
|
|
|
NS_IMETHODIMP nsAndroidBridge::SetBrowserApp(nsIAndroidBrowserApp *aBrowserApp)
|
|
|
|
{
|
2015-12-24 03:03:35 +00:00
|
|
|
nsAppShell* const appShell = nsAppShell::Get();
|
|
|
|
if (appShell)
|
|
|
|
appShell->SetBrowserApp(aBrowserApp);
|
2012-02-17 18:52:26 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
__attribute__ ((visibility("default")))
|
|
|
|
jobject JNICALL
|
2012-05-04 15:08:47 +00:00
|
|
|
Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *env, jclass, jlong size);
|
2012-02-17 18:52:26 +00:00
|
|
|
|
2016-10-03 16:26:00 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2013-05-30 13:55:23 +00:00
|
|
|
void
|
2016-10-03 16:26:00 +00:00
|
|
|
AndroidBridge::ContentDocumentChanged(mozIDOMWindowProxy* aWindow)
|
2013-05-30 13:55:23 +00:00
|
|
|
{
|
2016-10-03 16:26:00 +00:00
|
|
|
auto layerClient = GetJavaLayerClient(aWindow);
|
|
|
|
if (!layerClient) {
|
2013-05-30 13:55:23 +00:00
|
|
|
return;
|
2013-11-12 18:41:01 +00:00
|
|
|
}
|
2016-10-03 16:26:00 +00:00
|
|
|
layerClient->ContentDocumentChanged();
|
2013-05-30 13:55:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2016-10-03 16:26:00 +00:00
|
|
|
AndroidBridge::IsContentDocumentDisplayed(mozIDOMWindowProxy* aWindow)
|
2013-05-30 13:55:23 +00:00
|
|
|
{
|
2016-10-03 16:26:00 +00:00
|
|
|
auto layerClient = GetJavaLayerClient(aWindow);
|
|
|
|
if (!layerClient) {
|
2013-05-30 13:55:23 +00:00
|
|
|
return false;
|
2016-10-03 16:26:00 +00:00
|
|
|
}
|
|
|
|
return layerClient->IsContentDocumentDisplayed();
|
2013-05-30 13:55:23 +00:00
|
|
|
}
|
|
|
|
|
2016-02-10 23:54:55 +00:00
|
|
|
class AndroidBridge::DelayedTask
|
|
|
|
{
|
|
|
|
using TimeStamp = mozilla::TimeStamp;
|
|
|
|
using TimeDuration = mozilla::TimeDuration;
|
|
|
|
|
|
|
|
public:
|
2016-04-28 00:06:05 +00:00
|
|
|
DelayedTask(already_AddRefed<Runnable> aTask)
|
2016-02-10 23:54:55 +00:00
|
|
|
: mTask(aTask)
|
|
|
|
, mRunTime() // Null timestamp representing no delay.
|
|
|
|
{}
|
|
|
|
|
2016-04-28 00:06:05 +00:00
|
|
|
DelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs)
|
2016-02-10 23:54:55 +00:00
|
|
|
: 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;
|
|
|
|
}
|
|
|
|
|
2016-04-28 00:06:05 +00:00
|
|
|
already_AddRefed<Runnable> TakeTask()
|
2016-02-10 23:54:55 +00:00
|
|
|
{
|
2016-04-28 00:06:05 +00:00
|
|
|
return mTask.forget();
|
2016-02-10 23:54:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2016-04-28 00:06:05 +00:00
|
|
|
RefPtr<Runnable> mTask;
|
2016-02-10 23:54:55 +00:00
|
|
|
const TimeStamp mRunTime;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-04-26 17:24:28 +00:00
|
|
|
void
|
2016-04-28 00:06:05 +00:00
|
|
|
AndroidBridge::PostTaskToUiThread(already_AddRefed<Runnable> aTask, int aDelayMs)
|
2013-04-26 17:24:28 +00:00
|
|
|
{
|
2016-02-10 23:54:55 +00:00
|
|
|
// add the new task into the mUiTaskQueue, sorted with
|
2013-04-26 17:26:46 +00:00
|
|
|
// the earliest task first in the queue
|
2016-02-10 23:54:55 +00:00
|
|
|
size_t i;
|
2016-04-28 00:06:05 +00:00
|
|
|
DelayedTask newTask(aDelayMs ? DelayedTask(mozilla::Move(aTask), aDelayMs)
|
|
|
|
: DelayedTask(mozilla::Move(aTask)));
|
2016-02-10 23:54:55 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
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));
|
2013-04-26 17:26:46 +00:00
|
|
|
}
|
|
|
|
}
|
2016-02-10 23:54:55 +00:00
|
|
|
|
2013-04-26 17:26:46 +00:00
|
|
|
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
|
2016-08-18 22:04:11 +00:00
|
|
|
GeckoThread::RequestUiThreadCallback(int64_t(aDelayMs));
|
2013-04-26 17:26:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t
|
2014-08-08 21:42:20 +00:00
|
|
|
AndroidBridge::RunDelayedUiThreadTasks()
|
2013-04-26 17:26:46 +00:00
|
|
|
{
|
2016-02-10 23:54:55 +00:00
|
|
|
MutexAutoLock lock(mUiTaskQueueLock);
|
|
|
|
|
|
|
|
while (!mUiTaskQueue.IsEmpty()) {
|
|
|
|
const int64_t timeLeft = mUiTaskQueue[0].MillisecondsToRunTime();
|
2013-04-26 17:26:46 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-02-10 23:54:55 +00:00
|
|
|
// Retrieve task before unlocking/running.
|
2016-04-28 00:06:05 +00:00
|
|
|
RefPtr<Runnable> nextTask(mUiTaskQueue[0].TakeTask());
|
2016-02-10 23:54:55 +00:00
|
|
|
mUiTaskQueue.RemoveElementAt(0);
|
2013-04-26 17:26:46 +00:00
|
|
|
|
2016-02-10 23:54:55 +00:00
|
|
|
// Unlock to allow posting new tasks reentrantly.
|
|
|
|
MutexAutoUnlock unlock(mUiTaskQueueLock);
|
|
|
|
nextTask->Run();
|
2013-04-26 17:26:46 +00:00
|
|
|
}
|
|
|
|
return -1;
|
2013-04-26 17:24:28 +00:00
|
|
|
}
|
2014-06-04 19:28:04 +00:00
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
Object::LocalRef AndroidBridge::ChannelCreate(Object::Param stream) {
|
2015-08-13 04:53:39 +00:00
|
|
|
JNIEnv* const env = GetEnvForThread();
|
2015-01-10 00:33:57 +00:00
|
|
|
auto rv = Object::LocalRef::Adopt(env, env->CallStaticObjectMethod(
|
2015-09-24 18:53:05 +00:00
|
|
|
sBridge->jChannels, sBridge->jChannelCreate, stream.Get()));
|
2015-12-30 23:36:41 +00:00
|
|
|
MOZ_CATCH_JNI_EXCEPTION(env);
|
2015-01-10 00:33:57 +00:00
|
|
|
return rv;
|
2014-06-04 19:28:04 +00:00
|
|
|
}
|
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
void AndroidBridge::InputStreamClose(Object::Param obj) {
|
2015-08-13 04:53:39 +00:00
|
|
|
JNIEnv* const env = GetEnvForThread();
|
2015-01-10 00:33:57 +00:00
|
|
|
env->CallVoidMethod(obj.Get(), sBridge->jClose);
|
2015-12-30 23:36:41 +00:00
|
|
|
MOZ_CATCH_JNI_EXCEPTION(env);
|
2014-06-04 19:28:04 +00:00
|
|
|
}
|
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
uint32_t AndroidBridge::InputStreamAvailable(Object::Param obj) {
|
2015-08-13 04:53:39 +00:00
|
|
|
JNIEnv* const env = GetEnvForThread();
|
2015-01-10 00:33:57 +00:00
|
|
|
auto rv = env->CallIntMethod(obj.Get(), sBridge->jAvailable);
|
2015-12-30 23:36:41 +00:00
|
|
|
MOZ_CATCH_JNI_EXCEPTION(env);
|
2015-01-10 00:33:57 +00:00
|
|
|
return rv;
|
2014-06-04 19:28:04 +00:00
|
|
|
}
|
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
nsresult AndroidBridge::InputStreamRead(Object::Param obj, char *aBuf, uint32_t aCount, uint32_t *aRead) {
|
2015-08-13 04:53:39 +00:00
|
|
|
JNIEnv* const env = GetEnvForThread();
|
2016-07-21 17:49:04 +00:00
|
|
|
auto arr = ByteBuffer::New(aBuf, aCount);
|
2015-01-10 00:33:57 +00:00
|
|
|
jint read = env->CallIntMethod(obj.Get(), sBridge->jByteBufferRead, arr.Get());
|
2014-06-04 19:28:04 +00:00
|
|
|
|
|
|
|
if (env->ExceptionCheck()) {
|
|
|
|
env->ExceptionClear();
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (read <= 0) {
|
|
|
|
*aRead = 0;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
*aRead = read;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2014-07-24 20:42:50 +00:00
|
|
|
|
|
|
|
nsresult AndroidBridge::GetExternalPublicDirectory(const nsAString& aType, nsAString& aPath) {
|
2015-09-15 18:01:07 +00:00
|
|
|
if (XRE_IsContentProcess()) {
|
|
|
|
nsString key(aType);
|
|
|
|
nsAutoString path;
|
|
|
|
if (AndroidBridge::sStoragePaths.Get(key, &path)) {
|
|
|
|
aPath = path;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lazily get the value from the parent.
|
|
|
|
dom::ContentChild* child = dom::ContentChild::GetSingleton();
|
|
|
|
if (child) {
|
|
|
|
nsAutoString type(aType);
|
|
|
|
child->SendGetDeviceStorageLocation(type, &path);
|
|
|
|
if (!path.IsEmpty()) {
|
|
|
|
AndroidBridge::sStoragePaths.Put(key, path);
|
2015-11-06 05:55:40 +00:00
|
|
|
aPath = path;
|
2015-09-15 18:01:07 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ALOG_BRIDGE("AndroidBridge::GetExternalPublicDirectory no cache for %s",
|
|
|
|
NS_ConvertUTF16toUTF8(aType).get());
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
2015-01-10 00:33:57 +00:00
|
|
|
auto path = GeckoAppShell::GetExternalPublicDirectory(aType);
|
2014-07-24 20:42:50 +00:00
|
|
|
if (!path) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
2016-02-09 22:27:28 +00:00
|
|
|
aPath = path->ToString();
|
2014-07-24 20:42:50 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|