Angular 2 application on mobile browser (sleep detection) - javascript

After mobile phone puts the browser to sleep, and stays like that for a longer period of time, after wake up it displays wrong data, which otherwise perfectly updates all the data on the page. Is there a way to detect wake up event and what's the best Angular way to reload page/component in that case?

A simple way to achieve this could be run a timer to detect if the browser is asleep.
Using RxJS timeinterval operator,
http://reactivex.io/documentation/operators/timeinterval.html
Rx.Observable.timer(0, 1000).timeInterval().subscribe(timer => {
if (timer.interval > (1000 + SLEEP_THRESHOLD)) {
console.log ('wake-up from sleep detected');
}
});
Other simple way could be,
var now = new Date().getTime();
setInterval (function () {
if ((new Date().getTime() - now) > SLEEP_THRESHOLD) {
console.log ('wake-up from sleep detected');
}
now = new Date().getTime();
}, 1000);

You can reload your app by simply calling JS function
location.reload()
or if you want a more Angular style approach you can try calling your
route again
this.router.navigate(["myRoute"]);
Regarding sleep on mobile browsers you can check out NoSleep.js maybe it can serve your purpose.

Related

setInterval functions not running when app in background

I'm developing a simple app with phonegap which every 30 seconds send user current coordinates to my database via ajax call.It works very well
$(document).ready(function() {
setInterval(function() {
SetLocationUpdates();
}, 30000);
});
If the app is in the foreground there is no problem and everything works fine, but if I open google maps app with this code
<div><a href="geo:41.897096,27.036545">Open maps app</div>
My app goes in the background(my app and google map app work separately.Two apps work at same time) and the interval function is not executed any more.
Is it possible to have the javascript code (a timer function) executing in the background with phonegap?
Edited:
I use cordova-plugin-background-mode(https://github.com/katzer/cordova-plugin-background-mode) but it still does not work.And alert give false.What is wrong with this?
document.addEventListener('deviceready', function () {
cordova.plugins.backgroundMode.enable();
alert(cordova.plugins.backgroundMode.isActive());
}, false);
I was looking for a solution to the same problem, and I think I just found one, though I haven't been able to fully try this out yet, I thought I'd post the answer here anyways, so you can try it out too.
One solution would be to set the timer in native code, instead of JavaScript, and there seems to be a Cordova plugin for just such a purpose:
https://github.com/dukhanov/cordova-background-timer
After installing the Cordova plugin, you can use it like this (pasted from the documentation):
var eventCallback = function() {
// timer event fired
}
var successCallback = function() {
// timer plugin configured successfully
}
var errorCallback = function(e) {
// an error occurred
}
var settings = {
timerInterval: 60000, // interval between ticks of the timer in milliseconds (Default: 60000)
startOnBoot: true, // enable this to start timer after the device was restarted (Default: false)
stopOnTerminate: true, // set to true to force stop timer in case the app is terminated (User closed the app and etc.) (Default: true)
hours: 12, // delay timer to start at certain time (Default: -1)
minutes: 0, // delay timer to start at certain time (Default: -1)
}
window.BackgroundTimer.onTimerEvent(eventCallback); // subscribe on timer event
// timer will start at 12:00
window.BackgroundTimer.start(successCallback, errorCallback, settings);
if you are still looking for an answer for this issue , or it can help someone else:
im sure that you are facing this problem in android so to resolve this you should add this piece of code after you add background-mode cordova plugin to your project :
this.backgroundMode.enable();
this.backgroundMode.on('activate').subscribe(()=>{
this.backgroundMode.disableWebViewOptimizations();
});

How setInterval and setTimeout behave on Phonegap/Cordova when app resumes from background? [duplicate]

I have a jQuery Mobile web app which targets iOS and Android devices. A component of the application is a background task, which periodically checks for a.) changes to local data and b.) connectivity to the server. If both are true, the task pushes the changes.
I'm using a simple setTimeout()-based function to execute this task. Each failure or success condition calls setTimeout() on the background task, ensuring that it runs on 30 second intervals. I update a status div with the timestamp of the last task runtime for debugging purposes.
In any desktop browser, this works just fine; however, on iOS or Android, after some period of time, the task stops executing. I'm wondering if this is related to the power conservation settings of the devices--when iOS enters stand-by, does it terminate JavaScript execution? That is what appears to happen.
If so, what is the best way to resume? Is there an on-wake event which I can hook into? If not, what other options are there which don't involve hooking into events dependent on user interaction (I don't want to bind the entire page to a click event just to restart the background task).
Looks like Javascript execution is paused on MobileSafari when the browser page isn't focused. It also seems if setInterval() events are late, they are simply fired as soon as the browser is focused. This means we should be able to keep a setInterval() running, and assume the browser lost/regained focus if the setInterval function took much longer than usual.
This code alerts after switching back from a browser tab, after switching back from another app, and after resuming from sleep. If you set your threshold a bit longer than your setTimeout(), you can assume your timeout wouldn't finish if this fires.
If you wanted to stay on the safe side: you could save your timeout ID (returned by setTimeout) and set this to a shorter threshold than your timeout, then run clearTimeout() and setTimeout() again if this fires.
<script type="text/javascript">
var lastCheck = 0;
function sleepCheck() {
var now = new Date().getTime();
var diff = now - lastCheck;
if (diff > 3000) {
alert('took ' + diff + 'ms');
}
lastCheck = now;
}
window.onload = function() {
lastCheck = new Date().getTime();
setInterval(sleepCheck, 1000);
}
</script>
Edit: It appears this can sometimes trigger more than once in a row on resume, so you'd need to handle that somehow. (After letting my android browser sleep all night, it woke up to two alert()s. I bet Javascript got resumed at some arbitrary time before fully sleeping.)
I tested on Android 2.2 and the latest iOS - they both alert as soon as you resume from sleep.
When the user switches to another app or the screen sleeps, timers seem to pause until the user switches back to the app (or when the screen awakens).
Phonegap has a resume event you can listen to instead of polling for state (as well as a pause event if you want to do things before it is out of focus). You start listening to it after deviceReady fires.
document.addEventListener("deviceready", function () {
// do something when the app awakens
document.addEventListener('resume', function () {
// re-create a timer.
// ...
}, false);
}, false);
I use angular with phonegap and I have a service implemented that manages a certain timeout for me but basically you could create an object that sets the timer, cancels the timer and most importantly, updates the timer (update is what is called during the 'resume' event).
In angular I have a scopes and root scope that I can attach data to, my timeout is global so I attach it to root scope but for the purpose of this example, I'll simply attach it to the document object. I don't condone that because you need should apply it to some sort of scope or namespace.
var timeoutManager = function () {
return {
setTimer: function (expiresMsecs) {
document.timerData = {
timerId: setTimeout(function () {
timeoutCallback();
},
expiresMsecs),
totalDurationMsecs: expiresMsecs,
expirationDate: new Date(Date.now() += expiresMsecs)
};
},
updateTimer: function () {
if (document.timerData) {
//
// Calculate the msecs remaining so it can be used to set a new timer.
//
var timerMsecs = document.timerData.expirationDate - new Date();
//
// Kill the previous timer because a new one needs to be set or the callback
// needs to be fired.
//
this.cancelTimer();
if (timerMsecs > 0) {
this.setTimer(timerMsecs);
} else {
timeoutCallback();
}
}
},
cancelTimer: function () {
if (document.timerData && document.timerData.timerId) {
clearTimeout(document.timerData.timerId);
document.timerData = null;
}
}
};
};
You could have the manager function take a millisecond parameter instead of passing it into set, but again this is modeled somewhat after the angular service I wrote. The operations should be clear and concise enough to do something with them and add them to your own app.
var timeoutCallback = function () { console.log('timer fired!'); };
var manager = timeoutManager();
manager.setTimer(20000);
You will want to update the timer once you get the resume event in your event listener, like so:
// do something when the app awakens
document.addEventListener('resume', function () {
var manager = timeoutManager();
manager.updateTimer();
}, false);
The timeout manager also has cancelTimer() which can be used to kill the timer at any time.
You can use this class github.com/mustafah/background-timer based on #jlafay answer , where you can use as follow:
coffeescript
timer = new BackgroundTimer 10 * 1000, ->
# This callback will be called after 10 seconds
console.log 'finished'
timer.enableTicking 1000, (remaining) ->
# This callback will get called every second (1000 millisecond) till the timer ends
console.log remaining
timer.start()
javascript
timer = new BackgroundTimer(10 * 1000, function() {
// This callback will be called after 10 seconds
console.log("finished");
});
timer.enableTicking(1000, function(remaining) {
// This callback will get called every second (1000 millisecond) till the timer ends
console.log(remaining);
});
timer.start();
Hope it helps, Thank you ...
You should use the Page Visibility API (MDN) which is supported just about everywhere. It can detect if a page or tab has become visible again and you can then resume your timeouts or carry out some actions.

How to sleep in a firefox extension without using setTimeout?

I am trying to open a pop-up window, wait X seconds and then close the popup window.
(The use case is sending a notification to a webapp - but we can't just do a GET request as it needs to be in the same session so we can use the login session)
I can't use setTimeout as we can't use it in add-ons/extensions
How can I get similar functionality without resorting to chewing up CPU cycles, which obviously causes a noticeable lag?
You can use the timers module provided by the SDK instead of nsITimer for the same kind of setTimeout/setInterval functionality provided in browsers
let { setTimeout } = require('sdk/timers');
function openPopup () {}
setTimeout(openPopup, 3000);
You can use nsITimer.
A basic example is below but you can find more information (including the use of Components.interfaces.nsITimer.TYPE_REPEATING_SLACK as an alternative to setInterval) on the relevant documentation page at https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsITimer
// we need an nsITimerCallback compatible interface for the callbacks.
var event = {
notify: function(timer) {
alert("Fire!");
}
}
// Create the timer...
var timer = Components.classes["#mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
// initialize it to call event.notify() once after exactly ten seconds.
timer.initWithCallback(event,10000, Components.interfaces.nsITimer.TYPE_ONE_SHOT);

Reducing Jitter in HTML5/Javascript App

I'm building for a hobby a metronome in JavaScript/HTML5 (should be eventually a FirefoxOS app). The problem I have is Jitter, which is a no-go for Metronomes. I understand that JavaScript is single-threaded and no controls about process priority exist. This is what I have:
function tick() {
var next_tick_bpm = parseInt(document.getElementById("bpm").value);
if (started) {
if (next_tick_bpm > 0) {
var next_tick_ms = 60000 / next_tick_bpm;
beep();
setTimeout(tick, next_tick_ms);
} else {
toggle();
}
}
}
Is there something else besides setTimeout (I also tried setInterval with the same results)? Maybe some native browser code for more precise timers?
Thanks,
Johannes
Since JS runs on the UI thread and shares it with all other activity, you absolutely cannot remove jitter with simple tools like timeout and interval. The problem is that these merely put you into the queue periodically, and always in the back.
Instead, you should look at Web Workers, which offer a mechanism for pushing long running tasks (like a metronome) off the main thread.
Some good info here:
https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers
You could try something like this:
function start(speed) {
return setInterval(beep, 60000/speed);
}
function stop(iid) {
clearInterval(iid);
}
When you want to start it, do something like:
// Start
var metronome = start(100);
// Stop
stop(metronome);
If nothing blocks the UI thread, the setInterval should give you good results.

Prevent js alert() from pausing timers

So I made some timers for a quiz. The thing is, I just realized when I put
javascript: alert("blah");
in the address, the popup alert box pauses my timer. Which is very unwanted in a quiz.
I don't think there is any way to stop this behaviour... but I'll ask anyway.
If there is not, mind suggesting what should I do?
Never, ever rely on javascript (or any other client-side time) to calculate elapsed times for operations done between postbacks, or different pages.
If you always compare server dates, it will be hard for people to cheat:
first page request, store the server time
ping with javascript calls each N seconds, compare the 2 server times, and return the elapsed (just for show)
when the user submits the form, compare the 2 server times, calculate the elapsed time, and discard the ones which took too long (ie: possible cheaters)
Apparently the preview rendering differs from the posted rendering. This paragraph is here to make sure the next two lines show up as code.
// Preserve native alert() if you need it for something special
window.nativeAlert = window.alert;
window.alert = function(msg) {
// Do something with msg here. I always write mine to console.log,
// but then I have rarely found a use for a real modal dialog,
// and most can be handled by the browser (like window.onbeforeunload).
};
No, there is no way to prevent alert from stopping the single thread in JavaScript. Probably you can use some other way of user notification, for example a floating layer.
It's modal and stops execution. Consider an alternative which does not pause execution like a Lightbox technique.
I think the question asker is trying to prevent cheating. Since a user can type javascript: alert("paused"); into the address bar, or make a bookmarklet to do that, it's easy to pause the quiz and cheat.
The only thing I can think of is to use Date() to get the current time, and check it again when the timer fires. Then if the time difference is not reasonably close to the intended timer duration, show an admonishment and disqualify the answer to that question or let them flunk the quiz. There is no way to prevent the user from pausing your quiz, but it should be possible to catch them.
Of course with any cheat-proofing, you motivate people to become better cheaters. A person could change the system time on their PC, and fool the javascript Date() constructor which gets the time from the operating system.
You can use an interval to do a repeated clock comparison against a one second interval length. The interval handler can also update a time-remaining field on the user's display. Then the users can feel the pressure build as time runs out on their quiz. Fun times!
The feedback loop on SyaZ's question has clarified the issues at stake.
Here's an attempt to summarize the good answers so far:
Client scripts are by nature are easy to manipulate to cheat an online quiz. SEE #Filini 's Server-side approach
window.alert = function(msg) {} will overriding alert() and perhaps defeat the low hanging fruit of putting in the addressbar: javascript:alert('Pausing page so I can google the answer') or I'll use my Phone-A-Friend now. Courtesy of #eyelidlessness
If you must use a client-side approach, instead of using setTimeOut(), you could use a custom date-compare-based pause function like this (concept by #Mnebuerquo, code example by me (#micahwittman)):
Example:
var beginDate = new Date();
function myTimeout(milsecs){
do { curDate = new Date(); }
while((curDate-beginDate) < milsecs);
}
function putDownYourPencils(milsecs){
myTimeout(milsecs);
var seconds = milsecs / 1000;
alert('Your ' + seconds + ' seconds are up. Quiz is over.');
}
putDownYourPencils(3000);
Ultimately, you cannot trust user input. Without keeping track of the time elapsed on the server, there's just no guarantee the data hasn't been manipulated.
However, if you're confident your quiz-takers aren't JavaScript-savvy, and are merely relying on a "trick" they found somewhere, you could test for cheating (pausing) with the following code, which doesn't require modifying window.alert:
var timer = {
startDatetime: null,
startSec: 0,
variance: 1,
exitOnPause: true,
count: function (config) {
var that = this;
if (typeof config == "object" && typeof parseInt(config.seconds) == "number" && !isNaN(parseInt(config.seconds)))
{
if (typeof parseFloat(config.variance) == "number" && !isNaN(parseFloat(config.variance))) this.variance = config.variance;
if (typeof config.exitOnPause == "boolean") this.exitOnPause = config.exitOnPause;
if (config.seconds > 0)
{
if (!this.startSec) this.startSec = config.seconds;
if (!this.startDatetime) this.startDatetime = new Date();
var currentDatetime = new Date();
if (currentDatetime.getTime() - this.startDatetime.getTime() > (this.startSec - config.seconds) * this.variance * 1000)
{
if (typeof config.onPause == "function") config.onPause();
if (!this.exitOnPause)
{
this.startDatetime = new Date();
this.startSec = config.seconds--;
window.setTimeout(function () { that.count(config); }, 1000);
}
}
else
{
config.seconds--;
window.setTimeout(function () { that.count(config); }, 1000);
}
}
else
{
if (typeof config.onFinish == "function") config.onFinish();
}
}
}
};
This timer object has a single method, count(), which accepts an object as input. It expects a seconds property in the input object at minimum.
For some reason, window.setTimeout doesn't always work as expected. Sometimes, on my machine, window.setTimeout(x, 1000), which should execute the code after 1 second, took more than 2 seconds. So, in a case like this, you should allow a variance, so people who aren't cheating don't get flagged as cheaters. The variance defaults to 1, but it can be overridden in the input object. Here's an example of how to use this code, which allows 2.5 seconds of "wiggle room" for slow-pokes:
timer.count({
seconds: 10,
onPause: function () { alert("You cheated!"); window.location.replace("cheatersAreBad.html"); },
onFinish: function () { alert("Time's up!"); },
variance: 2.5
});
With a solution like this, you could use Ajax to tell a server-side script that the user has paused the timer or redirect the user to a page explaining they were caught cheating, for example. If, for some reason, you wanted to allow the user to continue taking the quiz after they've been caught cheating, you could set exitOnPause to false:
timer.count({
seconds: 10,
exitOnPause: false,
onPause: function () { recordCheaterViaAjax(); },
onFinish: function () { alert("Time's up!"); },
variance: 2.5
});
The server session could be set to expire at say 1 hour. The javascript could be used as only a display tool for the user to know how much time is left. If he decides to cheat by pausing the timer, then he might be suprised when posting his test that his session has timed out.

Categories