From 89db41ccf92d5fee5cdc0dfa441bf110e318e6fc Mon Sep 17 00:00:00 2001
From: kitolog
Date: Fri, 7 Dec 2018 17:18:56 +0300
Subject: [PATCH 1/7] Updated package.json
---
CHANGELOG.md | 4 +---
README.md | 3 ++-
package.json | 8 ++++----
plugin.xml | 6 +++---
4 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 16414726..cbd2082c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,6 @@
## ChangeLog
#### Version 0.7.3 (not yet released)
-- Check if screen is off on Android
-- Wake-up device on Android
-- Unlock device on Android
+- fixed iOS crashes
#### Version 0.7.2 (02.02.2017)
- Fixed app freeze on iOS using wkwebview-engine
diff --git a/README.md b/README.md
index bde896a8..f62be5c8 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,9 @@
SAMPLE APP :point_right:
-Cordova Background Plugin [](http://badge.fury.io/js/cordova-plugin-background-mode) [](https://travis-ci.org/katzer/cordova-plugin-background-mode) [](https://codebeat.co/projects/github-com-katzer-cordova-plugin-background-mode)
+Cordova Background Plugin iOS Fix [](http://badge.fury.io/js/cordova-plugin-background-mode) [](https://travis-ci.org/katzer/cordova-plugin-background-mode) [](https://codebeat.co/projects/github-com-katzer-cordova-plugin-background-mode)
=========================
+[cordova-plugin-background-mode](https://github.com/katzer/cordova-plugin-background-mode) fork. Fixed iOS crashes
Plugin for the [Cordova][cordova] framework to perform infinite background execution.
diff --git a/package.json b/package.json
index ebbedf34..9589a4df 100644
--- a/package.json
+++ b/package.json
@@ -1,9 +1,9 @@
{
- "name": "cordova-plugin-background-mode",
- "version": "0.7.2",
- "description": "Prevent apps from going to sleep in background.",
+ "name": "cordova-plugin-background-mode-fixed",
+ "version": "0.7.3",
+ "description": "Prevent apps from going to sleep in background. iOS fix.",
"cordova": {
- "id": "cordova-plugin-background-mode",
+ "id": "cordova-plugin-background-mode-fixed",
"platforms": [
"ios",
"android",
diff --git a/plugin.xml b/plugin.xml
index 52bd90e9..718c2ab4 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -2,12 +2,12 @@
+ id="cordova-plugin-background-mode-fixed"
+ version="0.7.3">
BackgroundMode
- Prevent apps from going to sleep in background.
+ Prevent apps from going to sleep in background. iOS fix.
https://github.com/katzer/cordova-plugin-background-mode.git
From 67ab6e840314703d40faabd1a189ab8bd6c0b807 Mon Sep 17 00:00:00 2001
From: kitolog
Date: Mon, 8 Apr 2019 13:56:44 +0300
Subject: [PATCH 2/7] Version 0.7.4. Merged Android updates, added iOS 12.2 fix
---
.gitignore | 23 ++
CHANGELOG.md | 9 +-
README.md | 1 +
package.json | 2 +-
plugin.xml | 12 +-
src/android/BackgroundExt.java | 332 ---------------------
src/android/BackgroundMode.java | 173 +++++------
src/android/BackgroundModeExt.java | 445 +++++++++++++++++++++++++++++
src/android/ForegroundService.java | 122 +++++---
src/browser/BackgroundModeProxy.js | 30 +-
src/ios/APPBackgroundMode.m | 2 +-
src/windows/BackgroundModeProxy.js | 36 +--
www/background-mode.js | 238 ++++++++-------
13 files changed, 827 insertions(+), 598 deletions(-)
create mode 100644 .gitignore
delete mode 100644 src/android/BackgroundExt.java
create mode 100644 src/android/BackgroundModeExt.java
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..8aab9a9d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,23 @@
+# Specifies intentionally untracked files to ignore when using Git
+# http://git-scm.com/docs/gitignore
+
+*~
+*.sw[mnpcod]
+*.log
+*.tmp
+*.tmp.*
+log.txt
+*.sublime-project
+*.sublime-workspace
+.vscode/
+npm-debug.log*
+
+.idea/
+.sourcemaps/
+.sass-cache/
+.tmp/
+tmp/
+$RECYCLE.BIN/
+
+.DS_Store
+Thumbs.db
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cbd2082c..9d91858b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,13 @@
## ChangeLog
-#### Version 0.7.3 (not yet released)
+#### Version 0.7.4
+- Fixed iOS 12.2 crashes
+- Merged original repository Android source updates
+
+#### Version 0.7.3
- fixed iOS crashes
+- Check if screen is off on Android
+- Wake-up device on Android
+- Unlock device on Android
#### Version 0.7.2 (02.02.2017)
- Fixed app freeze on iOS using wkwebview-engine
diff --git a/README.md b/README.md
index f62be5c8..d1c760f1 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,7 @@
Cordova Background Plugin iOS Fix [](http://badge.fury.io/js/cordova-plugin-background-mode) [](https://travis-ci.org/katzer/cordova-plugin-background-mode) [](https://codebeat.co/projects/github-com-katzer-cordova-plugin-background-mode)
+Implemented ios 12.2 fix
=========================
[cordova-plugin-background-mode](https://github.com/katzer/cordova-plugin-background-mode) fork. Fixed iOS crashes
diff --git a/package.json b/package.json
index 9589a4df..ef185e90 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "cordova-plugin-background-mode-fixed",
- "version": "0.7.3",
+ "version": "0.7.4",
"description": "Prevent apps from going to sleep in background. iOS fix.",
"cordova": {
"id": "cordova-plugin-background-mode-fixed",
diff --git a/plugin.xml b/plugin.xml
index 718c2ab4..79654026 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -3,7 +3,7 @@
+ version="0.7.4">
BackgroundMode
@@ -59,9 +59,11 @@
-
-
+
+
+
+
+
@@ -82,7 +84,7 @@
target-dir="src/de/appplant/cordova/plugin/background" />
cordova;
-
- // Weak reference to the cordova web view passed by the plugin
- private final WeakReference webView;
-
- private PowerManager.WakeLock wakeLock;
-
- /**
- * Initialize the extension to perform non-background related tasks.
- *
- * @param plugin The cordova plugin.
- */
- private BackgroundExt(CordovaPlugin plugin) {
- this.cordova = new WeakReference(plugin.cordova);
- this.webView = new WeakReference(plugin.webView);
- }
-
- /**
- * Executes the request asynchronous.
- *
- * @param plugin The cordova plugin.
- * @param action The action to execute.
- * @param callback The callback context used when
- * calling back into JavaScript.
- */
- @SuppressWarnings("UnusedParameters")
- static void execute (CordovaPlugin plugin, final String action,
- final CallbackContext callback) {
-
- final BackgroundExt ext = new BackgroundExt(plugin);
-
- plugin.cordova.getThreadPool().execute(new Runnable() {
- @Override
- public void run() {
- ext.execute(action, callback);
- }
- });
- }
-
- // codebeat:disable[ABC]
-
- /**
- * Executes the request.
- *
- * @param action The action to execute.
- * @param callback The callback context used when
- * calling back into JavaScript.
- */
- private void execute (String action, CallbackContext callback) {
-
- if (action.equalsIgnoreCase("optimizations")) {
- disableWebViewOptimizations();
- }
-
- if (action.equalsIgnoreCase("background")) {
- moveToBackground();
- }
-
- if (action.equalsIgnoreCase("foreground")) {
- moveToForeground();
- }
-
- if (action.equalsIgnoreCase("tasklist")) {
- excludeFromTaskList();
- }
-
- if (action.equalsIgnoreCase("dimmed")) {
- isDimmed(callback);
- }
-
- if (action.equalsIgnoreCase("wakeup")) {
- wakeup();
- }
-
- if (action.equalsIgnoreCase("unlock")) {
- wakeup();
- unlock();
- }
- }
-
- // codebeat:enable[ABC]
-
- /**
- * Move app to background.
- */
- private void moveToBackground() {
- Intent intent = new Intent(Intent.ACTION_MAIN);
-
- intent.addCategory(Intent.CATEGORY_HOME);
- getApp().startActivity(intent);
- }
-
- /**
- * Move app to foreground.
- */
- private void moveToForeground() {
- Activity app = getApp();
- Intent intent = getLaunchIntent();
-
- 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);
- getApp().runOnUiThread(new Runnable() {
- @Override
- public void run() {
- View view = webView.get().getEngine().getView();
-
- try {
- Class.forName("org.crosswalk.engine.XWalkCordovaView")
- .getMethod("onShow")
- .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) getService(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);
- }
-
- /**
- * Invoke the callback with information if the screen is on.
- *
- * @param callback The callback to invoke.
- */
- @SuppressWarnings("deprecation")
- private void isDimmed(CallbackContext callback) {
- PluginResult result = new PluginResult(Status.OK, isDimmed());
- callback.sendPluginResult(result);
- }
-
- /**
- * If the screen is active.
- */
- @SuppressWarnings("deprecation")
- private boolean isDimmed() {
- PowerManager pm = (PowerManager) getService(POWER_SERVICE);
-
- if (Build.VERSION.SDK_INT < 20) {
- return !pm.isScreenOn();
- }
-
- return !pm.isInteractive();
- }
-
- /**
- * Wakes up the device if the screen isn't still on.
- */
- private void wakeup() {
- try {
- acquireWakeLock();
- } catch (Exception e) {
- releaseWakeLock();
- }
- }
-
- /**
- * Unlocks the device even with password protection.
- */
- private void unlock() {
- Intent intent = getLaunchIntent();
- getApp().startActivity(intent);
- }
-
- /**
- * Acquire a wake lock to wake up the device.
- */
- private void acquireWakeLock() {
- PowerManager pm = (PowerManager) getService(POWER_SERVICE);
-
- releaseWakeLock();
-
- if (!isDimmed()) {
- return;
- }
-
- int level = PowerManager.SCREEN_DIM_WAKE_LOCK |
- PowerManager.ACQUIRE_CAUSES_WAKEUP;
-
- wakeLock = pm.newWakeLock(level, "BackgroundModeExt");
- wakeLock.setReferenceCounted(false);
- wakeLock.acquire(1000);
- }
-
- /**
- * Releases the previously acquire wake lock.
- */
- private void releaseWakeLock() {
- if (wakeLock != null && wakeLock.isHeld()) {
- wakeLock.release();
- wakeLock = null;
- }
- }
-
- /**
- * Add required flags to the window to unlock/wakeup the device.
- */
- static void addWindowFlags(Activity app) {
- final Window window = app.getWindow();
-
- app.runOnUiThread(new Runnable() {
- public void run() {
- window.addFlags(
- FLAG_ALLOW_LOCK_WHILE_SCREEN_ON |
- FLAG_SHOW_WHEN_LOCKED |
- FLAG_TURN_SCREEN_ON |
- FLAG_DISMISS_KEYGUARD
- );
- }
- });
- }
-
- /**
- * The activity referenced by cordova.
- *
- * @return The main activity of the app.
- */
- Activity getApp() {
- return cordova.get().getActivity();
- }
-
- /**
- * The launch intent for the main activity.
- */
- private Intent getLaunchIntent() {
- Context app = getApp().getApplicationContext();
- String pkgName = app.getPackageName();
-
- return app.getPackageManager().getLaunchIntentForPackage(pkgName);
- }
-
- /**
- * Get the requested system service by name.
- *
- * @param name The name of the service.
- *
- * @return The service instance.
- */
- private Object getService(String name) {
- return getApp().getSystemService(name);
- }
-
-}
diff --git a/src/android/BackgroundMode.java b/src/android/BackgroundMode.java
index 3ade663e..cac418af 100644
--- a/src/android/BackgroundMode.java
+++ b/src/android/BackgroundMode.java
@@ -1,22 +1,22 @@
/*
- 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.
+ 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;
@@ -30,23 +30,20 @@ Licensed to the Apache Software Foundation (ASF) under one
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONArray;
-import org.json.JSONException;
import org.json.JSONObject;
import de.appplant.cordova.plugin.background.ForegroundService.ForegroundBinder;
import static android.content.Context.BIND_AUTO_CREATE;
+import static de.appplant.cordova.plugin.background.BackgroundModeExt.clearKeyguardFlags;
public class BackgroundMode extends CordovaPlugin {
// Event types for callbacks
- private enum Event {
- ACTIVATE, DEACTIVATE, FAILURE
- }
+ private enum Event { ACTIVATE, DEACTIVATE, FAILURE }
// Plugin namespace
- private static final String JS_NAMESPACE =
- "cordova.plugins.backgroundMode";
+ private static final String JS_NAMESPACE = "cordova.plugins.backgroundMode";
// Flag indicates if the app is in background or foreground
private boolean inBackground = false;
@@ -64,26 +61,22 @@ private enum Event {
private ForegroundService service;
// Used to (un)bind the service to with the activity
- private final ServiceConnection connection = new ServiceConnection() {
+ private final ServiceConnection connection = new ServiceConnection()
+ {
@Override
- public void onServiceConnected(ComponentName name, IBinder service) {
+ public void onServiceConnected (ComponentName name, IBinder service)
+ {
ForegroundBinder binder = (ForegroundBinder) service;
BackgroundMode.this.service = binder.getService();
}
@Override
- public void onServiceDisconnected(ComponentName name) {
+ public void onServiceDisconnected (ComponentName name)
+ {
fireEvent(Event.FAILURE, "'service disconnected'");
}
};
- @Override
- protected void pluginInitialize() {
- BackgroundExt.addWindowFlags(cordova.getActivity());
- }
-
- // codebeat:disable[ABC]
-
/**
* Executes the request.
*
@@ -93,47 +86,59 @@ protected void pluginInitialize() {
* 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")) {
- configure(args.getJSONObject(0), args.getBoolean(1));
- callback.success();
- return true;
- }
-
- if (action.equalsIgnoreCase("enable")) {
- enableMode();
- callback.success();
- return true;
+ CallbackContext callback)
+ {
+ boolean validAction = true;
+
+ switch (action)
+ {
+ case "configure":
+ configure(args.optJSONObject(0), args.optBoolean(1));
+ break;
+ case "enable":
+ enableMode();
+ break;
+ case "disable":
+ disableMode();
+ break;
+ default:
+ validAction = false;
}
- if (action.equalsIgnoreCase("disable")) {
- disableMode();
+ if (validAction) {
callback.success();
- return true;
+ } else {
+ callback.error("Invalid action: " + action);
}
- BackgroundExt.execute(this, action, callback);
- return true;
+ return validAction;
}
- // codebeat:enable[ABC]
-
/**
* 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();
+ public void onPause(boolean multitasking)
+ {
+ try {
+ inBackground = true;
+ startService();
+ } finally {
+ clearKeyguardFlags(cordova.getActivity());
+ }
+ }
+
+ /**
+ * Called when the activity is no longer visible to the user.
+ */
+ @Override
+ public void onStop () {
+ clearKeyguardFlags(cordova.getActivity());
}
/**
@@ -142,8 +147,8 @@ public void onPause(boolean multitasking) {
* @param multitasking Flag indicating if multitasking is turned on for app.
*/
@Override
- public void onResume(boolean multitasking) {
- super.onResume(multitasking);
+ public void onResume (boolean multitasking)
+ {
inBackground = false;
stopService();
}
@@ -152,16 +157,17 @@ public void onResume(boolean multitasking) {
* Called when the activity will be destroyed.
*/
@Override
- public void onDestroy() {
+ public void onDestroy()
+ {
stopService();
- super.onDestroy();
android.os.Process.killProcess(android.os.Process.myPid());
}
/**
* Enable the background mode.
*/
- private void enableMode() {
+ private void enableMode()
+ {
isDisabled = false;
if (inBackground) {
@@ -172,7 +178,8 @@ private void enableMode() {
/**
* Disable the background mode.
*/
- private void disableMode() {
+ private void disableMode()
+ {
stopService();
isDisabled = true;
}
@@ -183,7 +190,8 @@ private void disableMode() {
* @param settings The settings
* @param update A truthy value means to update the running service.
*/
- private void configure(JSONObject settings, boolean update) {
+ private void configure(JSONObject settings, boolean update)
+ {
if (update) {
updateNotification(settings);
} else {
@@ -196,17 +204,15 @@ private void configure(JSONObject settings, boolean update) {
*
* @param settings The new default settings
*/
- private void setDefaultSettings(JSONObject settings) {
+ private void setDefaultSettings(JSONObject settings)
+ {
defaultSettings = settings;
}
/**
- * The settings for the new/updated notification.
- *
- * @return
- * updateSettings if set or default settings
+ * Returns the settings for the new/updated notification.
*/
- protected static JSONObject getSettings() {
+ static JSONObject getSettings () {
return defaultSettings;
}
@@ -215,7 +221,8 @@ protected static JSONObject getSettings() {
*
* @param settings The config settings
*/
- private void updateNotification(JSONObject settings) {
+ private void updateNotification(JSONObject settings)
+ {
if (isBind) {
service.updateNotification(settings);
}
@@ -225,7 +232,8 @@ private void updateNotification(JSONObject settings) {
* Bind the activity to a background service and put them into foreground
* state.
*/
- private void startService() {
+ private void startService()
+ {
Activity context = cordova.getActivity();
if (isDisabled || isBind)
@@ -248,12 +256,12 @@ private void startService() {
* Bind the activity to a background service and put them into foreground
* state.
*/
- private void stopService() {
+ private void stopService()
+ {
Activity context = cordova.getActivity();
Intent intent = new Intent(context, ForegroundService.class);
- if (!isBind)
- return;
+ if (!isBind) return;
fireEvent(Event.DEACTIVATE, null);
context.unbindService(connection);
@@ -268,7 +276,8 @@ private void stopService() {
* @param event The name of the event
* @param params Optional arguments for the event
*/
- private void fireEvent (Event event, String params) {
+ private void fireEvent (Event event, String params)
+ {
String eventName = event.name().toLowerCase();
Boolean active = event == Event.ACTIVATE;
@@ -283,12 +292,6 @@ private void fireEvent (Event event, String params) {
final String js = str;
- cordova.getActivity().runOnUiThread(new Runnable() {
- @Override
- public void run() {
- webView.loadUrl("javascript:" + js);
- }
- });
+ cordova.getActivity().runOnUiThread(() -> webView.loadUrl("javascript:" + js));
}
-
}
diff --git a/src/android/BackgroundModeExt.java b/src/android/BackgroundModeExt.java
new file mode 100644
index 00000000..ed765984
--- /dev/null
+++ b/src/android/BackgroundModeExt.java
@@ -0,0 +1,445 @@
+/*
+ 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.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityManager.AppTask;
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.PowerManager;
+import android.view.View;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.PluginResult;
+import org.apache.cordova.PluginResult.Status;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static android.R.string.cancel;
+import static android.R.string.ok;
+import static android.R.style.Theme_DeviceDefault_Light_Dialog;
+import static android.content.Context.ACTIVITY_SERVICE;
+import static android.content.Context.POWER_SERVICE;
+import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
+import static android.os.Build.VERSION.SDK_INT;
+import static android.os.Build.VERSION_CODES.M;
+import static android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS;
+import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
+
+/**
+ * Implements extended functions around the main purpose
+ * of infinite execution in the background.
+ */
+public class BackgroundModeExt extends CordovaPlugin {
+
+ // To keep the device awake
+ private PowerManager.WakeLock wakeLock;
+
+ /**
+ * 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.
+ */
+ @Override
+ public boolean execute (String action, JSONArray args,
+ CallbackContext callback)
+ {
+ boolean validAction = true;
+
+ switch (action)
+ {
+ case "battery":
+ disableBatteryOptimizations();
+ break;
+ case "webview":
+ disableWebViewOptimizations();
+ break;
+ case "appstart":
+ openAppStart(args.opt(0));
+ break;
+ case "background":
+ moveToBackground();
+ break;
+ case "foreground":
+ moveToForeground();
+ break;
+ case "tasklist":
+ excludeFromTaskList();
+ break;
+ case "dimmed":
+ isDimmed(callback);
+ break;
+ case "wakeup":
+ wakeup();
+ break;
+ case "unlock":
+ wakeup();
+ unlock();
+ break;
+ default:
+ validAction = false;
+ }
+
+ if (validAction) {
+ callback.success();
+ } else {
+ callback.error("Invalid action: " + action);
+ }
+
+ return validAction;
+ }
+
+ /**
+ * Moves the app to the background.
+ */
+ private void moveToBackground()
+ {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+
+ intent.addCategory(Intent.CATEGORY_HOME);
+
+ getApp().startActivity(intent);
+ }
+
+ /**
+ * Moves the app to the foreground.
+ */
+ private void moveToForeground()
+ {
+ Activity app = getApp();
+ Intent intent = getLaunchIntent();
+
+ intent.addFlags(
+ Intent.FLAG_ACTIVITY_REORDER_TO_FRONT |
+ Intent.FLAG_ACTIVITY_SINGLE_TOP |
+ Intent.FLAG_ACTIVITY_CLEAR_TOP);
+
+ clearScreenAndKeyguardFlags();
+ app.startActivity(intent);
+ }
+
+ /**
+ * Enable GPS position tracking while in background.
+ */
+ private void disableWebViewOptimizations() {
+ Thread thread = new Thread(){
+ public void run() {
+ try {
+ Thread.sleep(1000);
+ getApp().runOnUiThread(() -> {
+ View view = webView.getEngine().getView();
+
+ try {
+ Class.forName("org.crosswalk.engine.XWalkCordovaView")
+ .getMethod("onShow")
+ .invoke(view);
+ } catch (Exception e){
+ view.dispatchWindowVisibilityChanged(View.VISIBLE);
+ }
+ });
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+ }
+ };
+
+ thread.start();
+ }
+
+ /**
+ * Disables battery optimizations for the app.
+ * Requires permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS to function.
+ */
+ @SuppressLint("BatteryLife")
+ private void disableBatteryOptimizations()
+ {
+ Activity activity = cordova.getActivity();
+ Intent intent = new Intent();
+ String pkgName = activity.getPackageName();
+ PowerManager pm = (PowerManager)getService(POWER_SERVICE);
+
+ if (SDK_INT < M)
+ return;
+
+ if (pm.isIgnoringBatteryOptimizations(pkgName))
+ return;
+
+ intent.setAction(ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
+ intent.setData(Uri.parse("package:" + pkgName));
+
+ cordova.getActivity().startActivity(intent);
+ }
+
+ /**
+ * Opens the system settings dialog where the user can tweak or turn off any
+ * custom app start settings added by the manufacturer if available.
+ *
+ * @param arg Text and title for the dialog or false to skip the dialog.
+ */
+ private void openAppStart (Object arg)
+ {
+ Activity activity = cordova.getActivity();
+ PackageManager pm = activity.getPackageManager();
+
+ for (Intent intent : getAppStartIntents())
+ {
+ if (pm.resolveActivity(intent, MATCH_DEFAULT_ONLY) != null)
+ {
+ JSONObject spec = (arg instanceof JSONObject) ? (JSONObject) arg : null;
+
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ if (arg instanceof Boolean && !((Boolean) arg))
+ {
+ activity.startActivity(intent);
+ break;
+ }
+
+ AlertDialog.Builder dialog = new AlertDialog.Builder(activity, Theme_DeviceDefault_Light_Dialog);
+
+ dialog.setPositiveButton(ok, (o, d) -> activity.startActivity(intent));
+ dialog.setNegativeButton(cancel, (o, d) -> {});
+ dialog.setCancelable(true);
+
+ if (spec != null && spec.has("title"))
+ {
+ dialog.setTitle(spec.optString("title"));
+ }
+
+ if (spec != null && spec.has("text"))
+ {
+ dialog.setMessage(spec.optString("text"));
+ }
+ else
+ {
+ dialog.setMessage("missing text");
+ }
+
+ activity.runOnUiThread(dialog::show);
+
+ break;
+ }
+ }
+ }
+
+ /**
+ * Excludes the app from the recent tasks list.
+ */
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private void excludeFromTaskList()
+ {
+ ActivityManager am = (ActivityManager) getService(ACTIVITY_SERVICE);
+
+ if (am == null || SDK_INT < 21)
+ return;
+
+ List tasks = am.getAppTasks();
+
+ if (tasks == null || tasks.isEmpty())
+ return;
+
+ tasks.get(0).setExcludeFromRecents(true);
+ }
+
+ /**
+ * Invokes the callback with information if the screen is on.
+ *
+ * @param callback The callback to invoke.
+ */
+ @SuppressWarnings("deprecation")
+ private void isDimmed (CallbackContext callback)
+ {
+ boolean status = isDimmed();
+ PluginResult res = new PluginResult(Status.OK, status);
+
+ callback.sendPluginResult(res);
+ }
+
+ /**
+ * Returns if the screen is active.
+ */
+ @SuppressWarnings("deprecation")
+ private boolean isDimmed()
+ {
+ PowerManager pm = (PowerManager) getService(POWER_SERVICE);
+
+ if (SDK_INT < 20)
+ {
+ return !pm.isScreenOn();
+ }
+
+ return !pm.isInteractive();
+ }
+
+ /**
+ * Wakes up the device if the screen isn't still on.
+ */
+ private void wakeup()
+ {
+ try {
+ acquireWakeLock();
+ } catch (Exception e) {
+ releaseWakeLock();
+ }
+ }
+
+ /**
+ * Unlocks the device even with password protection.
+ */
+ private void unlock()
+ {
+ addSreenAndKeyguardFlags();
+ getApp().startActivity(getLaunchIntent());
+ }
+
+ /**
+ * Acquires a wake lock to wake up the device.
+ */
+ @SuppressWarnings("deprecation")
+ private void acquireWakeLock()
+ {
+ PowerManager pm = (PowerManager) getService(POWER_SERVICE);
+
+ releaseWakeLock();
+
+ if (!isDimmed())
+ return;
+
+ int level = PowerManager.SCREEN_DIM_WAKE_LOCK |
+ PowerManager.ACQUIRE_CAUSES_WAKEUP;
+
+ wakeLock = pm.newWakeLock(level, "backgroundmode:wakelock");
+ wakeLock.setReferenceCounted(false);
+ wakeLock.acquire(1000);
+ }
+
+ /**
+ * Releases the previously acquire wake lock.
+ */
+ private void releaseWakeLock()
+ {
+ if (wakeLock != null && wakeLock.isHeld()) {
+ wakeLock.release();
+ wakeLock = null;
+ }
+ }
+
+ /**
+ * Adds required flags to the window to unlock/wakeup the device.
+ */
+ private void addSreenAndKeyguardFlags()
+ {
+ getApp().runOnUiThread(() -> getApp().getWindow().addFlags(FLAG_ALLOW_LOCK_WHILE_SCREEN_ON | FLAG_SHOW_WHEN_LOCKED | FLAG_TURN_SCREEN_ON | FLAG_DISMISS_KEYGUARD));
+ }
+
+ /**
+ * Clears required flags to the window to unlock/wakeup the device.
+ */
+ private void clearScreenAndKeyguardFlags()
+ {
+ getApp().runOnUiThread(() -> getApp().getWindow().clearFlags(FLAG_ALLOW_LOCK_WHILE_SCREEN_ON | FLAG_SHOW_WHEN_LOCKED | FLAG_TURN_SCREEN_ON | FLAG_DISMISS_KEYGUARD));
+ }
+
+ /**
+ * Removes required flags to the window to unlock/wakeup the device.
+ */
+ static void clearKeyguardFlags (Activity app)
+ {
+ app.runOnUiThread(() -> app.getWindow().clearFlags(FLAG_DISMISS_KEYGUARD));
+ }
+
+ /**
+ * Returns the activity referenced by cordova.
+ */
+ Activity getApp() {
+ return cordova.getActivity();
+ }
+
+ /**
+ * Gets the launch intent for the main activity.
+ */
+ private Intent getLaunchIntent()
+ {
+ Context app = getApp().getApplicationContext();
+ String pkgName = app.getPackageName();
+
+ return app.getPackageManager().getLaunchIntentForPackage(pkgName);
+ }
+
+ /**
+ * Get the requested system service by name.
+ *
+ * @param name The name of the service.
+ */
+ private Object getService(String name)
+ {
+ return getApp().getSystemService(name);
+ }
+
+ /**
+ * Returns list of all possible intents to present the app start settings.
+ */
+ private List getAppStartIntents()
+ {
+ return Arrays.asList(
+ new Intent().setComponent(new ComponentName("com.miui.securitycenter","com.miui.permcenter.autostart.AutoStartManagementActivity")),
+ new Intent().setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")),
+ new Intent().setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity")),
+ new Intent().setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")),
+ new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")),
+ new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.startupapp.StartupAppListActivity")),
+ new Intent().setComponent(new ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity")),
+ new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity")),
+ new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager")),
+ new Intent().setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")),
+ new Intent().setComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.autostart.AutoStartActivity")),
+ new Intent().setComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.entry.FunctionActivity")).setData(android.net.Uri.parse("mobilemanager://function/entry/AutoStart")),
+ new Intent().setAction("com.letv.android.permissionautoboot"),
+ new Intent().setComponent(new ComponentName("com.samsung.android.sm_cn", "com.samsung.android.sm.ui.ram.AutoRunActivity")),
+ new Intent().setComponent(ComponentName.unflattenFromString("com.iqoo.secure/.MainActivity")),
+ new Intent().setComponent(ComponentName.unflattenFromString("com.meizu.safe/.permission.SmartBGActivity")),
+ new Intent().setComponent(new ComponentName("com.yulong.android.coolsafe", ".ui.activity.autorun.AutoRunListActivity")),
+ new Intent().setComponent(new ComponentName("cn.nubia.security2", "cn.nubia.security.appmanage.selfstart.ui.SelfStartActivity")),
+ new Intent().setComponent(new ComponentName("com.zui.safecenter", "com.lenovo.safecenter.MainTab.LeSafeMainActivity"))
+ );
+ }
+}
diff --git a/src/android/ForegroundService.java b/src/android/ForegroundService.java
index e3130821..806c9568 100644
--- a/src/android/ForegroundService.java
+++ b/src/android/ForegroundService.java
@@ -1,26 +1,27 @@
/*
- 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.
+ 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;
@@ -33,6 +34,7 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
+import android.app.NotificationChannel;
import org.json.JSONObject;
@@ -60,7 +62,7 @@ public class ForegroundService extends Service {
private static final String NOTIFICATION_ICON = "icon";
// Binder given to clients
- private final IBinder mBinder = new ForegroundBinder();
+ private final IBinder binder = new ForegroundBinder();
// Partial wake lock to prevent the app from going to sleep when locked
private PowerManager.WakeLock wakeLock;
@@ -70,15 +72,17 @@ public class ForegroundService extends Service {
*/
@Override
public IBinder onBind (Intent intent) {
- return mBinder;
+ 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.
*/
- public class ForegroundBinder extends Binder {
- ForegroundService getService() {
+ class ForegroundBinder extends Binder
+ {
+ ForegroundService getService()
+ {
// Return this instance of ForegroundService
// so clients can call public methods
return ForegroundService.this;
@@ -90,7 +94,8 @@ ForegroundService getService() {
* by the OS.
*/
@Override
- public void onCreate () {
+ public void onCreate()
+ {
super.onCreate();
keepAwake();
}
@@ -99,16 +104,27 @@ public void onCreate () {
* No need to run headless on destroy.
*/
@Override
- public void onDestroy() {
+ 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.
*/
- private void keepAwake() {
+ @SuppressLint("WakelockTimeout")
+ private void keepAwake()
+ {
JSONObject settings = BackgroundMode.getSettings();
boolean isSilent = settings.optBoolean("silent", false);
@@ -116,11 +132,10 @@ private void keepAwake() {
startForeground(NOTIFICATION_ID, makeNotification());
}
- PowerManager pm = (PowerManager)
- getSystemService(POWER_SERVICE);
+ PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE);
wakeLock = pm.newWakeLock(
- PARTIAL_WAKE_LOCK, "BackgroundMode");
+ PARTIAL_WAKE_LOCK, "backgroundmode:wakelock");
wakeLock.acquire();
}
@@ -128,7 +143,8 @@ private void keepAwake() {
/**
* Stop background mode.
*/
- private void sleepWell() {
+ private void sleepWell()
+ {
stopForeground(true);
getNotificationManager().cancel(NOTIFICATION_ID);
@@ -142,7 +158,8 @@ private void sleepWell() {
* 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() {
+ private Notification makeNotification()
+ {
return makeNotification(BackgroundMode.getSettings());
}
@@ -152,7 +169,25 @@ private Notification makeNotification() {
*
* @param settings The config settings
*/
- private Notification makeNotification(JSONObject 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);
@@ -168,6 +203,10 @@ private Notification makeNotification(JSONObject settings) {
.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);
}
@@ -197,7 +236,8 @@ private Notification makeNotification(JSONObject settings) {
*
* @param settings The config settings
*/
- protected void updateNotification (JSONObject settings) {
+ protected void updateNotification (JSONObject settings)
+ {
boolean isSilent = settings.optBoolean("silent", false);
if (isSilent) {
@@ -207,6 +247,7 @@ protected void updateNotification (JSONObject settings) {
Notification notification = makeNotification(settings);
getNotificationManager().notify(NOTIFICATION_ID, notification);
+
}
/**
@@ -214,10 +255,10 @@ protected void updateNotification (JSONObject settings) {
*
* @param settings A JSON dict containing the icon name.
*/
- private int getIconResId(JSONObject settings) {
+ private int getIconResId (JSONObject settings)
+ {
String icon = settings.optString("icon", NOTIFICATION_ICON);
- // cordova-android 6 uses mipmaps
int resId = getIconResId(icon, "mipmap");
if (resId == 0) {
@@ -235,7 +276,8 @@ private int getIconResId(JSONObject settings) {
*
* @return The resource id or 0 if not found.
*/
- private int getIconResId(String icon, String type) {
+ private int getIconResId (String icon, String type)
+ {
Resources res = getResources();
String pkgName = getPackageName();
@@ -255,8 +297,8 @@ private int getIconResId(String icon, String type) {
* @param settings A JSON dict containing the color definition (red: FF0000)
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
- private void setColor(Notification.Builder notification,
- JSONObject settings) {
+ private void setColor (Notification.Builder notification, JSONObject settings)
+ {
String hex = settings.optString("color", null);
@@ -272,10 +314,10 @@ private void setColor(Notification.Builder notification,
}
/**
- * Shared manager for the notification service.
+ * Returns the shared notification service manager.
*/
- private NotificationManager getNotificationManager() {
+ private NotificationManager getNotificationManager()
+ {
return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
}
-
}
diff --git a/src/browser/BackgroundModeProxy.js b/src/browser/BackgroundModeProxy.js
index 5ba7880a..4a880cbe 100644
--- a/src/browser/BackgroundModeProxy.js
+++ b/src/browser/BackgroundModeProxy.js
@@ -1,22 +1,22 @@
/*
- Copyright 2013-2017 appPlant GmbH
+ 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
+ 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
+ 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.
+ 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.
*/
/**
diff --git a/src/ios/APPBackgroundMode.m b/src/ios/APPBackgroundMode.m
index 20f0695b..174b6667 100644
--- a/src/ios/APPBackgroundMode.m
+++ b/src/ios/APPBackgroundMode.m
@@ -241,7 +241,7 @@ - (void) fireEvent:(NSString*)event
*/
+ (NSString*) wkProperty
{
- NSString* str = @"X2Fsd2F5c1J1bnNBdEZvcmVncm91bmRQcmlvcml0eQ==";
+ NSString* str = @"YWx3YXlzUnVuc0F0Rm9yZWdyb3VuZFByaW9yaXR5";
NSData* data = [[NSData alloc] initWithBase64EncodedString:str options:0];
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
diff --git a/src/windows/BackgroundModeProxy.js b/src/windows/BackgroundModeProxy.js
index 5542e3f7..b151ae1f 100644
--- a/src/windows/BackgroundModeProxy.js
+++ b/src/windows/BackgroundModeProxy.js
@@ -1,22 +1,22 @@
/*
- 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.
+ 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.
*/
var plugin = cordova.plugins.backgroundMode;
diff --git a/www/background-mode.js b/www/background-mode.js
index 440edc3c..fff3f8d3 100644
--- a/www/background-mode.js
+++ b/www/background-mode.js
@@ -22,11 +22,6 @@
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
@@ -34,14 +29,15 @@ var exec = require('cordova/exec'),
*
* @return [ Void ]
*/
-exports.enable = function() {
+exports.enable = function()
+{
if (this.isEnabled())
return;
var fn = function() {
- exports._isEnabled = true;
- exports.fireEvent('enable');
- };
+ exports._isEnabled = true;
+ exports.fireEvent('enable');
+ };
cordova.exec(fn, null, 'BackgroundMode', 'enable', []);
};
@@ -52,14 +48,15 @@ exports.enable = function() {
*
* @return [ Void ]
*/
-exports.disable = function() {
+exports.disable = function()
+{
if (!this.isEnabled())
return;
var fn = function() {
- exports._isEnabled = false;
- exports.fireEvent('disable');
- };
+ exports._isEnabled = false;
+ exports.fireEvent('disable');
+ };
cordova.exec(fn, null, 'BackgroundMode', 'disable', []);
};
@@ -71,7 +68,8 @@ exports.disable = function() {
*
* @return [ Void ]
*/
-exports.setEnabled = function (enable) {
+exports.setEnabled = function (enable)
+{
if (enable) {
this.enable();
} else {
@@ -84,7 +82,8 @@ exports.setEnabled = function (enable) {
*
* @return [ Object ]
*/
-exports.getDefaults = function() {
+exports.getDefaults = function()
+{
return this._defaults;
};
@@ -93,7 +92,8 @@ exports.getDefaults = function() {
*
* @return [ Object ]
*/
-exports.getSettings = function() {
+exports.getSettings = function()
+{
return this._settings || {};
};
@@ -104,16 +104,20 @@ exports.getSettings = function() {
*
* @return [ Void ]
*/
-exports.setDefaults = function (overrides) {
+exports.setDefaults = function (overrides)
+{
var defaults = this.getDefaults();
- for (var key in defaults) {
- if (overrides.hasOwnProperty(key)) {
+ for (var key in defaults)
+ {
+ if (overrides.hasOwnProperty(key))
+ {
defaults[key] = overrides[key];
}
}
- if (this._isAndroid) {
+ if (this._isAndroid)
+ {
cordova.exec(null, null, 'BackgroundMode', 'configure', [defaults, false]);
}
};
@@ -126,14 +130,16 @@ exports.setDefaults = function (overrides) {
*
* @return [ Void ]
*/
-exports.configure = function (options) {
+exports.configure = function (options)
+{
var settings = this.getSettings(),
defaults = this.getDefaults();
if (!this._isAndroid)
return;
- if (!this._isActive) {
+ if (!this._isActive)
+ {
console.log('BackgroundMode is not active, skipped...');
return;
}
@@ -150,9 +156,41 @@ exports.configure = function (options) {
*
* @return [ Void ]
*/
-exports.disableWebViewOptimizations = function() {
- if (this._isAndroid) {
- cordova.exec(null, null, 'BackgroundMode', 'optimizations', []);
+exports.disableWebViewOptimizations = function()
+{
+ if (this._isAndroid)
+ {
+ cordova.exec(null, null, 'BackgroundModeExt', 'webview', []);
+ }
+};
+
+/**
+ * Disables battery optimazation mode for the app.
+ *
+ * @return [ Void ]
+ */
+exports.disableBatteryOptimizations = function()
+{
+ if (this._isAndroid)
+ {
+ cordova.exec(null, null, 'BackgroundModeExt', 'battery', []);
+ }
+};
+
+/**
+ * Opens the system settings dialog where the user can tweak or turn off any
+ * custom app start settings added by the manufacturer if available.
+ *
+ * @param [ Object|Bool ] options Set to false if you dont want to display an
+ * alert dialog first.
+ *
+ * @return [ Void ]
+ */
+exports.openAppStartSettings = function (options)
+{
+ if (this._isAndroid)
+ {
+ cordova.exec(null, null, 'BackgroundModeExt', 'appstart', [options]);
}
};
@@ -161,9 +199,11 @@ exports.disableWebViewOptimizations = function() {
*
* @return [ Void ]
*/
-exports.moveToBackground = function() {
- if (this._isAndroid) {
- cordova.exec(null, null, 'BackgroundMode', 'background', []);
+exports.moveToBackground = function()
+{
+ if (this._isAndroid)
+ {
+ cordova.exec(null, null, 'BackgroundModeExt', 'background', []);
}
};
@@ -172,9 +212,11 @@ exports.moveToBackground = function() {
*
* @return [ Void ]
*/
-exports.moveToForeground = function() {
- if (this.isActive() && this._isAndroid) {
- cordova.exec(null, null, 'BackgroundMode', 'foreground', []);
+exports.moveToForeground = function()
+{
+ if (this.isActive() && this._isAndroid)
+ {
+ cordova.exec(null, null, 'BackgroundModeExt', 'foreground', []);
}
};
@@ -183,9 +225,11 @@ exports.moveToForeground = function() {
*
* @return [ Void ]
*/
-exports.excludeFromTaskList = function() {
- if (this._isAndroid) {
- cordova.exec(null, null, 'BackgroundMode', 'tasklist', []);
+exports.excludeFromTaskList = function()
+{
+ if (this._isAndroid)
+ {
+ cordova.exec(null, null, 'BackgroundModeExt', 'tasklist', []);
}
};
@@ -195,7 +239,8 @@ exports.excludeFromTaskList = function() {
*
* @return [ Void ]
*/
-exports.overrideBackButton = function() {
+exports.overrideBackButton = function()
+{
document.addEventListener('backbutton', function() {
exports.moveToBackground();
}, false);
@@ -208,10 +253,14 @@ exports.overrideBackButton = function() {
*
* @return [ Void ]
*/
-exports.isScreenOff = function (fn) {
- if (this._isAndroid) {
- cordova.exec(fn, null, 'BackgroundMode', 'dimmed', []);
- } else {
+exports.isScreenOff = function (fn)
+{
+ if (this._isAndroid)
+ {
+ cordova.exec(fn, null, 'BackgroundModeExt', 'dimmed', []);
+ }
+ else
+ {
fn(undefined);
}
};
@@ -221,9 +270,11 @@ exports.isScreenOff = function (fn) {
*
* @return [ Void ]
*/
-exports.wakeUp = function() {
- if (this._isAndroid) {
- cordova.exec(null, null, 'BackgroundMode', 'wakeup', []);
+exports.wakeUp = function()
+{
+ if (this._isAndroid)
+ {
+ cordova.exec(null, null, 'BackgroundModeExt', 'wakeup', []);
}
};
@@ -232,9 +283,11 @@ exports.wakeUp = function() {
*
* @return [ Void ]
*/
-exports.unlock = function() {
- if (this._isAndroid) {
- cordova.exec(null, null, 'BackgroundMode', 'unlock', []);
+exports.unlock = function()
+{
+ if (this._isAndroid)
+ {
+ cordova.exec(null, null, 'BackgroundModeExt', 'unlock', []);
}
};
@@ -243,7 +296,8 @@ exports.unlock = function() {
*
* @return [ Boolean ]
*/
-exports.isEnabled = function() {
+exports.isEnabled = function()
+{
return this._isEnabled !== false;
};
@@ -252,15 +306,11 @@ exports.isEnabled = function() {
*
* @return [ Boolean ]
*/
-exports.isActive = function() {
+exports.isActive = function()
+{
return this._isActive !== false;
};
-
-/**********
- * EVENTS *
- **********/
-
exports._listener = {};
/**
@@ -271,14 +321,16 @@ exports._listener = {};
*
* @return [ Void ]
*/
-exports.fireEvent = function (event) {
+exports.fireEvent = function (event)
+{
var args = Array.apply(null, arguments).slice(1),
listener = this._listener[event];
if (!listener)
return;
- for (var i = 0; i < listener.length; i++) {
+ for (var i = 0; i < listener.length; i++)
+ {
var fn = listener[i][0],
scope = listener[i][1];
@@ -295,12 +347,13 @@ exports.fireEvent = function (event) {
*
* @return [ Void ]
*/
-exports.on = function (event, callback, scope) {
-
+exports.on = function (event, callback, scope)
+{
if (typeof callback !== "function")
return;
- if (!this._listener[event]) {
+ if (!this._listener[event])
+ {
this._listener[event] = [];
}
@@ -317,51 +370,25 @@ exports.on = function (event, callback, scope) {
*
* @return [ Void ]
*/
-exports.un = function (event, callback) {
+exports.un = function (event, callback)
+{
var listener = this._listener[event];
if (!listener)
return;
- for (var i = 0; i < listener.length; i++) {
+ for (var i = 0; i < listener.length; i++)
+ {
var fn = listener[i][0];
- if (fn == callback) {
+ if (fn == callback)
+ {
listener.splice(i, 1);
break;
}
}
};
-/**
- * @deprecated
- *
- * Called when the background mode has been activated.
- */
-exports.onactivate = function() {};
-
-/**
- * @deprecated
- *
- * Called when the background mode has been deaktivated.
- */
-exports.ondeactivate = function() {};
-
-/**
- * @deprecated
- *
- * Called when the background mode could not been activated.
- *
- * @param {Integer} errorCode
- * Error code which describes the error
- */
-exports.onfailure = function() {};
-
-
-/***********
- * PRIVATE *
- ***********/
-
/**
* @private
*
@@ -381,7 +408,8 @@ exports._isActive = false;
*
* Default values of all available options.
*/
-exports._defaults = {
+exports._defaults =
+{
title: 'App is running in background',
text: 'Doing heavy tasks.',
bigText: false,
@@ -402,9 +430,12 @@ exports._defaults = {
*
* @return [ Object ] Default values merged with custom values.
*/
-exports._mergeObjects = function (options, toMergeIn) {
- for (var key in toMergeIn) {
- if (!options.hasOwnProperty(key)) {
+exports._mergeObjects = function (options, toMergeIn)
+{
+ for (var key in toMergeIn)
+ {
+ if (!options.hasOwnProperty(key))
+ {
options[key] = toMergeIn[key];
continue;
}
@@ -423,7 +454,8 @@ exports._mergeObjects = function (options, toMergeIn) {
*
* @return [ Void ]
*/
-exports._setActive = function(value) {
+exports._setActive = function(value)
+{
if (this._isActive == value)
return;
@@ -441,11 +473,13 @@ exports._setActive = function(value) {
*
* @return [ Void ]
*/
-exports._pluginInitialize = function() {
+exports._pluginInitialize = function()
+{
this._isAndroid = device.platform.match(/^android|amazon/i) !== null;
this.setDefaults({});
- if (device.platform == 'browser') {
+ if (device.platform == 'browser')
+ {
this.enable();
this._isEnabled = true;
}
@@ -454,19 +488,23 @@ exports._pluginInitialize = function() {
};
// Called before 'deviceready' listener will be called
-channel.onCordovaReady.subscribe(function() {
+channel.onCordovaReady.subscribe(function()
+{
channel.onCordovaInfoReady.subscribe(function() {
exports._pluginInitialize();
});
});
// Called after 'deviceready' event
-channel.deviceready.subscribe(function() {
- if (exports.isEnabled()) {
+channel.deviceready.subscribe(function()
+{
+ if (exports.isEnabled())
+ {
exports.fireEvent('enable');
}
- if (exports.isActive()) {
+ if (exports.isActive())
+ {
exports.fireEvent('activate');
}
});
From b87e466387c4286b10281790878fe915941d12c0 Mon Sep 17 00:00:00 2001
From: kitolog
Date: Thu, 18 Apr 2019 14:38:08 +0300
Subject: [PATCH 3/7] updated onactivate calls
---
.npmrc | 23 +++++++++++++++++++++++
CHANGELOG.md | 4 ++++
package.json | 2 +-
plugin.xml | 4 +++-
src/android/BackgroundMode.java | 2 +-
src/ios/APPBackgroundMode.m | 2 +-
6 files changed, 33 insertions(+), 4 deletions(-)
create mode 100644 .npmrc
diff --git a/.npmrc b/.npmrc
new file mode 100644
index 00000000..8aab9a9d
--- /dev/null
+++ b/.npmrc
@@ -0,0 +1,23 @@
+# Specifies intentionally untracked files to ignore when using Git
+# http://git-scm.com/docs/gitignore
+
+*~
+*.sw[mnpcod]
+*.log
+*.tmp
+*.tmp.*
+log.txt
+*.sublime-project
+*.sublime-workspace
+.vscode/
+npm-debug.log*
+
+.idea/
+.sourcemaps/
+.sass-cache/
+.tmp/
+tmp/
+$RECYCLE.BIN/
+
+.DS_Store
+Thumbs.db
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9d91858b..6c2e3708 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,8 @@
## ChangeLog
+#### Version 0.7.5
+- Fixed onactivate call
+- Merged new Android permissions
+
#### Version 0.7.4
- Fixed iOS 12.2 crashes
- Merged original repository Android source updates
diff --git a/package.json b/package.json
index ef185e90..2d233f63 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "cordova-plugin-background-mode-fixed",
- "version": "0.7.4",
+ "version": "0.7.5",
"description": "Prevent apps from going to sleep in background. iOS fix.",
"cordova": {
"id": "cordova-plugin-background-mode-fixed",
diff --git a/plugin.xml b/plugin.xml
index 79654026..6883ddd5 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -44,7 +44,7 @@
- audio
+ remote-notification
@@ -77,6 +77,8 @@
+
+
Date: Sun, 27 Sep 2020 13:04:22 -0400
Subject: [PATCH 4/7] updates to fix playback issue
---
plugin.xml | 2 +-
src/ios/APPBackgroundMode.m | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/plugin.xml b/plugin.xml
index 04888784..7aecd88d 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -42,7 +42,7 @@
- remote-notification
+ audio
diff --git a/src/ios/APPBackgroundMode.m b/src/ios/APPBackgroundMode.m
index e0792ccc..d9ba8daa 100644
--- a/src/ios/APPBackgroundMode.m
+++ b/src/ios/APPBackgroundMode.m
@@ -173,6 +173,7 @@ - (void) configureAudioSession
// 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
From 57a30e516ce64a4aa3a06c7776dc2671120524ac Mon Sep 17 00:00:00 2001
From: NMTeck
Date: Sun, 27 Sep 2020 13:07:15 -0400
Subject: [PATCH 5/7] updating version number
---
plugin.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugin.xml b/plugin.xml
index 7aecd88d..cd38b2aa 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -3,7 +3,7 @@
+ version="0.7.8">
BackgroundMode
Prevent apps from going to sleep in background. iOS fix.
From 9693256b903c4539091d8839a31115c2ad2503d6 Mon Sep 17 00:00:00 2001
From: thompsd3
Date: Sun, 27 Sep 2020 15:52:31 -0400
Subject: [PATCH 6/7] Update README.md
---
README.md | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/README.md b/README.md
index d1c760f1..ac188101 100644
--- a/README.md
+++ b/README.md
@@ -29,21 +29,10 @@ Use the plugin by your own risk!
## Installation
The plugin can be installed via [Cordova-CLI][CLI] and is publicly available on [NPM][npm].
-Execute from the projects root folder:
-
- $ cordova plugin add cordova-plugin-background-mode
-
-Or install a specific version:
-
- $ cordova plugin add de.appplant.cordova.plugin.background-mode@VERSION
Or install the latest head version:
- $ cordova plugin add https://github.com/katzer/cordova-plugin-background-mode.git
-
-Or install from local source:
-
- $ cordova plugin add cordova-plugin-background-mode --searchpath
+ $ cordova plugin add https://github.com/thompsd3/cordova-plugin-background-mode.git
## Usage
@@ -207,4 +196,4 @@ Made with :yum: from Leipzig
[changelog]: CHANGELOG.md
[apache2_license]: http://opensource.org/licenses/Apache-2.0
[appplant]: http://appplant.de
-[meshfields]: http://meshfields.de
\ No newline at end of file
+[meshfields]: http://meshfields.de
From 54507f30ad7018762c786b9b36beb60991ae0f88 Mon Sep 17 00:00:00 2001
From: thompsd3
Date: Sun, 27 Sep 2020 21:33:23 -0400
Subject: [PATCH 7/7] Update README.md
Added information regarding additions to the Controller that can help with backgrounding, particularly for music apps that need to skip to the next song while in the background.
---
README.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/README.md b/README.md
index ac188101..2bf3b0a2 100644
--- a/README.md
+++ b/README.md
@@ -82,6 +82,16 @@ cordova.plugins.backgroundMode.un('EVENT', function);
```
+## iOS specifics
+
+### Update MainController (hacky for now until I can integrate into plugin)
+Further information can be found in this post https://stackoverflow.com/questions/9660488/ios-avaudioplayer-doesnt-continue-to-next-song-while-in-background
+
+You need this code in either your first view controller's init or viewDidLoad method:
+```c
+[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
+```
+
## Android specifics
### Transit between application states