diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..07c1b1d
Binary files /dev/null and b/.DS_Store differ
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..3e6052b
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,87 @@
+## ChangeLog
+#### Version 0.7.2 (02.02.2017)
+- Fixed app freeze on iOS using wkwebview-engine
+- Websocket sample in SampleApp
+
+#### Version 0.7.1 (30.01.2017)
+- Bug fixes for iOS9 and Android
+- Allow app to be excluded from recent list on Android
+
+#### Version 0.7.0 (27.01.2017)
+- __Features__
+ - Support for tAmazon FireOS
+ - Support for the browser platform
+ - Ability to configure icon and color on Android
+ - Allow app to move to foreground on Android
+ - Allow app to move to background on Android
+ - Allow app to override back button behaviour on Android
+ - New events for when the mode has been enabled/disabled
+- __Improvements__
+ - Various enhancements and bug fixes for all platforms
+ - Support for latest platform and OS versions
+ - Multi line text on Android
+ - Multiple listeners for same event
+ - Compatibility with cordova-plugin-geolocation
+ - Compatibility with cordova-plugin-crosswalk-webview
+ - Compatibility with cordova-plugin-wkwebview-engine
+ - New sample app
+- __Fixes__
+ - Silent mode issues on Android
+ - Lock screen issues on Android
+ - Callback not called on Android
+ - Notification shows app info with cordova-android@6
+ - Other apps audio interruption on iOS
+- __Changes__
+ - Deprecate event callbacks
+ - Notification not visible by default on lock screen
+ - Remove ticker property on Android
+ - Remove unexpected back button handler
+ - Remove support for wp8 platform
+
+#### Version 0.6.5 (29.02.2016)
+- Published on npm
+- Updated dependency ID for the device plug-in
+
+#### Version 0.6.4 (03.03.2015)
+- Resolve possibly dependency conflict
+
+#### Version 0.6.3 (01.01.2015)
+- [feature:] Silent mode for Android
+
+#### Version 0.6.2 (14.12.2014)
+- [bugfix:] Type error
+- [bugfix:] Wrong default values for `isEnabled` and `isActive`.
+
+#### Version 0.6.1 (14.12.2014)
+- [enhancement:] Set default settings through `setDefaults`.
+- [enhancement:] New method `isEnabled` to receive if mode is enabled.
+- [enhancement:] New method `isActive` to receive if mode is active.
+- [bugfix:] Events caused thread collision.
+
+
+#### Version 0.6.0 (14.12.2014)
+- [feature:] Android support
+- [feature:] Change Android notification through `configure`.
+- [feature:] `onactivate`, `ondeactivate` and `onfailure` callbacks.
+- [___change___:] Disabled by default
+- [enhancement:] Get default settings through `getDefaults`.
+- [enhancement:] iOS does not require user permissions, internet connection and geo location anymore.
+
+#### Version 0.5.0 (13.02.2014)
+- __retired__
+
+#### Version 0.4.1 (13.02.2014)
+- Release under the Apache 2.0 license.
+- [enhancement:] Location tracking is only activated on WP8 if the location service is available.
+- [bigfix:] Nullpointer exception on WP8.
+
+#### Version 0.4.0 (10.10.2013)
+- Added WP8 support
+ The plugin turns the app into an location tracking app *(for the time it runs in the background)*.
+
+#### Version 0.2.1 (09.10.2013)
+- Added js interface to manually enable/disable the background mode.
+
+#### Version 0.2.0 (08.10.2013)
+- Added iOS (>= 5) support
+ The plugin turns the app into an location tracking app for the time it runs in the background.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..9999e87
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2013 appPlant GmbH
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..78e9329
--- /dev/null
+++ b/package.json
@@ -0,0 +1,59 @@
+{
+ "_from": "cordova-plugin-background-mode",
+ "_id": "cordova-plugin-background-mode@0.7.2",
+ "_inBundle": false,
+ "_integrity": "sha1-6vVjnAZahyMbPs91em4osQHQMy8=",
+ "_location": "/cordova-plugin-background-mode",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "tag",
+ "registry": true,
+ "raw": "cordova-plugin-background-mode",
+ "name": "cordova-plugin-background-mode",
+ "escapedName": "cordova-plugin-background-mode",
+ "rawSpec": "",
+ "saveSpec": null,
+ "fetchSpec": "latest"
+ },
+ "_requiredBy": [
+ "#USER",
+ "/"
+ ],
+ "_resolved": "https://registry.npm.taobao.org/cordova-plugin-background-mode/download/cordova-plugin-background-mode-0.7.2.tgz",
+ "_shasum": "eaf5639c065a87231b3ecf757a6e28b101d0332f",
+ "_spec": "cordova-plugin-background-mode",
+ "_where": "/Users/zhangxiongwang/Documents/workspace/laoting",
+ "author": {
+ "name": "Sebastián Katzer"
+ },
+ "bugs": {
+ "url": "https://github.com/katzer/cordova-plugin-background-mode/issues"
+ },
+ "bundleDependencies": false,
+ "deprecated": false,
+ "description": "Prevent app from going to sleep in background.",
+ "engines": [
+ {
+ "name": "cordova",
+ "version": ">=6.0.0"
+ }
+ ],
+ "homepage": "https://github.com/katzer/cordova-plugin-background-mode#readme",
+ "keywords": [
+ "appplant",
+ "background",
+ "cordova",
+ "ecosystem:cordova"
+ ],
+ "license": "Apache 2.0",
+ "name": "cordova-plugin-background-mode",
+ "platforms": [
+ "ios",
+ "android"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/katzer/cordova-plugin-background-mode.git"
+ },
+ "version": "0.7.2"
+}
diff --git a/plugin.xml b/plugin.xml
new file mode 100644
index 0000000..4121a33
--- /dev/null
+++ b/plugin.xml
@@ -0,0 +1,132 @@
+
+
+
+
+ BackgroundMode
+
+ Prevent apps from going to sleep in background.
+
+ https://github.com/katzer/cordova-plugin-background-mode.git
+
+ appplant, background
+
+ Apache 2.0
+
+ Sebastián Katzer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ audio
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/android/BackgroundExt.java b/src/android/BackgroundExt.java
new file mode 100644
index 0000000..69e4ec6
--- /dev/null
+++ b/src/android/BackgroundExt.java
@@ -0,0 +1,178 @@
+/*
+ Copyright 2013-2017 appPlant GmbH
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+package de.appplant.cordova.plugin.background;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityManager.AppTask;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.view.View;
+
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaWebView;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.util.List;
+
+class BackgroundExt {
+
+ // Weak reference to the cordova interface passed by the plugin
+ private final WeakReference cordova;
+
+ // Weak reference to the cordova web view passed by the plugin
+ private final WeakReference webView;
+
+ /**
+ * Initialize the extension to perform non-background related tasks.
+ *
+ * @param cordova The cordova interface.
+ * @param webView The cordova web view.
+ */
+ private BackgroundExt(CordovaInterface cordova, CordovaWebView webView) {
+ this.cordova = new WeakReference(cordova);
+ this.webView = new WeakReference(webView);
+ }
+
+ /**
+ * Executes the request.
+ *
+ * @param action The action to execute.
+ * @param cordova The cordova interface.
+ * @param webView The cordova web view.
+ */
+ static void execute(String action, CordovaInterface cordova,
+ CordovaWebView webView) {
+
+ BackgroundExt ext = new BackgroundExt(cordova, webView);
+
+ if (action.equalsIgnoreCase("optimizations")) {
+ ext.disableWebViewOptimizations();
+ }
+
+ if (action.equalsIgnoreCase("background")) {
+ ext.moveToBackground();
+ }
+
+ if (action.equalsIgnoreCase("foreground")) {
+ ext.moveToForeground();
+ }
+
+ if (action.equalsIgnoreCase("tasklist")) {
+ ext.excludeFromTaskList();
+ }
+ }
+
+ /**
+ * Move app to background.
+ */
+ private void moveToBackground() {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+
+ intent.addCategory(Intent.CATEGORY_HOME);
+ getActivity().startActivity(intent);
+ }
+
+ /**
+ * Move app to foreground.
+ */
+ private void moveToForeground() {
+ Activity app = getActivity();
+ String pkgName = app.getPackageName();
+
+ Intent intent = app
+ .getPackageManager()
+ .getLaunchIntentForPackage(pkgName);
+
+ intent.addFlags( Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
+ | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+
+ app.startActivity(intent);
+ }
+
+ /**
+ * Enable GPS position tracking while in background.
+ */
+ private void disableWebViewOptimizations() {
+ Thread thread = new Thread(){
+ public void run() {
+ try {
+ Thread.sleep(1000);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ View view = webView.get().getEngine().getView();
+
+ try {
+ Class> xWalkCls = Class.forName(
+ "org.crosswalk.engine.XWalkCordovaView");
+
+ Method onShowMethod =
+ xWalkCls.getMethod("onShow");
+
+ onShowMethod.invoke(view);
+ } catch (Exception e){
+ view.dispatchWindowVisibilityChanged(View.VISIBLE);
+ }
+ }
+ });
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+ }
+ };
+
+ thread.start();
+ }
+
+ /**
+ * Exclude the app from the recent tasks list.
+ */
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private void excludeFromTaskList() {
+ ActivityManager am = (ActivityManager) getActivity()
+ .getSystemService(Context.ACTIVITY_SERVICE);
+
+ if (am == null || Build.VERSION.SDK_INT < 21)
+ return;
+
+ List tasks = am.getAppTasks();
+
+ if (tasks == null || tasks.isEmpty())
+ return;
+
+ tasks.get(0).setExcludeFromRecents(true);
+ }
+
+ /**
+ * The activity referenced by cordova.
+ *
+ * @return The main activity of the app.
+ */
+ Activity getActivity() {
+ return cordova.get().getActivity();
+ }
+
+}
\ No newline at end of file
diff --git a/src/android/BackgroundMode.java b/src/android/BackgroundMode.java
new file mode 100644
index 0000000..aebb3ca
--- /dev/null
+++ b/src/android/BackgroundMode.java
@@ -0,0 +1,301 @@
+/*
+ Copyright 2013-2017 appPlant GmbH
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+package de.appplant.cordova.plugin.background;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaPlugin;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class BackgroundMode extends CordovaPlugin {
+
+ // Event types for callbacks
+ private enum Event {
+ ACTIVATE, DEACTIVATE, FAILURE
+ }
+
+ // Plugin namespace
+ private static final String JS_NAMESPACE =
+ "cordova.plugins.backgroundMode";
+
+ // Flag indicates if the app is in background or foreground
+ private boolean inBackground = false;
+
+ // Flag indicates if the plugin is enabled or disabled
+ private boolean isDisabled = true;
+
+ // Flag indicates if the service is bind
+ private boolean isBind = false;
+
+ // Default settings for the notification
+ private static JSONObject defaultSettings = new JSONObject();
+
+ // Service that keeps the app awake
+ private ForegroundService service;
+
+ // Used to (un)bind the service to with the activity
+ private final ServiceConnection connection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ ForegroundService.ForegroundBinder binder =
+ (ForegroundService.ForegroundBinder) service;
+
+ BackgroundMode.this.service = binder.getService();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ fireEvent(Event.FAILURE, "'service disconnected'");
+ }
+ };
+
+ /**
+ * Executes the request.
+ *
+ * @param action The action to execute.
+ * @param args The exec() arguments.
+ * @param callback The callback context used when
+ * calling back into JavaScript.
+ *
+ * @return Returning false results in a "MethodNotFound" error.
+ *
+ * @throws JSONException
+ */
+ @Override
+ public boolean execute (String action, JSONArray args,
+ CallbackContext callback) throws JSONException {
+
+ if (action.equalsIgnoreCase("configure")) {
+ JSONObject settings = args.getJSONObject(0);
+ boolean update = args.getBoolean(1);
+
+ configure(settings, update);
+ }
+ else
+ if (action.equalsIgnoreCase("enable")) {
+ enableMode();
+ }
+ else
+ if (action.equalsIgnoreCase("disable")) {
+ disableMode();
+ }
+ else {
+ BackgroundExt.execute(action, cordova, webView);
+ }
+
+ callback.success();
+
+ return true;
+ }
+
+ /**
+ * Called when the system is about to start resuming a previous activity.
+ *
+ * @param multitasking Flag indicating if multitasking is turned on for app.
+ */
+ @Override
+ public void onPause(boolean multitasking) {
+ super.onPause(multitasking);
+ inBackground = true;
+ startService();
+ }
+
+ /**
+ * Called when the activity will start interacting with the user.
+ *
+ * @param multitasking Flag indicating if multitasking is turned on for app.
+ */
+ @Override
+ public void onResume(boolean multitasking) {
+ super.onResume(multitasking);
+ inBackground = false;
+ stopService();
+ }
+
+ /**
+ * Called when the activity will be destroyed.
+ */
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ stopService();
+ }
+
+ /**
+ * Enable the background mode.
+ */
+ private void enableMode() {
+ isDisabled = false;
+
+ if (inBackground) {
+ startService();
+ }
+ }
+
+ /**
+ * Disable the background mode.
+ */
+ private void disableMode() {
+ stopService();
+ isDisabled = true;
+ }
+
+ /**
+ * Update the default settings and configure the notification.
+ *
+ * @param settings The settings
+ * @param update A truthy value means to update the running service.
+ */
+ private void configure(JSONObject settings, boolean update) {
+ if (update) {
+ updateNotification(settings);
+ } else {
+ setDefaultSettings(settings);
+ }
+ }
+
+ /**
+ * Update the default settings for the notification.
+ *
+ * @param settings The new default settings
+ */
+ private void setDefaultSettings(JSONObject settings) {
+ defaultSettings = settings;
+ }
+
+ /**
+ * The settings for the new/updated notification.
+ *
+ * @return
+ * updateSettings if set or default settings
+ */
+ protected static JSONObject getSettings() {
+ return defaultSettings;
+ }
+
+ /**
+ * Update the notification.
+ *
+ * @param settings The config settings
+ */
+ private void updateNotification(JSONObject settings) {
+ if (isBind) {
+ service.updateNotification(settings);
+ }
+ }
+
+ /**
+ * Bind the activity to a background service and put them into foreground
+ * state.
+ */
+ private void startService() {
+ Activity context = cordova.getActivity();
+
+ if (isDisabled || isBind)
+ return;
+
+ Intent intent = new Intent(
+ context, ForegroundService.class);
+
+ try {
+ context.bindService(intent,
+ connection, Context.BIND_AUTO_CREATE);
+
+ fireEvent(Event.ACTIVATE, null);
+
+ context.startService(intent);
+ } catch (Exception e) {
+ fireEvent(Event.FAILURE, String.format("'%s'", e.getMessage()));
+ }
+
+ isBind = true;
+ }
+
+ /**
+ * Bind the activity to a background service and put them into foreground
+ * state.
+ */
+ private void stopService() {
+ Activity context = cordova.getActivity();
+
+ Intent intent = new Intent(
+ context, ForegroundService.class);
+
+ if (!isBind)
+ return;
+
+ fireEvent(Event.DEACTIVATE, null);
+
+ context.unbindService(connection);
+ context.stopService(intent);
+
+ isBind = false;
+ }
+
+ /**
+ * Fire vent with some parameters inside the web view.
+ *
+ * @param event The name of the event
+ * @param params Optional arguments for the event
+ */
+ private void fireEvent (Event event, String params) {
+ String eventName;
+
+ switch (event) {
+ case ACTIVATE:
+ eventName = "activate"; break;
+ case DEACTIVATE:
+ eventName = "deactivate"; break;
+ default:
+ eventName = "failure";
+ }
+
+ String active = event == Event.ACTIVATE ? "true" : "false";
+
+ String flag = String.format("%s._isActive=%s;",
+ JS_NAMESPACE, active);
+
+ String depFn = String.format("%s.on%s(%s);",
+ JS_NAMESPACE, eventName, params);
+
+ String fn = String.format("%s.fireEvent('%s',%s);",
+ JS_NAMESPACE, eventName, params);
+
+ final String js = flag + fn + depFn;
+
+ cordova.getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ webView.loadUrl("javascript:" + js);
+ }
+ });
+ }
+
+}
diff --git a/src/android/ForegroundService.java b/src/android/ForegroundService.java
new file mode 100644
index 0000000..806c956
--- /dev/null
+++ b/src/android/ForegroundService.java
@@ -0,0 +1,323 @@
+/*
+ Copyright 2013 Sebastián Katzer
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+package de.appplant.cordova.plugin.background;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Binder;
+import android.os.Build;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.app.NotificationChannel;
+
+import org.json.JSONObject;
+
+import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
+
+/**
+ * Puts the service in a foreground state, where the system considers it to be
+ * something the user is actively aware of and thus not a candidate for killing
+ * when low on memory.
+ */
+public class ForegroundService extends Service {
+
+ // Fixed ID for the 'foreground' notification
+ public static final int NOTIFICATION_ID = -574543954;
+
+ // Default title of the background notification
+ private static final String NOTIFICATION_TITLE =
+ "App is running in background";
+
+ // Default text of the background notification
+ private static final String NOTIFICATION_TEXT =
+ "Doing heavy tasks.";
+
+ // Default icon of the background notification
+ private static final String NOTIFICATION_ICON = "icon";
+
+ // Binder given to clients
+ private final IBinder binder = new ForegroundBinder();
+
+ // Partial wake lock to prevent the app from going to sleep when locked
+ private PowerManager.WakeLock wakeLock;
+
+ /**
+ * Allow clients to call on to the service.
+ */
+ @Override
+ public IBinder onBind (Intent intent) {
+ return binder;
+ }
+
+ /**
+ * Class used for the client Binder. Because we know this service always
+ * runs in the same process as its clients, we don't need to deal with IPC.
+ */
+ class ForegroundBinder extends Binder
+ {
+ ForegroundService getService()
+ {
+ // Return this instance of ForegroundService
+ // so clients can call public methods
+ return ForegroundService.this;
+ }
+ }
+
+ /**
+ * Put the service in a foreground state to prevent app from being killed
+ * by the OS.
+ */
+ @Override
+ public void onCreate()
+ {
+ super.onCreate();
+ keepAwake();
+ }
+
+ /**
+ * No need to run headless on destroy.
+ */
+ @Override
+ public void onDestroy()
+ {
+ super.onDestroy();
+ sleepWell();
+ }
+
+ /**
+ * Prevent Android from stopping the background service automatically.
+ */
+ @Override
+ public int onStartCommand (Intent intent, int flags, int startId) {
+ return START_STICKY;
+ }
+
+ /**
+ * Put the service in a foreground state to prevent app from being killed
+ * by the OS.
+ */
+ @SuppressLint("WakelockTimeout")
+ private void keepAwake()
+ {
+ JSONObject settings = BackgroundMode.getSettings();
+ boolean isSilent = settings.optBoolean("silent", false);
+
+ if (!isSilent) {
+ startForeground(NOTIFICATION_ID, makeNotification());
+ }
+
+ PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE);
+
+ wakeLock = pm.newWakeLock(
+ PARTIAL_WAKE_LOCK, "backgroundmode:wakelock");
+
+ wakeLock.acquire();
+ }
+
+ /**
+ * Stop background mode.
+ */
+ private void sleepWell()
+ {
+ stopForeground(true);
+ getNotificationManager().cancel(NOTIFICATION_ID);
+
+ if (wakeLock != null) {
+ wakeLock.release();
+ wakeLock = null;
+ }
+ }
+
+ /**
+ * Create a notification as the visible part to be able to put the service
+ * in a foreground state by using the default settings.
+ */
+ private Notification makeNotification()
+ {
+ return makeNotification(BackgroundMode.getSettings());
+ }
+
+ /**
+ * Create a notification as the visible part to be able to put the service
+ * in a foreground state.
+ *
+ * @param settings The config settings
+ */
+ private Notification makeNotification (JSONObject settings)
+ {
+ // use channelid for Oreo and higher
+ String CHANNEL_ID = "cordova-plugin-background-mode-id";
+ if(Build.VERSION.SDK_INT >= 26){
+ // The user-visible name of the channel.
+ CharSequence name = "cordova-plugin-background-mode";
+ // The user-visible description of the channel.
+ String description = "cordova-plugin-background-moden notification";
+
+ int importance = NotificationManager.IMPORTANCE_LOW;
+
+ NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name,importance);
+
+ // Configure the notification channel.
+ mChannel.setDescription(description);
+
+ getNotificationManager().createNotificationChannel(mChannel);
+ }
+ String title = settings.optString("title", NOTIFICATION_TITLE);
+ String text = settings.optString("text", NOTIFICATION_TEXT);
+ boolean bigText = settings.optBoolean("bigText", false);
+
+ Context context = getApplicationContext();
+ String pkgName = context.getPackageName();
+ Intent intent = context.getPackageManager()
+ .getLaunchIntentForPackage(pkgName);
+
+ Notification.Builder notification = new Notification.Builder(context)
+ .setContentTitle(title)
+ .setContentText(text)
+ .setOngoing(true)
+ .setSmallIcon(getIconResId(settings));
+
+ if(Build.VERSION.SDK_INT >= 26){
+ notification.setChannelId(CHANNEL_ID);
+ }
+
+ if (settings.optBoolean("hidden", true)) {
+ notification.setPriority(Notification.PRIORITY_MIN);
+ }
+
+ if (bigText || text.contains("\n")) {
+ notification.setStyle(
+ new Notification.BigTextStyle().bigText(text));
+ }
+
+ setColor(notification, settings);
+
+ if (intent != null && settings.optBoolean("resume")) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ PendingIntent contentIntent = PendingIntent.getActivity(
+ context, NOTIFICATION_ID, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+
+ notification.setContentIntent(contentIntent);
+ }
+
+ return notification.build();
+ }
+
+ /**
+ * Update the notification.
+ *
+ * @param settings The config settings
+ */
+ protected void updateNotification (JSONObject settings)
+ {
+ boolean isSilent = settings.optBoolean("silent", false);
+
+ if (isSilent) {
+ stopForeground(true);
+ return;
+ }
+
+ Notification notification = makeNotification(settings);
+ getNotificationManager().notify(NOTIFICATION_ID, notification);
+
+ }
+
+ /**
+ * Retrieves the resource ID of the app icon.
+ *
+ * @param settings A JSON dict containing the icon name.
+ */
+ private int getIconResId (JSONObject settings)
+ {
+ String icon = settings.optString("icon", NOTIFICATION_ICON);
+
+ int resId = getIconResId(icon, "mipmap");
+
+ if (resId == 0) {
+ resId = getIconResId(icon, "drawable");
+ }
+
+ return resId;
+ }
+
+ /**
+ * Retrieve resource id of the specified icon.
+ *
+ * @param icon The name of the icon.
+ * @param type The resource type where to look for.
+ *
+ * @return The resource id or 0 if not found.
+ */
+ private int getIconResId (String icon, String type)
+ {
+ Resources res = getResources();
+ String pkgName = getPackageName();
+
+ int resId = res.getIdentifier(icon, type, pkgName);
+
+ if (resId == 0) {
+ resId = res.getIdentifier("icon", type, pkgName);
+ }
+
+ return resId;
+ }
+
+ /**
+ * Set notification color if its supported by the SDK.
+ *
+ * @param notification A Notification.Builder instance
+ * @param settings A JSON dict containing the color definition (red: FF0000)
+ */
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private void setColor (Notification.Builder notification, JSONObject settings)
+ {
+
+ String hex = settings.optString("color", null);
+
+ if (Build.VERSION.SDK_INT < 21 || hex == null)
+ return;
+
+ try {
+ int aRGB = Integer.parseInt(hex, 16) + 0xFF000000;
+ notification.setColor(aRGB);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Returns the shared notification service manager.
+ */
+ private NotificationManager getNotificationManager()
+ {
+ return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+ }
+}
diff --git a/src/browser/BackgroundModeProxy.js b/src/browser/BackgroundModeProxy.js
new file mode 100644
index 0000000..5ba7880
--- /dev/null
+++ b/src/browser/BackgroundModeProxy.js
@@ -0,0 +1,49 @@
+/*
+ Copyright 2013-2017 appPlant GmbH
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+/**
+ * Activates the background mode. When activated the application
+ * will be prevented from going to sleep while in background
+ * for the next time.
+ *
+ * @param [ Function ] success The success callback to use.
+ * @param [ Function ] error The error callback to use.
+ *
+ * @return [ Void ]
+ */
+exports.enable = function (success, error) {
+ success();
+};
+
+/**
+ * Deactivates the background mode. When deactivated the application
+ * will not stay awake while in background.
+ *
+ * @param [ Function ] success The success callback to use.
+ * @param [ Function ] error The error callback to use.
+ *
+ * @return [ Void ]
+ */
+exports.disable = function (success, error) {
+ success();
+};
+
+cordova.commandProxy.add('BackgroundMode', exports);
diff --git a/src/ios/APPBackgroundMode.h b/src/ios/APPBackgroundMode.h
new file mode 100644
index 0000000..e7ed1e5
--- /dev/null
+++ b/src/ios/APPBackgroundMode.h
@@ -0,0 +1,35 @@
+/*
+ Copyright 2013-2017 appPlant GmbH
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+#import
+#import
+
+@interface APPBackgroundMode : CDVPlugin {
+ AVAudioPlayer* audioPlayer;
+ BOOL enabled;
+}
+
+// Activate the background mode
+- (void) enable:(CDVInvokedUrlCommand*)command;
+// Deactivate the background mode
+- (void) disable:(CDVInvokedUrlCommand*)command;
+
+@end
diff --git a/src/ios/APPBackgroundMode.m b/src/ios/APPBackgroundMode.m
new file mode 100644
index 0000000..0e05666
--- /dev/null
+++ b/src/ios/APPBackgroundMode.m
@@ -0,0 +1,277 @@
+/*
+ Copyright 2013-2017 appPlant GmbH
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+#import "APPMethodMagic.h"
+#import "APPBackgroundMode.h"
+#import
+
+@implementation APPBackgroundMode
+
+#pragma mark -
+#pragma mark Constants
+
+NSString* const kAPPBackgroundJsNamespace = @"cordova.plugins.backgroundMode";
+NSString* const kAPPBackgroundEventActivate = @"activate";
+NSString* const kAPPBackgroundEventDeactivate = @"deactivate";
+
+
+#pragma mark -
+#pragma mark Life Cycle
+
+/**
+ * Called by runtime once the Class has been loaded.
+ * Exchange method implementations to hook into their execution.
+ */
++ (void) load
+{
+ [self swizzleWKWebViewEngine];
+}
+
+/**
+ * Initialize the plugin.
+ */
+- (void) pluginInitialize
+{
+ enabled = NO;
+ [self configureAudioPlayer];
+ [self configureAudioSession];
+ [self observeLifeCycle];
+}
+
+/**
+ * Register the listener for pause and resume events.
+ */
+- (void) observeLifeCycle
+{
+ NSNotificationCenter* listener = [NSNotificationCenter
+ defaultCenter];
+
+ [listener addObserver:self
+ selector:@selector(keepAwake)
+ name:UIApplicationDidEnterBackgroundNotification
+ object:nil];
+
+ [listener addObserver:self
+ selector:@selector(stopKeepingAwake)
+ name:UIApplicationWillEnterForegroundNotification
+ object:nil];
+
+ [listener addObserver:self
+ selector:@selector(handleAudioSessionInterruption:)
+ name:AVAudioSessionInterruptionNotification
+ object:nil];
+}
+
+#pragma mark -
+#pragma mark Interface
+
+/**
+ * Enable the mode to stay awake
+ * when switching to background for the next time.
+ */
+- (void) enable:(CDVInvokedUrlCommand*)command
+{
+ if (enabled)
+ return;
+
+ enabled = YES;
+ [self execCallback:command];
+}
+
+/**
+ * Disable the background mode
+ * and stop being active in background.
+ */
+- (void) disable:(CDVInvokedUrlCommand*)command
+{
+ if (!enabled)
+ return;
+
+ enabled = NO;
+ [self stopKeepingAwake];
+ [self execCallback:command];
+}
+
+#pragma mark -
+#pragma mark Core
+
+/**
+ * Keep the app awake.
+ */
+- (void) keepAwake
+{
+ if (!enabled)
+ return;
+
+ [audioPlayer play];
+ [self fireEvent:kAPPBackgroundEventActivate];
+}
+
+/**
+ * Let the app going to sleep.
+ */
+- (void) stopKeepingAwake
+{
+ if (TARGET_IPHONE_SIMULATOR) {
+ NSLog(@"BackgroundMode: On simulator apps never pause in background!");
+ }
+
+ if (audioPlayer.isPlaying) {
+ [self fireEvent:kAPPBackgroundEventDeactivate];
+ }
+
+ [audioPlayer pause];
+}
+
+/**
+ * Configure the audio player.
+ */
+- (void) configureAudioPlayer
+{
+ NSString* path = [[NSBundle mainBundle]
+ pathForResource:@"appbeep" ofType:@"wav"];
+
+ NSURL* url = [NSURL fileURLWithPath:path];
+
+
+ audioPlayer = [[AVAudioPlayer alloc]
+ initWithContentsOfURL:url error:NULL];
+
+ audioPlayer.volume = 0;
+ audioPlayer.numberOfLoops = -1;
+};
+
+/**
+ * Configure the audio session.
+ */
+- (void) configureAudioSession
+{
+ AVAudioSession* session = [AVAudioSession
+ sharedInstance];
+
+ // Don't activate the audio session yet
+ [session setActive:NO error:NULL];
+
+ // Play music even in background and dont stop playing music
+ // even another app starts playing sound
+ [session setCategory:AVAudioSessionCategoryPlayback
+ withOptions:AVAudioSessionCategoryOptionMixWithOthers
+ error:NULL];
+
+ // Active the audio session
+ [session setActive:YES error:NULL];
+};
+
+#pragma mark -
+#pragma mark Helper
+
+/**
+ * Simply invokes the callback without any parameter.
+ */
+- (void) execCallback:(CDVInvokedUrlCommand*)command
+{
+ CDVPluginResult *result = [CDVPluginResult
+ resultWithStatus:CDVCommandStatus_OK];
+
+ [self.commandDelegate sendPluginResult:result
+ callbackId:command.callbackId];
+}
+
+/**
+ * Restart playing sound when interrupted by phone calls.
+ */
+- (void) handleAudioSessionInterruption:(NSNotification*)notification
+{
+ [self fireEvent:kAPPBackgroundEventDeactivate];
+ [self keepAwake];
+}
+
+/**
+ * Find out if the app runs inside the webkit powered webview.
+ */
++ (BOOL) isRunningWebKit
+{
+ return IsAtLeastiOSVersion(@"8.0") && NSClassFromString(@"CDVWKWebViewEngine");
+}
+
+/**
+ * Method to fire an event with some parameters in the browser.
+ */
+- (void) fireEvent:(NSString*)event
+{
+ NSString* active =
+ [event isEqualToString:kAPPBackgroundEventActivate] ? @"true" : @"false";
+
+ NSString* flag = [NSString stringWithFormat:@"%@._isActive=%@;",
+ kAPPBackgroundJsNamespace, active];
+
+ NSString* depFn = [NSString stringWithFormat:@"%@.on%@();",
+ kAPPBackgroundJsNamespace, event];
+
+ NSString* fn = [NSString stringWithFormat:@"%@.fireEvent('%@');",
+ kAPPBackgroundJsNamespace, event];
+
+ NSString* js = [NSString stringWithFormat:@"%@%@%@", flag, depFn, fn];
+
+ [self.commandDelegate evalJs:js];
+}
+
+#pragma mark -
+#pragma mark Swizzling
+
+/**
+ * Method to swizzle.
+ */
++ (NSString*) wkProperty
+{
+ NSString* str = @"YWx3YXlzUnVuc0F0Rm9yZWdyb3VuZFByaW9yaXR5";
+ NSData* data = [[NSData alloc] initWithBase64EncodedString:str options:0];
+
+ return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+}
+
+/**
+ * Swizzle some implementations of CDVWKWebViewEngine.
+ */
++ (void) swizzleWKWebViewEngine
+{
+ if (![self isRunningWebKit])
+ return;
+
+ Class wkWebViewEngineCls = NSClassFromString(@"CDVWKWebViewEngine");
+ SEL selector = NSSelectorFromString(@"createConfigurationFromSettings:");
+
+ SwizzleSelectorWithBlock_Begin(wkWebViewEngineCls, selector)
+ ^(CDVPlugin *self, NSDictionary *settings) {
+ id obj = ((id (*)(id, SEL, NSDictionary*))_imp)(self, _cmd, settings);
+
+ [obj setValue:[NSNumber numberWithBool:YES]
+ forKey:[APPBackgroundMode wkProperty]];
+
+ [obj setValue:[NSNumber numberWithBool:NO]
+ forKey:@"requiresUserActionForMediaPlayback"];
+
+ return obj;
+ }
+ SwizzleSelectorWithBlock_End;
+}
+
+@end
diff --git a/src/ios/APPMethodMagic.h b/src/ios/APPMethodMagic.h
new file mode 100644
index 0000000..84de791
--- /dev/null
+++ b/src/ios/APPMethodMagic.h
@@ -0,0 +1,93 @@
+/*
+ Copyright 2013-2017 appPlant GmbH
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+/**
+ * Code extracted from
+ * - http://defagos.github.io/yet_another_article_about_method_swizzling/
+ * - https://gist.github.com/defagos/1312fec96b48540efa5c
+ */
+
+#import
+#import
+
+#define SwizzleSelector(clazz, selector, newImpl, oldImpl) \
+(*oldImpl) = (__typeof((*oldImpl)))class_swizzleSelector((clazz), (selector), (IMP)(newImpl))
+
+#define SwizzleClassSelector(clazz, selector, newImpl, oldImpl) \
+(*oldImpl) = (__typeof((*oldImpl)))class_swizzleClassSelector((clazz), (selector), (IMP)(newImpl))
+
+#define SwizzleSelectorWithBlock_Begin(clazz, selector) { \
+SEL _cmd = selector; \
+__block IMP _imp = class_swizzleSelectorWithBlock((clazz), (selector),
+#define SwizzleSelectorWithBlock_End );}
+
+#define SwizzleClassSelectorWithBlock_Begin(clazz, selector) { \
+SEL _cmd = selector; \
+__block IMP _imp = class_swizzleClassSelectorWithBlock((clazz), (selector),
+#define SwizzleClassSelectorWithBlock_End );}
+
+/**
+ * Swizzle class method specified by class and selector
+ * through the provided method implementation.
+ *
+ * @param [ Class ] clazz The class containing the method.
+ * @param [ SEL ] selector The selector of the method.
+ * @param [ IMP ] newImpl The new implementation of the method.
+ *
+ * @return [ IMP ] The previous implementation of the method.
+ */
+IMP class_swizzleClassSelector(Class clazz, SEL selector, IMP newImpl);
+
+/**
+ * Swizzle class method specified by class and selector
+ * through the provided code block.
+ *
+ * @param [ Class ] clazz The class containing the method.
+ * @param [ SEL ] selector The selector of the method.
+ * @param [ id ] newImplBlock The new implementation of the method.
+ *
+ * @return [ IMP ] The previous implementation of the method.
+ */
+IMP class_swizzleClassSelectorWithBlock(Class clazz, SEL selector, id newImplBlock);
+
+/**
+ * Swizzle method specified by class and selector
+ * through the provided code block.
+ *
+ * @param [ Class ] clazz The class containing the method.
+ * @param [ SEL ] selector The selector of the method.
+ * @param [ id ] newImplBlock The new implementation of the method.
+ *
+ * @return [ IMP ] The previous implementation of the method.
+ */
+IMP class_swizzleSelectorWithBlock(Class clazz, SEL selector, id newImplBlock);
+
+/**
+ * Swizzle method specified by class and selector
+ * through the provided method implementation.
+ *
+ * @param [ Class ] clazz The class containing the method.
+ * @param [ SEL ] selector The selector of the method.
+ * @param [ IMP ] newImpl The new implementation of the method.
+ *
+ * @return [ IMP ] The previous implementation of the method.
+ */
+IMP class_swizzleSelector(Class clazz, SEL selector, IMP newImpl);
diff --git a/src/ios/APPMethodMagic.m b/src/ios/APPMethodMagic.m
new file mode 100644
index 0000000..cb9cc35
--- /dev/null
+++ b/src/ios/APPMethodMagic.m
@@ -0,0 +1,105 @@
+/*
+ Copyright 2013-2017 appPlant GmbH
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+/**
+ * Code extracted from
+ * - http://defagos.github.io/yet_another_article_about_method_swizzling/
+ * - https://gist.github.com/defagos/1312fec96b48540efa5c
+ */
+
+#import "APPMethodMagic.h"
+#import
+#import
+
+/**
+ * Swizzle class method specified by class and selector
+ * through the provided method implementation.
+ *
+ * @param [ Class ] clazz The class containing the method.
+ * @param [ SEL ] selector The selector of the method.
+ * @param [ IMP ] newImpl The new implementation of the method.
+ *
+ * @return [ IMP ] The previous implementation of the method.
+ */
+IMP class_swizzleClassSelector(Class clazz, SEL selector, IMP newImpl)
+{
+ return class_swizzleSelector(object_getClass(clazz), selector, newImpl);
+}
+
+/**
+ * Swizzle class method specified by class and selector
+ * through the provided code block.
+ *
+ * @param [ Class ] clazz The class containing the method.
+ * @param [ SEL ] selector The selector of the method.
+ * @param [ id ] newImplBlock The new implementation of the method.
+ *
+ * @return [ IMP ] The previous implementation of the method.
+ */
+IMP class_swizzleClassSelectorWithBlock(Class clazz, SEL selector, id newImplBlock)
+{
+ IMP newImpl = imp_implementationWithBlock(newImplBlock);
+ return class_swizzleClassSelector(clazz, selector, newImpl);
+}
+
+/**
+ * Swizzle method specified by class and selector
+ * through the provided code block.
+ *
+ * @param [ Class ] clazz The class containing the method.
+ * @param [ SEL ] selector The selector of the method.
+ * @param [ id ] newImplBlock The new implementation of the method.
+ *
+ * @return [ IMP ] The previous implementation of the method.
+ */
+IMP class_swizzleSelectorWithBlock(Class clazz, SEL selector, id newImplBlock)
+{
+ IMP newImpl = imp_implementationWithBlock(newImplBlock);
+ return class_swizzleSelector(clazz, selector, newImpl);
+}
+
+/**
+ * Swizzle method specified by class and selector
+ * through the provided method implementation.
+ *
+ * @param [ Class ] clazz The class containing the method.
+ * @param [ SEL ] selector The selector of the method.
+ * @param [ IMP ] newImpl The new implementation of the method.
+ *
+ * @return [ IMP ] The previous implementation of the method.
+ */
+IMP class_swizzleSelector(Class clazz, SEL selector, IMP newImpl)
+{
+ Method method = class_getInstanceMethod(clazz, selector);
+ const char *types = method_getTypeEncoding(method);
+
+ class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) {
+ struct objc_super super = {
+ .receiver = self,
+ .super_class = class_getSuperclass(clazz)
+ };
+
+ id (*objc_msgSendSuper_typed)(struct objc_super*, SEL, va_list) = (void*)&objc_msgSendSuper;
+ return objc_msgSendSuper_typed(&super, selector, argp);
+ }), types);
+
+ return class_replaceMethod(clazz, selector, newImpl, types);
+}
diff --git a/src/windows/BackgroundModeProxy.js b/src/windows/BackgroundModeProxy.js
new file mode 100644
index 0000000..5542e3f
--- /dev/null
+++ b/src/windows/BackgroundModeProxy.js
@@ -0,0 +1,123 @@
+/*
+ Copyright 2013-2017 appPlant GmbH
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+var plugin = cordova.plugins.backgroundMode;
+
+var Uri = Windows.Foundation.Uri,
+ MediaSource = Windows.Media.Core.MediaSource,
+ MediaPlaybackItem = Windows.Media.Playback.MediaPlaybackItem,
+ MediaPlaybackList = Windows.Media.Playback.MediaPlaybackList,
+ AudioCategory = Windows.Media.Playback.MediaPlayerAudioCategory,
+ MediaPlayer = Windows.Media.Playback.MediaPlayer,
+ WebUIApplication = Windows.UI.WebUI.WebUIApplication;
+
+/**
+ * Activates the background mode. When activated the application
+ * will be prevented from going to sleep while in background
+ * for the next time.
+ *
+ * @param [ Function ] success The success callback to use.
+ * @param [ Function ] error The error callback to use.
+ *
+ * @return [ Void ]
+ */
+exports.enable = function (success, error) {
+ success();
+};
+
+/**
+ * Deactivates the background mode. When deactivated the application
+ * will not stay awake while in background.
+ *
+ * @param [ Function ] success The success callback to use.
+ * @param [ Function ] error The error callback to use.
+ *
+ * @return [ Void ]
+ */
+exports.disable = function (success, error) {
+ exports.stopKeepingAwake();
+ success();
+};
+
+/**
+ * Keep the app awake.
+ *
+ * @return [ Void ]
+ */
+exports.keepAwake = function () {
+ if (!plugin.isEnabled() || plugin.isActive())
+ return;
+
+ exports.configureAudioPlayer();
+ exports.audioPlayer.play();
+
+ plugin._isActive = true;
+ plugin.fireEvent('activate');
+};
+
+/**
+ * Let the app going to sleep.
+ *
+ * @return [ Void ]
+ */
+exports.stopKeepingAwake = function () {
+ if (!exports.audioPlayer)
+ return;
+
+ exports.audioPlayer.close();
+ exports.audioPlayer = null;
+
+ cordova.plugins.backgroundMode._isActive = false;
+ cordova.plugins.backgroundMode.fireEvent('deactivate');
+};
+
+/**
+ * Configure the audio player for playback in background.
+ *
+ * @return [ Void ]
+ */
+exports.configureAudioPlayer = function () {
+ if (exports.audioPlayer)
+ return;
+
+ var pkg = Windows.ApplicationModel.Package.current,
+ pkgName = pkg.id.name;
+
+ var audioPlayer = new MediaPlayer(),
+ audioFile = new Uri('ms-appx://' + pkgName + '/appbeep.wma'),
+ audioSource = MediaSource.createFromUri(audioFile),
+ playList = new MediaPlaybackList();
+
+ playList.items.append(new MediaPlaybackItem(audioSource));
+ playList.autoRepeatEnabled = true;
+
+ audioPlayer.source = playList;
+ audioPlayer.autoPlay = false;
+ audioPlayer.audioCategory = AudioCategory.soundEffects;
+ audioPlayer.volume = 0;
+
+ exports.audioPlayer = audioPlayer;
+};
+
+WebUIApplication.addEventListener('enteredbackground', exports.keepAwake, false);
+WebUIApplication.addEventListener('leavingbackground', exports.stopKeepingAwake, false);
+
+cordova.commandProxy.add('BackgroundMode', exports);
diff --git a/www/background-mode.js b/www/background-mode.js
new file mode 100644
index 0000000..7dcdff3
--- /dev/null
+++ b/www/background-mode.js
@@ -0,0 +1,403 @@
+/*
+ Copyright 2013-2017 appPlant GmbH
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var exec = require('cordova/exec'),
+ channel = require('cordova/channel');
+
+
+/*************
+ * INTERFACE *
+ *************/
+
+/**
+ * Activates the background mode. When activated the application
+ * will be prevented from going to sleep while in background
+ * for the next time.
+ *
+ * @return [ Void ]
+ */
+exports.enable = function () {
+ if (this.isEnabled())
+ return;
+
+ var fn = function () {
+ exports._isEnabled = true;
+ exports.fireEvent('enable');
+ };
+
+ cordova.exec(fn, null, 'BackgroundMode', 'enable', []);
+};
+
+/**
+ * Deactivates the background mode. When deactivated the application
+ * will not stay awake while in background.
+ *
+ * @return [ Void ]
+ */
+exports.disable = function () {
+ if (!this.isEnabled())
+ return;
+
+ var fn = function () {
+ exports._isEnabled = false;
+ exports.fireEvent('disable');
+ };
+
+ cordova.exec(fn, null, 'BackgroundMode', 'disable', []);
+};
+
+/**
+ * Enable or disable the background mode.
+ *
+ * @param [ Bool ] enable The status to set for.
+ *
+ * @return [ Void ]
+ */
+exports.setEnabled = function (enable) {
+ if (enable) {
+ this.enable();
+ } else {
+ this.disable();
+ }
+};
+
+/**
+ * List of all available options with their default value.
+ *
+ * @return [ Object ]
+ */
+exports.getDefaults = function () {
+ return this._defaults;
+};
+
+/**
+ * Overwrite the default settings.
+ *
+ * @param [ Object ] overrides Dict of options to be overridden.
+ *
+ * @return [ Void ]
+ */
+exports.setDefaults = function (overrides) {
+ var defaults = this.getDefaults();
+
+ for (var key in defaults) {
+ if (overrides.hasOwnProperty(key)) {
+ defaults[key] = overrides[key];
+ }
+ }
+
+ if (this._isAndroid) {
+ cordova.exec(null, null, 'BackgroundMode', 'configure', [defaults, false]);
+ }
+};
+
+/**
+ * Configures the notification settings for Android.
+ * Will be merged with the defaults.
+ *
+ * @param [ Object ] overrides Dict of options to be overridden.
+ *
+ * @return [ Void ]
+ */
+exports.configure = function (options) {
+ var settings = this.mergeWithDefaults(options);
+
+ if (this._isAndroid) {
+ cordova.exec(null, null, 'BackgroundMode', 'configure', [settings, true]);
+ }
+};
+
+/**
+ * Enable GPS-tracking in background (Android).
+ *
+ * @return [ Void ]
+ */
+exports.disableWebViewOptimizations = function () {
+ if (this._isAndroid) {
+ cordova.exec(null, null, 'BackgroundMode', 'optimizations', []);
+ }
+};
+
+/**
+ * Move app to background (Android only).
+ *
+ * @return [ Void ]
+ */
+exports.moveToBackground = function () {
+ if (this._isAndroid) {
+ cordova.exec(null, null, 'BackgroundMode', 'background', []);
+ }
+};
+
+/**
+ * Move app to foreground when in background (Android only).
+ *
+ * @return [ Void ]
+ */
+exports.moveToForeground = function () {
+ if (this.isActive() && this._isAndroid) {
+ cordova.exec(null, null, 'BackgroundMode', 'foreground', []);
+ }
+};
+
+/**
+ * Exclude the app from the recent tasks list (Android only).
+ *
+ * @return [ Void ]
+ */
+exports.excludeFromTaskList = function () {
+ if (this._isAndroid) {
+ cordova.exec(null, null, 'BackgroundMode', 'tasklist', []);
+ }
+};
+
+/**
+ * Override the back button on Android to go to background
+ * instead of closing the app.
+ *
+ * @return [ Void ]
+ */
+exports.overrideBackButton = function () {
+ document.addEventListener('backbutton', function() {
+ exports.moveToBackground();
+ }, false);
+};
+
+/**
+ * If the mode is enabled or disabled.
+ *
+ * @return [ Boolean ]
+ */
+exports.isEnabled = function () {
+ return this._isEnabled !== false;
+};
+
+/**
+ * If the mode is active.
+ *
+ * @return [ Boolean ]
+ */
+exports.isActive = function () {
+ return this._isActive !== false;
+};
+
+
+/**********
+ * EVENTS *
+ **********/
+
+exports._listener = {};
+
+/**
+ * Fire event with given arguments.
+ *
+ * @param [ String ] event The event's name.
+ * @param [ Array