Robotium waitForView to disappear? - android

I'm using robotium 3.1 and I'd like to wait for a view to disappear, is there some way I can do that easily? My current way involves a ugly busy-loop with sleeps that makes no one happy.
To clarify what I'd like to happen:
waitForView(<View>) //The view appears
//The view is visible for a few seconds
waitForViewNotThere(<View>) //waits until the view has disappeared
The view that appears doesn't contain any text or such either. Any input is very much appreciated.

This is how:
final TextView helloWorldText = solo.getText("Hello world!");
solo.waitForCondition(new Condition() {
#Override
public boolean isSatisfied() {
return helloWorldText.getVisibility() == View.INVISIBLE;
}
}, 10000);

Whatever you do you are probably going to have some sort of sleep in the loop. (If you look at robotiums source it also uses sleeps). You can keep them to a minimum by using the waitforidlesync method on instrumentation that waits for the Ui thread to become idle.

if you want to wait for a view to disappear, use solo.waitForDialogToClose(long timeout).
Parameters :
timeout - the amount of time in milliseconds to wait.
returns : true if the Dialog is closed before the timeout and false if it is not closed.

Related

How to set progress dialog to max value in between

I have a progress dialog that takes 3 minutes to fill the progress.
If i get response from server earlier I want to fill progress to 100%, and then disables it.
This is my code, but it does not fill the progress bar to 100%.
progressBar.setProgress(100);
progressBar.cancel();
progressBarLayout.setVisibility(View.GONE)
I have a separate layout for progress dialog, that i disable when i set progressBar to 100. May be that's the reason it fails to render the progress dialog.
There might be an issue here:
The progressBar has a setMax method. So if your max is set to 2 (for example) if you use progressBar.setProgress(1); it will advance to 50%.
If you want to always fill it completely, perhaps using something like:
progressBar.setProgress(progressBar.getMax());
Possible issue:
Im not sure if you should change this in the UIThread, because you are touching the UI, I would recommend to check it.
Hope this helps.
Your code fills it to 100% but immediately makes it disappear, hence you're not seeing it. Try adding the code about turning your bar invisible in a runnable that starts only after you get the confirmation from the server
Runnable r = new Runnable() {
#Override
public void run() {
progressBarLayout.setVisibility(View.GONE)
}
}
then create a handler for ypur runnable:
Handler handler = new Handler();
When you get the response from the server tell the handler to wait for x seconds and run the runnable
handler.postDelayed(r, 2000); //here it waits for 2 seconds (2000 mills)

Espresso testing ProgressBar that toggles quickly

I have an activity that fires an asynchronous request to a server.
Right when it is fired, I show a progress bar. When a result is returned to the activity, I set the progressbar to View.GONE.
I have two tests right now.
One for testing trying to login with wrong credentials
which works perfectly :
#Test
public void tryLogin__withWrongPassword() {
onView(withId(R.id.loginEmail))
.perform(typeText("em#ail.com"), closeSoftKeyboard());
onView(withId(R.id.loginPassword))
.perform(typeText("123456789"), closeSoftKeyboard());
onView(withId(R.id.loginSubmit))
.perform(click());
onView(withId(R.id.loginProgressBar))
.check(matches(isDisplayed()));
onView(isRoot()).perform(waitFor(3000));
onView(withId(R.id.loginProgressBar))
.check(matches(not((isDisplayed()))));
onView(withId(R.id.loginPassword))
.check(matches(hasErrorText("Wrong password")));
}
And one that I test with no internet connectivity that does not work :
#Test
public void tryLogin__withoutInternet() {
onView(withId(R.id.loginEmail))
.perform(typeText("em#ail.com"), closeSoftKeyboard());
onView(withId(R.id.loginPassword))
.perform(typeText("123456789"), closeSoftKeyboard());
onView(withId(R.id.loginSubmit))
.perform(click());
onView(withId(R.id.loginProgressBar))
.check(matches(isDisplayed()));
onView(isRoot()).perform(waitFor(3000));
onView(withId(R.id.loginProgressBar))
.check(matches(not((isDisplayed()))));
onView(withText("Network error, try again later"))
.inRoot(withDecorView(not(mActivityRule.getActivity().getWindow().getDecorView())))
.check(matches(isDisplayed()));
}
The test fails because the progressbar in this case is shown for a fraction of a second (because the error is almost immediately dispatched from the viewmodel)
and seemingly Espresso cannot catch it while it is still loading.
My question is how could this potentially be fixed in my test? I have read somewhere that Espresso cannot test progress bars and the advice was to use UIAutomator instead, however I just started with Instrumented tests and chose Espresso and it is difficult for me to find the ideal tool for this case. Moreover, it seems to be working just fine when the progressbar appears for a bit more than half a second (in my first test for example)
P.S. the waitFor(long millis) method is a utility add-on method I made to force Espresso to wait for a specified amount of time before checking something (enforcing a timeout as a quality requirement)
Edit for clarification :
My main question here is if anyone has an idea why the visibility is not caught when it is active for less than an amount of time vs when it lasts for more than half a second, even if the check is done immediately after the perform(click()) call.

Android prevent UI thread from stalling when appending views

I'm building an app that requires me to append a bunch of views into a scrollView (as many as 70) based on the data the server sends back. An abbreviated version of how I am appending them looks like this.
if (mWallPosts != null) {
for (Map.Entry entry : mWallPosts.entrySet()) {
addPostToView((DataClass) entry.getValue(), (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE), mViewGroup);
}
}
and this being the addPostToView method call
View postView = inflater.inflate(R.layout.fragment_wall_post, container, false);
LinearLayout containerView = (LinearLayout) mWallView.findViewById(R.id.wall_content);
containerView.addView(postView);
There is more work that goes on, but it is irrelevant for the purpose of this post. I am also using a NavgationDrawer and the problem I am having is that when I navigate to this item the animation of closing the drawer isn't smooth (it kind of hangs for a second and snaps shut) It's pretty obvious to me that this is caused by the fact that this appending and the closing of the drawer are happening on the same thread, but I'm not sure how to resolve this issue. If I could figure out how to delay the append or something like that it would probably help. I don't think async would be of any use since it is ultimately going to run on the UI thread.

Run multiple performClick() with UI update

button.performClick();
For software demonstration purposes, I want to show the user interface updating after each button performClick(). For example, if the Activity was a calculator I can currently simulate the pressing of buttons [1], [2] and [3] using
btn1.performClick();
btn2.performClick();
btn3.performClick();
However, these updates to the EditText too quickly with no visible pause, i.e. it appears "123" are written to the screen simultaneously. What I want is:-
btn1.performClick() updates UI so people can physically see only button press updated to the EditText before the next button does. Similarly with btn2.performClick() and then btn3.performClick().
You may want to use a library like Robotium, and use Solo.waitForText Method to do what you want.
The problem is that we can not determine in advance the time that it will take to display the text, as it depends on the content of your onClick method.
It's why Robotium may be useful for what you want.
You can either use
Thread.sleep(delay);
or use
handler.postDelayed(Runnable,delay);
Use handler for btn2.performClick() and btn3.performClick() like...
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
// do something after 100ms
btn2.performClick();
}
}, 100);

Using SeekBar and setProgress doesn't change seekBar position [duplicate]

This question already has answers here:
Android SeekBar set progress value
(10 answers)
Closed 4 years ago.
I am using a Seekbar in a fragment and need to move the Seekbar to different positions. However, setProgress(xxx) is not working.
How do you trigger this method programmatically for a Seekbar: public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)? Moving the Seekbar manually works fine.
It's a Bug in ProgressBar!
The setProgress(...) seems to not trigger the update on the drawable if the same value is passed again. But it's not triggered during the setMax, too. So the update is missing.
To solve this, I'm just doing a bar.setProgress(0) before each update... this is only a workaround, but it works for me as expected:
bar.setProgress(0); // call these two methods before setting progress.
bar.setMax(20);
bar.setProgress(20);
Second Option.
mSeekBar.post(new Runnable() {
#Override
public void run() {
mSeekBar.setProgress(percentOfFullVolume);
}
});
it may also work for someone.
Try to set max value first and then set the progress.
I add this answer as this can help someone in the future.
In my case, I also thought setProgress was not working properly but here is my mistake.
increaseIncomeSeekBar.setProgress(progress);
increaseIncomeSeekBar.setMax(maxProgress);
For info progress and maxProgress equals 2000 and 12000. But when displaying the SeekBar, it seems like the progress was at 0 and thus not working properly.
You have to be aware of this which is pretty logical when you know it:
first SeekBar max = 100.
when you set a progress > max then progress = max.
so you need to set a max value before setting a progress value.
I add a comment to this topic because it happenned to me and it took me hours to figure out what the problem was. The bug is still active and the setProgress() method does not work properly sometimes.
I have a MainActivity which commit and replace Fragments and transmit the SeekBar value inside the bundle of each Fragments. The User changes the value of the Seekbar and its progress are put in the Bundle. Then when the User switch of Fragment, the new one get the SeekBar progress.
It works perfectly fine to transmit it this way and I always have the right value on my progress variable in the second Fragment. The problem appears when I use setProgress(theProgressValueTransmitted) method. This set my SeekBar progress only the first time I replace the first Fragment. After that, it never changes it wheareas the value of progress is still the right one.
I used :
int seekBarProgress;
Bundle bundle = this.getArguments();
if (bundle != null) {
seekBarProgress = bundle.getInt("seekBarProgress");
mySeekBar.post(new Runnable() {
#Override
public void run() {
eventListTimeSeekBar.setProgress(seekBarProgress);
}
});
}
And this is the only way I can make this work. Hope it could help someone with the same problem. This post is more than 4 years old, I don't even understand how this bug can still exist since it has been reported.
SeekBar.setProgress() should work just fine. Are you sure your code is executing on the UI thread? If not, then this would be the obvious explanation. Check the example in the API doc for ProgressBar
https://developer.android.com/reference/android/widget/ProgressBar.html
There they show how to bring the execution back to the main thread.
Nowadays everything seems to work as expected.
Post is not needed anymore.
Just do:
seekBar.setMax(200);
seekBar.setProgress(50);
(order doesn't matter)
Most of the time, SeekBar works fine. Sometimes, it won't.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//...
seekBar.setProgress(value);
//...
}
After I refresh the fragment view by detach() + attach(), the code does not work. My solution is to apply setProgress() within onViewStateRestored().
#Override
public void onViewStateRestored(Bundle inState) {
//...
seekBar.setProgress(value);
//...
}

Categories

Resources