diff --git a/CHANGELOG.md b/CHANGELOG.md index 812238c..1641472 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## ChangeLog #### Version 0.7.3 (not yet released) - 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 22502e3..dbfc62c 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,16 @@ cordova.plugins.backgroundMode.isScreenOff(function(bool) { }); ``` +### Unlock and wake-up +A wake-up turns on the screen while unlocking moves the app to foreground even the device is locked. + +```js +// Turn screen on +cordova.plugins.backgroundMode.wakeUp(); +// Turn screen on and show app even locked +cordova.plugins.backgroundMode.unlock(); +``` + ### Notification To indicate that the app is executing tasks in background and being paused would disrupt the user, the plug-in has to create a notification while in background - like a download progress bar. diff --git a/src/android/BackgroundExt.java b/src/android/BackgroundExt.java index c402a0b..ad3b9ea 100644 --- a/src/android/BackgroundExt.java +++ b/src/android/BackgroundExt.java @@ -25,10 +25,12 @@ 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.os.PowerManager; import android.view.View; +import android.view.Window; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaInterface; @@ -42,6 +44,10 @@ import java.util.List; import static android.content.Context.ACTIVITY_SERVICE; import static android.content.Context.POWER_SERVICE; +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; class BackgroundExt { @@ -51,6 +57,8 @@ class BackgroundExt { // 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. * @@ -113,6 +121,15 @@ class BackgroundExt { if (action.equalsIgnoreCase("dimmed")) { isDimmed(callback); } + + if (action.equalsIgnoreCase("wakeup")) { + wakeup(); + } + + if (action.equalsIgnoreCase("unlock")) { + wakeup(); + unlock(); + } } // codebeat:enable[ABC] @@ -124,22 +141,19 @@ class BackgroundExt { Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); - getActivity().startActivity(intent); + getApp().startActivity(intent); } /** * Move app to foreground. */ private void moveToForeground() { - Activity app = getActivity(); - String pkgName = app.getPackageName(); + Activity app = getApp(); + Intent intent = getLaunchIntent(); - Intent intent = app - .getPackageManager() - .getLaunchIntentForPackage(pkgName); - - intent.addFlags( Intent.FLAG_ACTIVITY_REORDER_TO_FRONT - | Intent.FLAG_ACTIVITY_SINGLE_TOP); + intent.addFlags( + Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | + Intent.FLAG_ACTIVITY_SINGLE_TOP); app.startActivity(intent); } @@ -152,15 +166,15 @@ class BackgroundExt { public void run() { try { Thread.sleep(1000); - getActivity().runOnUiThread(new Runnable() { + 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); + .getMethod("onShow") + .invoke(view); } catch (Exception e){ view.dispatchWindowVisibilityChanged(View.VISIBLE); } @@ -199,18 +213,90 @@ class BackgroundExt { * @param callback The callback to invoke. */ @SuppressWarnings("deprecation") - private void isDimmed (CallbackContext callback) { + 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); - boolean isDimmed; if (Build.VERSION.SDK_INT < 20) { - isDimmed = !pm.isScreenOn(); - } else { - isDimmed = !pm.isInteractive(); + return !pm.isScreenOn(); } - PluginResult result = new PluginResult(Status.OK, isDimmed); - callback.sendPluginResult(result); + 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 + ); + } + }); } /** @@ -218,10 +304,20 @@ class BackgroundExt { * * @return The main activity of the app. */ - Activity getActivity() { + 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. * @@ -229,8 +325,8 @@ class BackgroundExt { * * @return The service instance. */ - private Object getService (String name) { - return getActivity().getSystemService(name); + private Object getService(String name) { + return getApp().getSystemService(name); } } diff --git a/src/android/BackgroundMode.java b/src/android/BackgroundMode.java index 880cde4..1ffed24 100644 --- a/src/android/BackgroundMode.java +++ b/src/android/BackgroundMode.java @@ -33,6 +33,8 @@ 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; public class BackgroundMode extends CordovaPlugin { @@ -65,9 +67,7 @@ public class BackgroundMode extends CordovaPlugin { private final ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { - ForegroundService.ForegroundBinder binder = - (ForegroundService.ForegroundBinder) service; - + ForegroundBinder binder = (ForegroundBinder) service; BackgroundMode.this.service = binder.getService(); } @@ -77,6 +77,11 @@ public class BackgroundMode extends CordovaPlugin { } }; + @Override + protected void pluginInitialize() { + BackgroundExt.addWindowFlags(cordova.getActivity()); + } + // codebeat:disable[ABC] /** diff --git a/src/android/ForegroundService.java b/src/android/ForegroundService.java index 6a78589..ca9bb27 100644 --- a/src/android/ForegroundService.java +++ b/src/android/ForegroundService.java @@ -116,10 +116,10 @@ public class ForegroundService extends Service { startForeground(NOTIFICATION_ID, makeNotification()); } - PowerManager powerMgr = (PowerManager) + PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE); - wakeLock = powerMgr.newWakeLock( + wakeLock = pm.newWakeLock( PARTIAL_WAKE_LOCK, "BackgroundMode"); wakeLock.acquire(); diff --git a/www/background-mode.js b/www/background-mode.js index e208a72..a96c3de 100644 --- a/www/background-mode.js +++ b/www/background-mode.js @@ -196,6 +196,28 @@ exports.isScreenOff = function (fn) { } }; +/** + * Wake up the device. + * + * @return [ Void ] + */ +exports.wakeUp = function () { + if (this._isAndroid) { + cordova.exec(null, null, 'BackgroundMode', 'wakeup', []); + } +}; + +/** + * Wake up and unlock the device. + * + * @return [ Void ] + */ +exports.unlock = function () { + if (this._isAndroid) { + cordova.exec(null, null, 'BackgroundMode', 'unlock', []); + } +}; + /** * If the mode is enabled or disabled. *