First off, before the flames start, I do know that trying to hinder the back button in the browser is a dumb idea. I would not try to do this, but my business partners are very insistent on it. We are porting an existing .exe to the web and their definition of this is 'run it in a browser' and not "make it a web site". So, fact that it's a bad idea (I agree), here's the question:
Is there a way to ignore or trick the GWT PlaceController / History manager mechanisms so that when the back button is pressed, it just stays on the same page?
I have used Window.addWindowClosingHandler to add a handler which will prompt the user if they want to leave the page and overriden the newItem() method of the defaultHistorian so that no history is tracked at all, but this isn't quite what the business people want.
What they'd like is to just ignore the back button so that nothing happens when it is clicked.
If anyone knows how to do this with GWT, I'd be very grateful.
And I"ve done a lot of google searching and haven't found anything exactly like this question. At least, not close enough to help.
I was able to get GWT to not accumulate any history so that when the user presses the BACK button, they cause an onWindowClosing event to happen and the Browser will prompt them if they want to stay or leave. This will accomplish the goal of not allowing the BACK button to take them back, but it's a bit Draconian. This code does that:
class TvHistorian extends PlaceHistoryHandler.DefaultHistorian
{
#Override
public void newItem(String token, boolean issueEvent) {
// don't do anything - this will prevent history from accumulating
}
}
final PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper, new TvHistorian());
I've tried a bunch of stuff including extending the PlaceController.goTo() to save the "lastNormalFlowPlace". Then, I tried to override the History.onValueChange to use this saved Place if it was different than what the event specified. But I think I missed some subtlety because that didn't work as expected.
With the above exception, my code looks almost exactly like what is documented here: http://www.gwtproject.org/doc/latest/DevGuideMvpActivitiesAndPlaces.html#Putting_it_all_together
I have already posted an answer in the same context.
Please have a look at below links:
promt user on backspace and browser backbutton in gwt
how can i get a prompt on url change
Disable back button in GWT
Try with any option:
History.addValueChangeHandler
WindowClosingHandler
Event.addNativePreviewHandler
$wnd.onbeforeunload
--EDIT--
Sample code: (It's working perfectly fine in Firefox, Chrome as well as IE9)
Note: add below code in the beginning of the onModuleLoad() method.
final String initToken = "Place";
History.addValueChangeHandler(new ValueChangeHandler<String>() {
#Override
public void onValueChange(ValueChangeEvent<String> event) {
String token = event.getValue();
if (!initToken.equalsIgnoreCase(token)) {
History.newItem(initToken);
}
}
});
// fire the initial history state.
History.fireCurrentHistoryState();
Note: add checks for other allowed history tokens.
Related
Does anybody have an idea on how I can accomplish this using Wicket?
I want to display a Wicket odal window automatically when no user activity has been detected for a certain amount of time. I'm thinking of using an AjaxSelfUpdatingBehavior in some way, but I have no clear ideas actually.
Is this possible with Wicket?
Also, you can use some js library not to catch all ajax calls and to be sure, that your user is really afk (even does not touching his mouse).
For example, see this free framework and it's demo.
And (if you using this js framework) in wicket you must handle
ifvisible.idle(function(){
Wicket.Ajax.get({u: '${callbackUrl}'})// This code will work when page goes into idle status
});
You must set ${callbackUrl} from wicket code to let js know what action to proceed in java code. It is not hard to do this. Look here.
This approach is more tricky, but if you implement this, you don't have to worry about users actions at all (he can read site's info and don't click any ajax links, but suddenly he will see modal window).
Yes you can, I use this as autologout function
public class MyTimer extends AbstractAjaxTimerBehavior {
public MyTimer(int seconds) {
this(Duration.seconds(seconds));
}
#Override
protected void onTimer(AjaxRequestTarget target) {
// show your window magic
}
}
Add this to you page (add(new MyTimer(300));) and this will be called after the number of seconds you specify. Make sure to replace the timer with a new one when doing ajax calls, or reset it.
I'm starting a new activity to display a leaderboard in my Android App.
When the leaderboard activity is displayed, and the user presses the home key and then resumes the app (so the leaderboard activity comes up again), and then navigates back to the main activity by pressing the back key, the back key and volume keys stop working).
I've attempted to override onBackPressed in my activity class. I can confirm that when this problem occurs, onBackPressed is not called (When back / volume is working, pressing back does trigger onBackPressed).
Normally I get a message in LogCat when I press the back key 'Unimplemented WebView method onKeyDown called from android.webkit.WebView,onKeyDown(WebView.java.2178)' - Again I can confirm that this message doesn't come up when the back key isn't working
Armed with the above information, I can only assume that it's something to do with the View not having focus or something along those lines. I would point out that touch input on the screen itself does work. It just seems to be the back and volume keys/buttons that have no effect.
It's an openGL ES 2.0 app so in my onPause() I'm calling view.onPause(); and in onResume, I'm calling view.onResume();
I really have no idea what's going on and I've been on this for 3 days straight so if anyone can point me in the right direction, that would be great.
If the user comes out of the leaderboard and back into the main app before they press the home key, then everything is OK, it's just if the home key is pressed while the leaderboard activity is displayed as described above.
So when I'm at the point where the back / volume keys aren't working, if I click my scores button and fire up the leaderboard activity again, they work. On returning to my activity, they stop working again.
Not sure if this is relevant at all but the following shows how I'm starting my leaderboard activity:
if (scoresButtonPresses){
displayLeaderBoard();
}
void displayLeaderBoard(){
//Display the leaderboard if already signed in
if (checkSignedIn()){
startActivityForResult(Games.Leaderboards.getLeaderboardIntent(getApiClient(), leaderboardID), 1);
}
//if not already connected, then set flag and connect to play services before displaying leaderbaord
else{
signInAction=SHOW_LEADERBOARD;
getGameHelper().beginUserInitiatedSignIn();
}
}
#Override
public void onSignInSucceeded() {
//If the flag is set, then display the leaderboard
if (signInAction==DISPLAY_LEADERBOARD){
startActivityForResult(Games.Leaderboards.getLeaderboardIntent(getApiClient(), leaderboardID), 1);
}
//Otherwise, reset the flag and take no action
else {signInAction=NO_ACTION;}
}
This is driving me crazy so any help or even a nudge in the right direction would be very much appreciated!!
Edit
After much testing I have learned a couple of things:
If I remove the view.onPause() && view.onResume() the problem seems to go away. So this appears to be something to do with the way key events are captured by the view. Pausing and resuming seems to mess something up.
I have also tried removing the view.onPause() and view.onResume() as above, but instead, putting in View.setVisibility(View.GONE); and then making it visible again in public void onWindowFocusChanged(boolean hasFocus). Again, I get the same problem. Interestingly, when I open the leaderboard, as expected the view's staus is 'gone' then hitting the home key and running the app again, it's set back to 'visible' - I don't understand this behaviour but I'll ask another question for that.
Lastly, and this I find really odd. If I put my app back to as I had it, then after hitting the home key and relaunching the app via Eclipse (and I can do this multiple times) the problem doesn't seem to occur. So in that respect, it appears to be something to do with touching the screen.
Edit
It appears as though this isn't limited to my app. I've tested this on a couple of other apps from the Play store and get the same result.
One app clearly uses a single activity model like mine and the back and volume stop working throughout the app.
The other may use a different activity for it menu and game. When I test on this app, the back/volume breaks but if you start a game (therefore a second activity), the back key starts working again, even when you return to the first activity (recreated this activity?!)
So maybe I can get around this by ensuring the activity is recreated? I thought i was already but maybe I'm not getting something. Maybe it's something to do with the stack.........
I have no solution to your problem but some additional insights since I'm facing the same bug/problem with the leaderboards and the back button (and it's driving me crazy).
I'm using a single activity with fragments from which I login to Google Play, open Leaderboards and Achievements in the exact way you are doing it (startActivityForResult). Always when I come back from any Google Play Service activity my back button is broken. Sometimes it's even enough if I try to login to Google Play for it to break, meaning the login popup sometimes breaks the back button (but not always).
Some more insights which might help to solve the problem:
I'm not using OpenGL, so it's not related to this - I'm just using a single activity and fragments
It's also breaking for me when I just use the back button for going back from any Google Play Activity (I don't even need to go via the home key, just normal back is enough).
When the back button is broken the Activity is not receiving any Key Events (OnKeyDown, OnKeyUp, dispatchKeyEvent) are all not working, although using the activity and touching it fully works. My guess is that some view is catching the events...
Edit:
I also tried checking activity.getCurrentFocus() and activity.hasWindowFocus() as well as the parent and context classes of activity.getCurrentFocus() to see if there is any difference between when it's working and when it's not - and there isn't any difference...
Edit:
It seems that a simple call to View.requestFocus() is fixing the problem. For my single activity (using fragments implementation) I have now added:
#Override
public void onResume(){
super.onResume();
Fragment fragment = getFragmentManager().findFragmentById(R.id.fragmentContainer);
fragment.getView().requestFocus();
}
and this seems to be fixing the problem. Sill have to do long term checking if it's always fixed. In your OpenGL implementation I guess you will have to get the main view of the activity in some other way since you are not using fragments.
I know it's pretty old question, but for clarification: accepted answer is correct, but incomplete. Focus requesting should be done in onResume, onActivityResult, onSignInSucceeded and onSignInFailed. In first two you have! to call super. Some code:
private void requestFocusAfterGooglePlay(){
if(gimmeFocus==null)
return;
View currFocus=getCurrentFocus();
gimmeFocus.setFocusableInTouchMode(true);
gimmeFocus.setFocusable(true);
gimmeFocus.requestFocus();
gimmeFocus.setFocusableInTouchMode(false);
gimmeFocus.setFocusable(false);
if(currFocus!=null)
currFocus.requestFocus();
}
#Override
public void onSignInFailed() {
requestFocusAfterGooglePlay();
}
#Override
public void onSignInSucceeded() {
requestFocusAfterGooglePlay();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
requestFocusAfterGooglePlay();
super.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onResume(){
super.onResume();
requestFocusAfterGooglePlay();
}
in my case gimmeFocus is a dummy View created as below:
<View
android:id="#+id/gimme_focus"
android:layout_width="0px"
android:layout_height="0px"
android:focusable="false"
android:focusableInTouchMode="false"/>
I have dynamic layout so I can't never be sure that any view exists in my layout, so I've created this dummy View, it might be also added programmatically. You might choose your fixed View for gaining focus, but rembember that changing focus might change view's look (drawable state).
I am using GWTs Activities and Places pretty much as described on http://code.google.com/webtoolkit/doc/latest/DevGuideMvpActivitiesAndPlaces.html and it is all working fine.
What I would like to do is from a particular page navigate to the previous page without using History.back() as I don't want to lose the history state. (I have a page where the user performs an action, on success I want to return to the previous page and keep the history state, on the other hand if they cancel I do want to use History.back() as I do want to lose the state).
The only way I can think of to do this is to create my own Place/History tracking code that listens to Place/History change events and makes the previous Place available to me so that I can call placeController.goto(...)
Is there an easier way of doing this? Am I missing something?
The approach I took was to store the history token in code (as suggested). I extended PlaceController and used it to track Place changes on the EventBus. Now everywhere I was using PlaceController I instead use PlaceControllerExt which has a nice previous() method that takes me back to where I came from - but navigates forward and never leaves the application.
public class PlaceControllerExt extends PlaceController {
private final Place defaultPlace;
private Place previousPlace;
private Place currentPlace;
public PlaceControllerExt(EventBus eventBus, Place defaultPlace) {
super(eventBus);
this.defaultPlace = defaultPlace;
eventBus.addHandler(PlaceChangeEvent.TYPE, new PlaceChangeEvent.Handler() {
public void onPlaceChange(PlaceChangeEvent event) {
previousPlace = currentPlace;
currentPlace = event.getNewPlace();
}
});
}
/**
* Navigate back to the previous Place. If there is no previous place then
* goto to default place. If there isn't one of these then it'll go back to
* the default place as configured when the PlaceHistoryHandler was
* registered. This is better than using History#back() as that can have the
* undesired effect of leaving the web app.
*/
public void previous() {
if (previousPlace != null) {
goTo(previousPlace);
} else {
goTo(defaultPlace);
}
}
}
You have to somehow keep track of were to return, because instead of cancel the user can hit the back button, which would be the same as clicking cancel, except there is no code in your application executed, so you have no control.
Secondly if you have the history in the url, the user could navigate directly to that page and then you should know where to go to when the user click ok. Or if the user goes directly to the page, redirect the user to another page.
One approach is to store the return history token in the history token of the page you go to. When the page is finished it can go back(or technically it would be 'go forward') to that page based on the passed return token. (Although with GWT you could easily store the history token in code).
is it possible to remove a History item in gwt? What i want to achieve is that in a special case pressing the browsers back button will show up the second history item from back. I know i can do it by manually calling History.back();, but i don't like that because the user will see the transition for a second or so which is not nice. Thx in advance for help.
kuku
No the browsers do not allow this.
GWT uses Javascript (of course) to manipulate the browser history. The Javascript engines do not allow the removal of history entries.
Maybe you could make a HistoryListener to skip the step you want removed, but you would have to keep track of history yourself in order to decide which way to skip (forward or backward)
As stated above, this isn't possible via GWT but you can manage this using History
(note: HistoryListener - mentioned in the previous post - has been deprecated)
Here is a simple example that will get you started.
public class UrlManager implements ValueChangeHandler<String> {
public UrlManager() {
History.addValueChangeHandler(this);
}
public void onValueChange(ValueChangeEvent<String> event) {
String historyToken = event.getValue();
}
}
You can use History.replaceItem(newToken, fireEvent).
This will replace the current history token on top of the browsers history stack.
newToken - history token to replace current top entry
fireEvent - a boolean for whether you want to fire history state event or not
im new to GWT ive been working on it since recently..
i want to know how can i go from "entry point page" ie,ImageViewer.java..
ive been suggested to create the memory by calling constructor on a perticular button
Button button = new Button("New button");
button.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event)
{
new LookupMaster(); //this is a composite
}
});
but this is not working.. i guess v can only call or get alert messages using this type..
can some one help me.
I'm not sure how to answer, since I have the feeling you're not understanding the basic concepts totally, but that's just my interpretation.
GWT is one html page that via JavaScript methods changes the content of that one page. When you want to display 'another' page you need to do this via methods that update the html dynamically. Since you are just starting with GWT, you might want to read this page on Build User Interfaces to understand the concepts and look at some examples provided with GWT.