Differentiate browser tab close and refresh (to detect multiple instances of application) - java

How can Differentiating browser tab close and refresh functionality.
As of now window refresh and close event doesn't have different events.
My requirement is to checking weather user already logged in or not in any of tabs,So that I wont allow him to load my app in any other tabs.
In GWT (java)
private void registerWindowCloseEvent() {
Window.addCloseHandler(new CloseHandler<Window>() {
#Override
public void onClose(CloseEvent<Window> event) {
// do something on close
}
});
}
in JavaScript/Jquery:
window.onbeforeunload = function(e) {
// do something on close
};
The above events are firing for both the events refresh and close..is there any way to differentiate.

Differentiating browser tab close and refresh functionality is really a pain because we don't have two events to know which event being fired.
But there are always some requirements :)
What I'm doing is setting one cookie in on-load and making a flag true if found that cookie and removing the cookie on browser close event.
So until unless the he closed the active tab(logged in tab), that cookie still there and if he tries to open in another tab, then the already active dialog comes.
Note:Solution provided with help of Cookies.
In
Here is the onModule() for GWT / same as onload/document.ready() for java script/Jquery.
#Override
public void onModuleLoad() {
if("already_in_browser".
equalsIgnoreCase(Cookies.getCookie("already_in_browser"))){
showAlreadyTabActiveDialog();
return;
}else{
setLoggedincookie();
}
private void setLoggedincookie() {
isLoggedintab = true; //this is a global variable
registerWindowCloseEvent();
com.google.gwt.user.client.Cookies.
setCookie("already_in_browser","already_in_browser");
}
private void showAlreadyTabActiveDialog() {
alert("You are already active in another tab");
registerWindowCloseEvent();
}
/** This event is onbeforeunload in javascript
private void registerWindowCloseEvent() {
Window.addCloseHandler(new CloseHandler<Window>() {
#Override
public void onClose(CloseEvent<Window> event) {
if(isLoggedintab ){
Cookies.removeCookie("already_in_browser");
}
}
});
}
Let me know If you found any bugs or loop holes in this.So that I'l look in to them.
I would be very happy,If some one provide a solution,without using cookies.

Related

Detect if application gains focus (as opposed to window focus)

I have a program that should issue some action when it gets activated after loosing focus to some other application before. I wrote a Focus-Listener to achieve this:
frame.addWindowFocusListener(new WindowFocusListener() {
#Override
public void windowGainedFocus(WindowEvent e) {
<do something when we gain focus>
}
#Override
public void windowLostFocus(WindowEvent e) {
<do something else when we lose focus>
}
});
Problem is, the gain-focus-action is also called when a modal dialog (for instance an authentication dialog) closes - the main window gains focus again. So I somehow would need to detect, if I gain focus from within my program or from the outside. Or, differently put, the focus action should not be located on the main window but on the application itself. What would be a simple way to do this?
Thanks #Aelop for helping me find an answer. e.getOppositeWindow() is null for windows of other applications, so I can neatly distinguish from where I'm coming from:
frame.addWindowFocusListener(new WindowFocusListener() {
#Override
public void windowGainedFocus(WindowEvent e) {
if (e.getOppositeWindow()==null) {
<do something when we gain focus>
}
}
#Override
public void windowLostFocus(WindowEvent e) {
<do something else when we lose focus>
}
});
if you didn't find a good solution use static variable when the focus is lost from a dialog in your application set a static boolean variable to true so when the focus is gained and the variable is true means that the focus is from some window in the application else the focus is from somewhere else i hope you get the idea try it if you didn't find some application or check the type of the source who lost the focus

Getting callback even when screen rotates in android (MVP Design Pattern)

Okay, this might be stale, but i really need to understand what the best practice will be and not how to easily bypass this either by disabling screen orientation or any other means.
I have a login screen and when the user clicks on login button it should go to the server and authenticate and return a response.
My problem is if the screen rotates my fragment might not receive a callback of the response data.
I'm trying out an MVP design pattern on android.
public void registerSignInEvent(){
this.signInBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String username = usernameEdit.getText().toString();
String password = passwordEdit.getText().toString();
authPresenter.loginUser(username, password, 1);
}
});
}
I've thought of the following...
Use a service to handle the login to the server, when its done the service updates the storage e.g is_login=false or true then use a LocalBroadcastManager to broadcast the event to the view(Fragment)
so it can query the presenter to know the login state.
Use a Fragment with setRetainIntance(true); to handle the presenter initialization and the presenter will trigger callback to methods of the activity e.g onLoginSuccess //confusing myself
Problem
A. the problem with my no.1 thought is that when my loginFragment is onPause at that moment, the broadcast receiver is unregistered, so it might not receive the event. plus i don't even know if it makes sense.
B. Its looks complicated with MVP pattern
The pattern really might not matter, i don't really need code snippet tho, I just need to understand the process that best fits the situation.
NOTE: My Presenter communicates with the view(fragment/activity) via the view interface, vice-versa.
You could try storing the user in the database/sharedprefs whenever you receive the response from the login, if a rotation occurs and the login-fragment gets reattached without receiving the necessary callbacks (which is the problem you're describing) you could add a check if the user is "already" logged in (by checking if the user exists in the db/sharedprefs in onResume of the loginactivity) and forward the user to the next activity or fragment from there.
First of all I use this cool method to keep presenter alive even if activity recreated: Presenter surviving orientation changes with Loaders. It detaches and attaches activity in onStop and onStart.
Need to mention also, that your second choice with persistent fragment in widely used, e.g. by Fernando Cejas. I've learned clean architecture approach with his articles, and he uses setRetainState(true).
And still your question is driving me crazy as well. Only solution I've found so far is ugly as hell. But it should work. Idea: after work done, I check if view is attached. If so, I proceed normally. I there is no view, that we are in the middle of rotation. So I have flag, that indicate, that work is done. I turn it on. Also I cache any needed data. And wait for the next view attaching. Where I check that flag.
Here is my code snippet. I'm not proud of it thought.
class SplashPresenter extends BasePresenter<SplashView> {
private final SplashInteractor splashInteractor;
private boolean isSplashWorkStarted;
private boolean isSplashWorkFinished;
private boolean isSplashWorkError;
private Throwable splashWorkError;
#Inject
SplashPresenter(SplashInteractor splashInteractor) {
this.splashInteractor = splashInteractor;
}
#Override
public void attachView(SplashView mvpView) {
super.attachView(mvpView);
if (isSplashWorkFinished) {
getMvpView().showApplicationUi();
} else if (isSplashWorkError) {
getMvpView().showError(splashWorkError.getMessage());
}
}
void executeSplashWork() {
if (!isSplashWorkStarted) {
splashInteractor.execute(new SplashInteractorSubscriber());
isSplashWorkStarted = true;
}
}
#Override
public void onDestroyed() {
splashInteractor.unsubscribe();
}
private final class SplashInteractorSubscriber extends Subscriber<Void> {
#Override
public void onCompleted() {
if (isViewAttached()) {
getMvpView().showApplicationUi();
} else {
isSplashWorkFinished = true;
}
}
#Override
public void onError(Throwable e) {
if (isViewAttached()) {
getMvpView().showError(e.getMessage());
} else {
isSplashWorkError = true;
splashWorkError = e;
}
}
#Override
public void onNext(Void v) {
}
}
}

Delayed view rendering not working

Currently learning play! 2.0, I wanted to add an "opening" to my homepage : the first time a user connects to the homepage, an opening would display for a few seconds and then he would be automatically redirected to the real home page. This opening would not be shown again for the rest of the session.
For now that piece of code looks like :
public class Application extends Controller {
private static ScheduledExecutorService executor = executors.newSingleThreadScheduledExecutor();
public static Result home() {
boolean introSeen = Cache.get("introSeen") == null ? false : true;
if(introSeen) {
System.out.println("Cache good, sending you home !");
return ok(home.render(Configs.HOME));
//return redirect("/");
}
else {
Cache.set("introSeen", true, 2*60*60);
Runnable task = new Runnable(){
#Override
public void run() {
home();
executor.shutdown();
}
};
executor.schedule(task, 7, TimeUnit.SECONDS);
return ok(intro.render(Configs.HOME));
}
}
I've added the println to make sure the cache variable registration and the delayed task were working, and they do. But for an unknown reason, the code
return ok(home.render(Configs.HOME));
is not working and the intro view (intro) stays on screen.
I've tried to user redirect instead of "ok" too, but nothing so far.
Thanks for your help :)
Why don't you just use Meta refresh or some JavaScript technique to do that ?
You can use session cookie for checking if next time user should see the opening or target page.

GWT handle back, refresh, close buttons

I'm trying to run some RPC calls when the user closes the window, refreshes it or clicks the back button but just for one single page. I found a post talking about handling but the solution is not working well, missing back button handler (not working) and always is for all page on the web, I can't find something for remove handler if you leave from page
Window.addWindowClosingHandler(new Window.ClosingHandler() {
#Override
public void onWindowClosing(ClosingEvent event) {
event.setMessage("You sure?");
}
});
Window.addCloseHandler(new CloseHandler<Window>() {
#Override
public void onClose(CloseEvent<Window> event) {
// Execute code when window closes!
System.out.println("ble ! ");
}
});
Framework: GWT 2.4 with mvp4g.
Browsers: FF and Chrome.
Because i use mvp4g framework i found a solution there , you need to extends your presenter with CyclePresenter and override onLoad and onUnload methods. These methods fire when view is load/unload from DOM, i tested and work for all cases, f5, back button, close browser/tab, go other web and call others events. Now i cant put some code there.
You need to remove the handler when you leave the page and then re-add it when you enter the page again. You have the "add" side covered with the above code, you are missing the "remove" part. You do that by using the HandlerRegistration object that is returned from the add*Handler methods. When you want to remove the registered handler, you just call the HandlerRegistration.removeHandler() method:
HandlerRegistration windowClosingHandler = Window.addWindowClosingHandler(new ClosingHandler() {
#Override
public void onWindowClosing(ClosingEvent event) {
// Handle window closing
}
});
// From now on the CloseHandler will be fired
// ...
// Somewhere else:
windowClosingHandler.removeHandler();
// From now on the CloseHandler won't be fired

Wicket - Progress/Multiple Label Updates

I'm not sure if this is even possible. It would seem like there would be a way to do this when you click a "submit" button.
private Button getButton(String id)
{
return new AjaxButton(id)
{
private static final long serialVersionUID = 1L;
{
setEnabled(true);
}
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form)
{
debug = "Beginning a process....";
target.addComponent(debugLabel);
//Perform the first process
debug = "Beginning second process....";
target.addComponent(debugLabel);
//Perform the second process
debug = "Finishing....";
target.addComponent(debugLabel);
//Perform the third process
debug = "Done.";
target.addComponent(debugLabel);
}
#Override
protected void onError(AjaxRequestTarget target, Form form)
{
//NO-OP
}
};
}
}
If it's not possible is there an alternative to multiple real-time updates? I want it so there is a status label on the bottom updating and telling you how much progress is done in that one method.
You would have to start the process that you want to have notifications about in another thread. Then you can update user session with information about the status which will be periodically checked by some ajax Behavior bound to label.
In wicket 6 you could also use WebSocketBehavior
Just use AjaxTimerBehavior, so that it updates your label every 1-2 seconds.
Code:
add(new AbstractAjaxTimerBehavior(Duration.seconds(1))
{
#Override
protected void onTimer(AjaxRequestTarget target)
{
target.add(label);
}
});
Obviously this solution uses dumb AJAX polling, so it is only advisable to use it on an intranet or other low traffic site.

Categories