In the application activities are stacked like this: A - > B - > C - > D - > E.
If I receive a particular notification and click on it, Activity E is started.
If I then click back (button on phone or button on actionbar), the application exit.
How do I make the transition to Activity D in this case, and then back through C, B, and A?
My code of back button:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
break;
}
return true;
}
Everything is okay when starting the application normally. The problem is when Activity starts from the notification.
Android has the functionality you're after built in, and it is already well documented. To begin with you should look at the TaskStackBuilder class. It was introduced in JellyBean, but is already included in the support library, and you use it to build a synthetic TaskStack which is what you need. A summary from the documentation reads:
When crossing from one task stack to another post-Android 3.0, the application should synthesize a back stack/history for the new task so that the user may navigate out of the new task and back to the Launcher by repeated presses of the back key. Back key presses should not navigate across task stacks.
TaskStackBuilder provides a way to obey the correct conventions around cross-task navigation.
How you build it is going to depend on the relationships of the Activities in your app, but the Tasks and Back Stack developers guide is a good read to help you decide, as is the Navigating with Up and Back design guide, if this is all new to you.
You'll find some code examples in the Implementing Effective Navigation lessons, also on the Android developers site, in the training section.
Incidentally, the button on the ActionBar is referred to as Up. Even though it sometimes shares the same functionality as the back button, the two are not the same (I assume that's the one you are talking about ;-) .)
I think you can solve your problem by sending an intent from Activity E to Activity D, and so on.
Therefore you should overwrite the method
onBackPressed()
that is called when you click on the back button.
Related
I have an issue with setting value of AutomationElement by using method ValuePattern.SetValue().
Everything works just fine until some dialog appears. When the dialog appears the code execution got stuck. No exception is thrown. After the dialog is confirmed, the code exection continues. Bellow is a sample of the code:
BasePattern basePattern = null;
ValuePattern valuePattern = null;
AutomationElement elementA = Window.GetElement(SearchCriteria.ByText(propertyName));
object patternObjectA = null;
elementA.TryGetCurrentPattern(ValuePattern.Pattern, out patternObjectA);
basePattern = (BasePattern)patternObjectA;
valuePattern = (ValuePattern)patternObjectA;
valuePattern.SetValue(optionToSet);
// Window.GetElement() is a method from TestStack.White framework
// The code execution got stuck on the last line until the dialog is confirmed
Is there any other way to set AutomationElement value?
Is somehow possible to avoid of getting stuck by dialog?
I'll by grateful for any help.
Thanks advance.
It could be that this dialog is not supporting UI Automation correctly or that you simply target the wrong element.
To verify that you may use Inspect.exe from Microsoft or similiar tools.
If it works, check if you really target the correct component with your code again.
If it does not work and:
if you are able to change the application
you can change the so called AutomationPeer of the UI component - here is a link for more infos
Or simply use another UI component that supports UI Automation correctly.
if you are not able to change the application, and also do not need to run in background, parallel, etc.. you might just focus the component (call setFocus() onto the AutomationElement, or expand it (via IsExpandCollapsePatternAvailable or simulated MouseClick onto the components coordinates)) and then use the SendKeys.SendWait("test") method.
EDIT: There is one more thing you should have a look at, and I wonder why I didn't mentioned it in the first place: Register to UI Automation Events
For example you could register a callback for the Structure change event type, and check if the dialog you talk about appeared.
If so --> click the confirmed button of the dialog.
Probably you will have to synchronize your execution, so that every further action in the UI Automation script waits until the registered callback got executed and the confirmed button got clicked.
I'm studying with AOSP, and I found ActivityStack and TaskRecord in "ActivityStack" Class. There is explanation In https://developer.android.com/guide/components/tasks-and-back-stack , Back-stack(=Activity Stack) And Task seems similar to me... What is the the difference between ActivityStack and TaskRecord?
In this https://developer.android.com/guide/components/tasks-and-back-stack,
Focus on below lines, For Task
A task is a cohesive unit that can move to the "background" when users begin a new task or go to the Home screen, via the Home button. While in the background, all the activities in the task are stopped.
For back stack
The back stack for the task remains intact—the task has simply lost focus while another task takes place. A task can then return to the "foreground" so users can pick up where they left off.
For info you can refer below links:-
What is the relationship between Task and Back stack
https://blog.mindorks.com/android-task-and-back-stack-review-5017f2c18196
https://medium.com/google-developers/tasks-and-the-back-stack-dbb7c3b0f6d4
If you think of activity back stack as two levels, it might be easier to understand the purpose of ActivityStack. Android supports launchMode and taskAffinity to put activities into different TaskRecords. But even activities are put into different TaskRecords, it keeps supporting the back button to switch back to previous activity. So when you launch activity that needs to be in new TaskRecord, then back button is pressed, it switches to top activity of previous TaskRecord. So ActivityStack is more like a TaskRecord stack, and TaskRecord is more like the activity stack inside the TaskRecord, however, general speaking, ActivityStack controls the pop up sequence, and you can say it's an indirect activity stack.
And creating ActivityStack seems to make management easier logically in multiple window environment. If you enable free form in Android, each launched window mode app has its own free form stack, and each stack has its own back stack.
My 2c.
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'm trying to minimize memory usage in my app, and one of the things I'm doing is calling finish() in the onPause method (which I know is not the best way to do things). For the most part, it seems to be working well, but when the user clicks the back button from the next activity, it logically skips over the finished activity and goes back further. Is it possible to have that activity in the back stack and just get recreated if the user presses back?
No. This conclusion comes from the task and backstack documentation as well as the activity documentation and a general understanding of how a stack data structure works.
A stack data strucure only has 2 possible operations push/put, which adds something to the collection, and pop, which removes it. Stacks folow a last in first out model, or LIFO, where by last thing added - in your case an activity - is the first thing removed when pop is called.
Within the android lifecycle activities are generally popped from the stack when the back button is pressed. At that point onDestroy() is called and the activity is removed (you can verify this by overriding the onDestroy() method and logging the results if you want to check). Alternativly you can force onDestroy() to be called by calling finish() as you are. Finishing an activity effectivly does the same thing as pressing back. The activity is destroyed and must be recreated before it can be added to the stack.
For what you're trying to do the stack would have to incorporate some intermediate state in which an activity does not exist but rather something akin to a reference is held that, when moved to the top, would indicate that the corresponding activity should be recreated. Since this is not how the sack works - it only holds activities - that state cannont exist and so the result you are talking about is not possible.
Your Goal is to minimize memory usage,Just make use of activity life cycle, You can do this alternative(if you need)
-Just leave onCreate() method blank.(only do setContentView(layout))
-Override onResume();
-whatever you were doing in onCreate just copy paste to onResume().
-and In onPause(), Recycle your all bitmaps and set them to null(I think you are using Bitmaps thats why you are very cautious about it ). and remove your views.
Now what will happen, when you launch your new activity, onPause() would be called. that will remove your all bitmap and views. and when you come back, onResume() will be call.(onCreate will not be called). and that will again initialize your view and bitmaps.
No, i don't think that is possible. Once you finish the Activity it's gone. You could, however, implement and handle your own stack. On back pressed, you would just start the closed Activity again.
I am trying to open a modal window during a click handler to verify the user action but the window doesn't appear until the handler completes. The window code can be as simple as the following and it still will not display so it isn't something to do with my abstract class.
Window w = new Window();
w.setModal(true);
w.setImmediate(true);
// Add components etc etc
UI.getCurrent().addWindow(w);
I could add the action code to the windows OK/Yes handler but that would stop me creating a generic Message class to simplify/stop code duplication.
I am guessing there is something I dont understand about how Vaadin/GWT works (still a newbie!), could someone point me in the right direction?
Cheers
For UI stuff, you have to stop thinking of sequencial programming,
better to think about event-driven concepts.
For Vaadin you could create a Dialog Window which asks the yes/no question.
In you app you create this dialog and display it.
And you attach a event-handler which is fired when the user clicks yes/no,
and inside this handler you then do the required actions in your code.
You can also look at this add-on
https://vaadin.com/de/directory#addon/confirmdialog
The right direction is architecture overview https://vaadin.com/book/vaadin7/-/page/architecture.html#architecture.overview
In other words your code makes only response from server side, but only client side can show "modal" window.
In your case you have to create handler for ok button click event and wait for this event