diff --git a/hal/android/AndroidAlarm.cpp b/hal/android/AndroidAlarm.cpp new file mode 100644 index 000000000000..df910acb3019 --- /dev/null +++ b/hal/android/AndroidAlarm.cpp @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "Hal.h" +#include "AndroidBridge.h" + +#include "GeneratedJNINatives.h" + +using namespace mozilla::hal; + +namespace mozilla { + +class AlarmReceiver : public widget::AlarmReceiver::Natives +{ +private: + AlarmReceiver(); + +public: + static void NotifyAlarmFired() { + nsCOMPtr runnable = NS_NewRunnableFunction([=]() { + hal::NotifyAlarmFired(); + }); + NS_DispatchToMainThread(runnable); + } +}; + +namespace hal_impl { + +bool +EnableAlarm() +{ + AlarmReceiver::Init(); + return true; +} + +void +DisableAlarm() +{ + widget::GeckoAppShell::DisableAlarm(); +} + +bool +SetAlarm(int32_t aSeconds, int32_t aNanoseconds) +{ + return widget::GeckoAppShell::SetAlarm(aSeconds, aNanoseconds); +} + +} // hal_impl +} // mozilla diff --git a/hal/moz.build b/hal/moz.build index 4f47a80575f3..ba9abffd8567 100644 --- a/hal/moz.build +++ b/hal/moz.build @@ -33,9 +33,12 @@ SOURCES += [ ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': + LOCAL_INCLUDES += [ + '/widget/android', + ] UNIFIED_SOURCES += [ + 'android/AndroidAlarm.cpp', 'android/AndroidSensor.cpp', - 'fallback/FallbackAlarm.cpp', 'fallback/FallbackPower.cpp', 'linux/LinuxMemory.cpp', ] diff --git a/mobile/android/b2gdroid/app/b2gdroid.js b/mobile/android/b2gdroid/app/b2gdroid.js index 649456fdd92a..ea4ee2f31409 100644 --- a/mobile/android/b2gdroid/app/b2gdroid.js +++ b/mobile/android/b2gdroid/app/b2gdroid.js @@ -1022,4 +1022,7 @@ pref("dom.wakelock.enabled", true); pref("dom.webcomponents.enabled", true); +// Enable the Alarms API +pref("dom.mozAlarms.enabled", true); + pref("layout.css.scroll-snap.enabled", true); diff --git a/mobile/android/b2gdroid/app/src/main/AndroidManifest.xml b/mobile/android/b2gdroid/app/src/main/AndroidManifest.xml index bf112ef54837..99d16f660da2 100644 --- a/mobile/android/b2gdroid/app/src/main/AndroidManifest.xml +++ b/mobile/android/b2gdroid/app/src/main/AndroidManifest.xml @@ -119,6 +119,8 @@ android:process="org.mozilla.b2gdroid.UpdateService"> + + diff --git a/mobile/android/base/AlarmReceiver.java b/mobile/android/base/AlarmReceiver.java new file mode 100644 index 000000000000..a06490d2c22d --- /dev/null +++ b/mobile/android/base/AlarmReceiver.java @@ -0,0 +1,42 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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/. */ + +package org.mozilla.gecko; + +import org.mozilla.gecko.annotation.WrapForJNI; + +import android.app.IntentService; +import android.content.Context; +import android.content.Intent; +import android.content.BroadcastReceiver; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; +import android.util.Log; + +import java.util.Timer; +import java.util.TimerTask; + +public class AlarmReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + final WakeLock wakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "GeckoAlarm"); + wakeLock.acquire(); + + AlarmReceiver.notifyAlarmFired(); + TimerTask releaseLockTask = new TimerTask() { + @Override + public void run() { + wakeLock.release(); + } + }; + Timer timer = new Timer(); + // 5 seconds ought to be enough for anybody + timer.schedule(releaseLockTask, 5*1000); + } + + @WrapForJNI + private static native void notifyAlarmFired(); +} diff --git a/mobile/android/base/AndroidManifest.xml.in b/mobile/android/base/AndroidManifest.xml.in index 7fe1d0701447..cb40a1511390 100644 --- a/mobile/android/base/AndroidManifest.xml.in +++ b/mobile/android/base/AndroidManifest.xml.in @@ -381,10 +381,13 @@ + android:exported="false" + android:process="@MANGLED_ANDROID_PACKAGE_NAME@.Restarter"> + + + #include ../services/manifests/FxAccountAndroidManifest_activities.xml.in #include ../services/manifests/HealthReportAndroidManifest_activities.xml.in #include ../services/manifests/SyncAndroidManifest_activities.xml.in diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 54db507a49a9..8395f75c9b05 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -59,6 +59,7 @@ import org.mozilla.gecko.util.ThreadUtils; import android.annotation.TargetApi; import android.app.Activity; import android.app.ActivityManager; +import android.app.AlarmManager; import android.app.PendingIntent; import android.content.ActivityNotFoundException; import android.content.Context; @@ -603,6 +604,31 @@ public class GeckoAppShell locationHighAccuracyEnabled = enable; } + @WrapForJNI + public static boolean setAlarm(int aSeconds, int aNanoSeconds) { + AlarmManager am = (AlarmManager) + getContext().getSystemService(Context.ALARM_SERVICE); + + Intent intent = new Intent(getContext(), AlarmReceiver.class); + PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); + + // AlarmManager only supports millisecond precision + long time = ((long)aSeconds * 1000) + ((long)aNanoSeconds/1_000_000L); + am.setExact(AlarmManager.RTC_WAKEUP, time, pi); + + return true; + } + + @WrapForJNI + public static void disableAlarm() { + AlarmManager am = (AlarmManager) + getContext().getSystemService(Context.ALARM_SERVICE); + + Intent intent = new Intent(getContext(), AlarmReceiver.class); + PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); + am.cancel(pi); + } + @WrapForJNI public static void enableSensor(int aSensortype) { GeckoInterface gi = getGeckoInterface(); diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index 3ee8de3c829e..8714c323983e 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -160,6 +160,7 @@ gbjar.sources += [ 'ActionModeCompat.java', 'ActionModeCompatView.java', 'ActivityHandlerHelper.java', + 'AlarmReceiver.java', 'AndroidGamepadManager.java', 'animation/AnimationUtils.java', 'animation/AnimatorProxy.java', diff --git a/widget/android/GeneratedJNINatives.h b/widget/android/GeneratedJNINatives.h index aa9aa027ff04..c372a34d2b00 100644 --- a/widget/android/GeneratedJNINatives.h +++ b/widget/android/GeneratedJNINatives.h @@ -36,6 +36,21 @@ public: template constexpr JNINativeMethod ANRReporter::Natives::methods[]; +template +class AlarmReceiver::Natives : public mozilla::jni::NativeImpl +{ +public: + static constexpr JNINativeMethod methods[] = { + + mozilla::jni::MakeNativeMethod( + mozilla::jni::NativeStub + ::template Wrap<&Impl::NotifyAlarmFired>) + }; +}; + +template +constexpr JNINativeMethod AlarmReceiver::Natives::methods[]; + template class GeckoJavaSampler::Natives : public mozilla::jni::NativeImpl { diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index d20fb670b50e..3623a5365e1c 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -21,6 +21,11 @@ constexpr char ANRReporter::ReleaseNativeStack_t::signature[]; constexpr char ANRReporter::RequestNativeStack_t::name[]; constexpr char ANRReporter::RequestNativeStack_t::signature[]; +constexpr char AlarmReceiver::name[]; + +constexpr char AlarmReceiver::NotifyAlarmFired_t::name[]; +constexpr char AlarmReceiver::NotifyAlarmFired_t::signature[]; + constexpr char DownloadsIntegration::name[]; constexpr char DownloadsIntegration::ScanMedia_t::name[]; @@ -137,6 +142,14 @@ auto GeckoAppShell::DeleteMessageWrapper(int32_t a0, int32_t a1) -> void return mozilla::jni::Method::Call(nullptr, nullptr, a0, a1); } +constexpr char GeckoAppShell::DisableAlarm_t::name[]; +constexpr char GeckoAppShell::DisableAlarm_t::signature[]; + +auto GeckoAppShell::DisableAlarm() -> void +{ + return mozilla::jni::Method::Call(nullptr, nullptr); +} + constexpr char GeckoAppShell::DisableBatteryNotifications_t::name[]; constexpr char GeckoAppShell::DisableBatteryNotifications_t::signature[]; @@ -617,6 +630,14 @@ auto GeckoAppShell::SendMessageWrapper(mozilla::jni::String::Param a0, mozilla:: return mozilla::jni::Method::Call(nullptr, nullptr, a0, a1, a2); } +constexpr char GeckoAppShell::SetAlarm_t::name[]; +constexpr char GeckoAppShell::SetAlarm_t::signature[]; + +auto GeckoAppShell::SetAlarm(int32_t a0, int32_t a1) -> bool +{ + return mozilla::jni::Method::Call(nullptr, nullptr, a0, a1); +} + constexpr char GeckoAppShell::SetFullScreen_t::name[]; constexpr char GeckoAppShell::SetFullScreen_t::signature[]; diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index cad7fab9c61b..79eddff3d163 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -76,6 +76,39 @@ public: template class Natives; }; +class AlarmReceiver : public mozilla::jni::Class +{ +public: + typedef mozilla::jni::Ref Ref; + typedef mozilla::jni::LocalRef LocalRef; + typedef mozilla::jni::GlobalRef GlobalRef; + typedef const mozilla::jni::Param& Param; + + static constexpr char name[] = + "org/mozilla/gecko/AlarmReceiver"; + +protected: + AlarmReceiver(jobject instance) : Class(instance) {} + +public: + struct NotifyAlarmFired_t { + typedef AlarmReceiver Owner; + typedef void ReturnType; + typedef void SetterType; + typedef mozilla::jni::Args<> Args; + static constexpr char name[] = "notifyAlarmFired"; + static constexpr char signature[] = + "()V"; + static const bool isStatic = true; + static const bool isMultithreaded = false; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + +public: + template class Natives; +}; + class DownloadsIntegration : public mozilla::jni::Class { public: @@ -376,6 +409,23 @@ public: static auto DeleteMessageWrapper(int32_t, int32_t) -> void; +public: + struct DisableAlarm_t { + typedef GeckoAppShell Owner; + typedef void ReturnType; + typedef void SetterType; + typedef mozilla::jni::Args<> Args; + static constexpr char name[] = "disableAlarm"; + static constexpr char signature[] = + "()V"; + static const bool isStatic = true; + static const bool isMultithreaded = false; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + + static auto DisableAlarm() -> void; + public: struct DisableBatteryNotifications_t { typedef GeckoAppShell Owner; @@ -1458,6 +1508,25 @@ public: static auto SendMessageWrapper(mozilla::jni::String::Param, mozilla::jni::String::Param, int32_t) -> void; +public: + struct SetAlarm_t { + typedef GeckoAppShell Owner; + typedef bool ReturnType; + typedef bool SetterType; + typedef mozilla::jni::Args< + int32_t, + int32_t> Args; + static constexpr char name[] = "setAlarm"; + static constexpr char signature[] = + "(II)Z"; + static const bool isStatic = true; + static const bool isMultithreaded = false; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + + static auto SetAlarm(int32_t, int32_t) -> bool; + public: struct SetFullScreen_t { typedef GeckoAppShell Owner;