I'm trying to test my android application with appium and I'm looking for a solution to the following issue:
In my application I have a section that takes time (for image processing) and it sometimes can take one minute, two minute or even more depends on the image size, quality.
In my test case I'm trying to wait for lets say 30 seconds and then I'm checking if the image processing is done.
The problem is if I'm waiting too long, I got the next message:
info: [debug] Didn't get a new command in 60 secs, shutting down...
I don't want to set a 'newCommandTimeout' cause I want to cut the test time and I want to test check if its done every short period.
In addition, I can't use the wait for element or something like that of appium API because I'm using a third party library which tells me when the image processing is done.
My questions is, there is any way to send a 'fake' command to appium so every 30 seconds that my thread is back to work and if I see that the image processing is not done I'll send a fake command and then go back to sleep for 30 seconds without any worry that the appium server will be shut down due to timeout?
Not sure what you are using for wait command. Use this:
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
This will wait until it finds the element on screen.
In addition to the comment here:
In order to solve this issue I use the WebDriverWait with a custom ExpectedCondition and it looks like:
new WebDriverWait(mDriver, 30) // 30 is for the time out
.withMessage("You can set any custom error message")
.until(new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver d) {
//This function will be called repeatedly until
//the return value will be true
}
});
You can see other implementations of WebDriverWait and actually I think it works with any Object instead of Boolean.
Related
I am using Delphi 10.2 to create Android app that uses Rest components to read returning data from post form. When I press on a button to load the data it load them normally after about 3 seconds freeze. The problem if the user try to click (or touch) any control on the form the app exit immediately after the 3 seconds freeze but if the user did not touch the app the data was loaded normally !
What is the reason for that and how I should fix it ?
The code I use for the button is
RESTRequest1.Execute;
I use 3 components RESTClient , RESTRequest and RESTResponse
and here is the code I use to get the data:
procedure TfrmMain.RESTRequest1AfterExecute(Sender: TCustomRESTRequest);
var
return_response: string;
begin
if RESTResponse1.StatusCode = 200 then begin
//fill years
return_response := RESTResponse1.Content;
memo1.text := return_response;
end;
end.
On mobile platforms you should always use ExecuteAsync because it does not run in the same thread as the UI. Execute instead runs on the same thread as the UI so it freezes while the request is processing. Android closes the app if it is not responsive (= freezed) after some seconds, and this is your problem!
To be more precise, here's the doc:
The use of the ExecuteAsync method is strongly recommended on mobile
platforms. iOS (and likely Android) will terminate an application if
it considers the main thread to be unresponsive, i.e. if a running
request takes more than a second or two to return
You can find more info here.
The function ExecuteAsync, as you can see in the doc, has an useful parameter which takes an anonymous procedure. The code of this procedure will be called once the ExecuteAsync has finished his task. Here's an example:
RESTRequest1.ExecuteAsync(
procedure
begin
ShowMessage('Finished!');
end;);
This is very easy and also you don't need to type the other parameters since they alrady have a value by default. Again, if you look at the doc you'll see for example ASynchronized: Boolean = True;, so setting the second parameter after the anonymous proc to True would be not relevant.
I have being upgrading an application to use the new Mobile Android GNSK but I have noticed that using the new MusicID-Stream is a little bit tricky. If the "identifyAlbumAsync" method get executed before the "audioProcessStart" method(since this need to be executed in a different thread), the application just crashes. In the Gracenote Demo application, the "audioProcessStart" method is continuously running so there is no need to synchronize its execution with the "identifyAlbumAsync" method call. Is it the way it is supposed to be used? It will be convenient if the application didn't crashed at least when the methods are not executed in order. Also in our application, we don't want to have the "audioProcessStart" method continuously like it is done in the demo application. We only want to run the "audioProcessStart" method when the user request identification and when the song playing gets identified , we want to stop the audio processing by calling "audioProcessStop". Is there an easy way to do this? Right now, we are getting the Thread where "identifyAlbumAsync" is running to sleep for 2 seconds in order to make sure that the Thread where the "audioProcessStart" method is supposed to run has time to get executed. Thank you in advance for your prompt response
In the upcoming 1.2 release, IGnMusicIdStreamEvents includes a callback that signals audio-processing has started, and an ID can be synced with this, e.g.:
#Override
public void musicIdStreamProcessingStatusEvent( GnMusicIdStreamProcessingStatus status, IGnCancellable canceller ) {
if (GnMusicIdStreamProcessingStatus.kStatusProcessingAudioStarted.compareTo(status) == 0) {
try {
gnMusicIdStream.identifyAlbumAsync();
} catch (GnException e) { }
}
}
Thanks for the feedback, you're right about this issue. Unfortunately right now sleeping is the best solution. But we are adding support for an explicit sync event in an upcoming release, please stay tuned.
Can I get any flag from calabash-android method which returns that page is still loading? I need to automate internet based application where wait is vary depending on internet speed and server load. How to set wait time or is there any way i will query to calabash-android which returns loading status of page.
You can use wait_for method. For instance:
wait_for(:timeout => 10, :retry_frequency => 0.2) { query("ProgressBar").empty? }
It waits for condition to be true until timeout runs out.
What is the most precise way to measure startup time of an Android app?
By startup time I mean the difference between 2. and 3. :
The app process is not running
User clicks on app icon in the launcher
Main Activity is fully initialized
So I basically need to somehow get time elapsed since JVM started and log it.
I understand I am too late to answer, nonetheless, this precisely answers the question.
This information gets logged on Logcat by default for API version 19 or higher.
From Android 4.4 (API level 19), logcat includes an output line containing a value called Displayed. This value represents the amount of time elapsed between launching the process and finishing drawing the corresponding activity on the screen.
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms
The key is looking for it in the right place -
If you’re tracking logcat output from the command line, or in a terminal, finding the elapsed time is straightforward. To find elapsed time in Android Studio, you must disable filters in your logcat view. Disabling the filters is necessary because the system server, not the app itself, serves this log.
The extracts are from the documentation.
I'm going to interpret your question as 'Is my app startup time fast enough. How can I check I have done everything I can do?'
The startup time is largely a false metric as it will vary across devices and ROMs. I guess what you're most likely to be interested in is how much of your code is taking a long time to execute and what is potentially blocking the main thread.
I've found the most effective way of doing this is to use Traceview on the app start and then reviewing how long it takes the method to execute and if there are any gaps on the main thread.
Start tracing:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Debug.startMethodTracing("startup");
}
}
Stop tracing:
#Override
public void onViewCreated(final View view, final Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Debug.stopMethodTracing();
}
Once the trace has been collected, you should be able to see anything that is having a major impact on startup time. In my case, seen below, there was a big gap on the UI thread where is was being blocked.
It transpired that both Crashlytics and Coremetrics were requiring a call to randomUUID() which was then being synchronized across threads and blocking the main thread. The solution was just to spin up a new thread to initialise the Coremetrics code.
This is something I would not have otherwise picked up with just measuring the startup time, but it actually sped up the app 'startup time' by a few hundred milliseconds.
Here's another snapshot after spinning off a separate thread for Coremetrics initialisation:
Check in adb shell in below manner.
adb shell
adb logcat -b events | grep am_activity_launch_time
[Output]
01-01 12:32:53.469 1236 1262 I am_activity_launch_time:
[0,205360373,com.sec.android.app.clockpackage/.ClockPackage,378,**378**,0]
Remarks:
Launch time for Clock is 378ms.
Wrap the entire onCreate() method in a TimingLogger. Just put this at the beginning:
TimingLogger timings = new TimingLogger(TAG, "methodA");
and this at the end:
timings.dumpToLog();
If you want to drop times at some intermediate step, you can do timings.addSplit("name"); to get the time it took to get to that step.
A simple way to display startup time in android.
Sometimes the Displayed line in the logcat output contains an additional field for total time. For example:
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)
In this case, the first time measurement is only for the activity that was first drawn
Source: Time to initial display
It is possible to implement time tracking using the next code:
Override your Application:
public class CustomApplication extends Application {
public final static long APP_START_TIME = System.currentTimeMillis();
/**
* Do all other application stuff
*/
}
And add few rows to your main Activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final View contentView = findViewById(android.R.id.content);
contentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= 16) {
contentView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
contentView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
long launchTime = System.currentTimeMillis() - CustomApplication.APP_START_TIME;
Log.e("TEST", "App launch time = " + launchTime);
}
});
}
}
And don't forget to define your custom application in Manifest:
<application
android:label="#string/app_name"
android:name=".CustomApplication" >
</application>
Important: You have to kill your application before launch, because Application stores static variable which tracks initial time.
Use SysTrace
Also the Trace class can be used to measure sections using
Trace.beginSection("name");
Trace.endSection();
This YouTube video is a quick primer as well.
I think this has been built into Firebase Console, under performance now
One possibility would be is to save the time at the beginning of the onCreate() method and at the end of the onCreate() method and then subtract those times from each other to get the time taken to initialize the app.
Whether I use this:
process = Runtime.getRuntime().exec("logcat -d time");
or that:
process = new ProcessBuilder()
.command("logcat", "-d", "time")
.redirectErrorStream(true)
.start();
I get the same results: it often hangs within the exec() or start() call, no matter what I tried to do!
The thread running this cannot even be interrupted with Thread.interrupt()! The child process is definitely started and if killed the above commands return.
These calls may fail on first attempt, so THERE IS NO WAY TO READ THEIR OUTPUT! I can also use a simple "su -c kill xxx" command line, same result!
EDIT: Started debugging the java_lang_ProcessManager.cpp file in an NDK project with some debugging logs! So here is what I found so far, after the fork() the parent does this:
int result;
int count = read(statusIn, &result, sizeof(int)); <- hangs there
close(statusIn);
Though the child process is not supposed to block on it: That's what the child does (if started at all!):
// Make statusOut automatically close if execvp() succeeds.
fcntl(statusOut, F_SETFD, FD_CLOEXEC); <- make the parent will not block
// Close remaining unwanted open fds.
closeNonStandardFds(statusOut, androidSystemPropertiesFd); <- hangs here sometimes
...
execvp(commands[0], commands);
// If we got here, execvp() failed or the working dir was invalid.
execFailed:
int error = errno;
write(statusOut, &error, sizeof(int));
close(statusOut);
exit(error);
The child can fail for 2 reproducible reasons:
1- child code is not running, but the parent believes it is!
2- child blocks on
closeNonStandardFds(statusOut, androidSystemPropertiesFd);
In either case the read(statusIn...) in the parent ends in deadlock! and a child process is left dead (and cannot be accessed, pid unknown, no Process object)!
This problem is fixed in Jelly Bean (Android 4.1) but not in ICS (4.0.4) and I guess it will never be fixed in ICS.
Above solution didn't prove to be reliable in any ways, causing more issues on some devices!
So I reverted back to the standard .exec() and kept digging...
Looking at the child code that hangs, I noticed the child process will hang while trying to close all file descriptors inherited from the parent (except the one created within the exec() call) !
So I search the whole app code for any BufferedReader/Writer and similar classes to make sure those would be closed when calling exec()!
The frequency of the issue was considerably reduced, and actually never occured again when I removed the last opened file descriptor before calling exec().
NB: Make sure SU binary is up-to-date, it can actually cause this issue too!
Enjoy your search ;)
Bug fix in Bionic was commited monthes ago, but it still hasn't been included in Android 4.0.4.
I have the same problem on ICS (seem to works fine on Android < 4). Did you find a solution?
A simple workaround could be to call the "exec" method in a dedicated thread with a timeout-join so that this situation could be "detected" (yes I know it's not very elegant...)