Providing delay between events in UiAutomator Android - java

How can I provide delay between event clicks in UiAutomator Android.
First event is entering a url in EditText :
new UiObject(new UiSelector().text("Search here")).setText("abc.com");
getUiDevice.waitForIdle(15000);
Here I am loading a webpage inside a webview. So when url loading finishes , then I need to check for second event.
Second event is checking content description of a object :
UiObject curClass = new UiObject(new UiSelector().className("android.widget.RelativeLayout"));
UiObject yCur = curClass.getChild(new UiSelector().description("ye"));
getCurCol();
public void getCurCol() throws UiObjectNotFoundException {
try {
if (yCur.getContentDescription() != null)
report.append("Success");
} catch (Exception e) {
System.err.println("\nCaught Exception: " + e.getMessage());
}
But this doesn't seem to be working.
I just want the app to wait for some time before checking for the second event.
I know these three methods are provided for delay in UI Automator -
public void waitForIdle(long timeout)
public void waitForIdle()
public boolean waitForWindowUpdate(String packageName, long timeout)
But I don't know how to use these methods.
Please suggest me a example how to use these.
Any help would be appreciated.
Thanks!

Try just
sleep(5000);
Let me know whether it works. Or you can try WaitForIdle( ) method.

If you need a wait after pressing a button
UiObject settingsButton = mDevice.findObject(new UiSelector().text("Settings"));
settingsButton.clickAndWaitForNewWindow();
or
settingsButton.waitUntilGone(1000);
In case of launching new activity from intent this way is the easiest I could find to wait for a settings package appear:
mDevice.wait(Until.hasObject(By.pkg("com.android.settings").depth(0)), 2000);
UiObject settingsValidation = mDevice.findObject(new UiSelector().packageName("com.android.settings").text("Settings"));
assertTrue("Unable to detect Settings", settingsValidation.waitForExists(4000));

public boolean waitForWindowUpdate(null, long timeout)
Works good for me. I think it's possible to bring any 'not existing' String packagaName, for ex. "blablabla", because you can get null instead of String packageName.
I've create a simply method to make a delay:
public void waitTime(int time) {
getUiDevice().waitForWindowUpdate(null, time);
}
Hope this is helpful.

I am no expert in UIautomator, but this can be done with Thread.sleep().

UiDevice provides a few methods that may work for you:
public void waitForIdle(long timeout)
public void waitForIdle()
public boolean waitForWindowUpdate(String packageName, long timeout)

i think TimeUnit.SECONDS.sleep(val); should be helpful here
for instance
import java.util.concurrent.TimeUnit;
private void waitFor(long val)
{
try
{
TimeUnit.SECONDS.sleep(val);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
This should work

I had a case where I had to wait for the Smart Lock dialog and find a way to dismiss it.
I ended up doing the following
final UiDevice mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
// Wait for the Smart Lock dialog to popup
if(mDevice.waitForWindowUpdate(null, 5000)) {
if("com.google.android.gms".equals(mDevice.getCurrentPackageName())) {
// Dismiss dialog
mDevice.pressBack();
}
}
This will wait for the dialog to appear and if it does it gets dismissed.

webView.loadUrl("http://abc.com");
webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
super.onPageStarted(view, url, favicon);
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
//Handle your code here
//Toast.makeText(TableContentsWithDisplay.this, "Width " + view.getWidth() +" *** " + "Height " + view.getHeight(), Toast.LENGTH_SHORT).show();
}
#Override
public void onReceivedSslError(WebView view,
SslErrorHandler handler, SslError error) {
// TODO Auto-generated method stub
super.onReceivedSslError(view, handler, error);
//Toast.makeText(TableContentsWithDisplay.this, "error "+error, Toast.LENGTH_SHORT).show();
}
});
Load your url then there is method onPageFinished() where you can handle your code.

The only way I was able to add delay in UIAutomator code was in a similar way to slott 's answer:
I basically lunched a small app (the basic app from android examples) and pressed back to close it. This allows time for all elements to load properly.
Context context = getApplicationContext();
final Intent intent = context.getPackageManager()
.getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); // Clear out any previous instances
context.startActivity(intent);
// Wait for the app to appear
mDevice.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), LAUNCH_TIMEOUT);
//then close this small app
mDevice.pressBack();

Related

Correct way to check internet connection with AsyncTask and output WebView content?

My app is based on a fullscreen WebView and I wanted to show a local file if there is no internet connection, otherwise load my website. I never used AsyncTask before and tried the following:
MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Check Internet Connection
mWebView = (WebView) findViewById(R.id.activity_main_webview);
HostAvailabilityTask hostAvailable = new HostAvailabilityTask(this);
boolean online = hostAvailable.isOnline();
if (!online) {
// Loading local html file into web view
mWebView.loadUrl("file:///android_asset/sample.html");
} else {
// load my website here
HostAvailabilityTask:
public class HostAvailabilityTask extends AsyncTask<String, Void, Boolean> {
private MainActivity main;
public HostAvailabilityTask(MainActivity main) {
this.main = main;
}
protected Boolean doInBackground(String... params) {
return isOnline(); // Correct way using AsyncTask?
}
protected void onPostExecute(Boolean... result) {
if(!result[0]) {
return; // What to return?
}
}
public boolean isOnline() {
Runtime runtime = Runtime.getRuntime();
try {
Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
int exitValue = ipProcess.waitFor();
return (exitValue == 0);
}
catch (IOException e) { e.printStackTrace(); }
catch (InterruptedException e) { e.printStackTrace(); }
return false;
}
}
As you can see I'm just calling the method isOnline(); inside the MainActivity and think this is the wrong way to use a AsyncTask? I just want to make sure to do it "the right way". I also don't know what would be logical to return in onPostExecute in that case?
As stated before I never used AsyncTask, so I hope someone could help me out. I also commented some lines in my code to make my confusion clear.
#Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error){
//Your code to do
Toast.makeText(getActivity(), "Your Internet Connection May not be active Or " + error , Toast.LENGTH_LONG).show();
}

Best practice implementing JavascriptInterface using WebView in Android?

I have a crash report of the same error like in this question: WebView methods on same thread error
There it is suggested to create a Runnable().
I don't understand why exactly this solves the problem. The error says "Webview methods on same Thread", but the answer suggests to create the method on the UI-Thread (Main Thread). But isn't the UI-Thread the one and only thread? Could someone explain this whole process in detail (considering I create a new Webview in every activity in the constructor)?
My code to implement Javascript functions/methods looks like this:
public class JS_Bind {
private static final String TAG = "JS_Bind";
private Context context;
private AdvancedWebView mWebView;
public JS_Bind(Context c, AdvancedWebView mWebView) {
context = c;
this.mWebView = mWebView;
}
#JavascriptInterface
public void openActivity(String activityName) {
try {
Class activityClass = Class.forName(PACKAGE_NAME + "." + activityName);
context.startActivity(new Intent(MainActivity.this, activityClass));
} catch (ClassNotFoundException e) {
Toast.makeText(context, "Invalid activity name: " + activityName, Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
#JavascriptInterface
public void makeToast(String toast) {
Toast mToast = Toast.makeText(context, toast, Toast.LENGTH_SHORT);
mToast.setGravity(Gravity.CENTER, 0, 0);
mToast.show();
}
#JavascriptInterface
public void external(String url) {
mTracker.send(new HitBuilders.EventBuilder().setCategory("Action").setAction("External Link: " + url).build());
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
#JavascriptInterface
public String showToken() {
return gcmToken;
}
#JavascriptInterface
public int showUid() {
SharedPreferences pref = getSharedPreferences("Pref", Activity.MODE_PRIVATE);
int uid = pref.getInt("uid", 0);
return uid;
}
#JavascriptInterface
public void buyPremium() {
bp.purchase(MainActivity.this, PRODUCT_ID);
}
}
Do I have to change EVERY function to this code (first answer in the question I refered to):
#JavascriptInterface
mWebView.post(new Runnable() {
#Override
public void makeToast() {
// ...
}
});
?
By the way, this is how I create the webview in the constructor activies onCreate method:
mWebView = (AdvancedWebView) findViewById(R.id.webView);
mWebView.setListener(this, this);
mWebView.addJavascriptInterface(new JS_Bind(this, mWebView), "Android");
mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
if (!DetectConnection.checkInternetConnection(this)) {
mWebView.loadUrl("file:///android_asset/offline.html");
}
else {
mWebView.loadUrl("http://example.com/tw3/index.php?s=home");
}
But isn't the UI-Thread the one and only thread?
No. WebView has its own pool of threads. There can be many other threads in an Android application.
Do I have to change EVERY function to this code
Not necessarily.
First, I do not see how you are getting that error (A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread.) from your #JavascriptInterface methods shown above. That error is when you call a method on the WebView itself, and you are not doing that.
You will need to use runOnUiThread() (or equivalent techniques) if:
Your #JavascriptInterface methods refer to the WebView itself, or
Your #JavascriptInterface try to do something else that has to be done on the main application thread (which will yield a different error message, as it will not be tied specifically to WebView)
Your startActivity() call might need to be called on the main application thread — I forget if that can be called on a background thread or not. Similarly with your Toast work — while I think that can be done on a background thread, I am not certain of it. It has been ages since I tried doing either of those things from a background thread.
Also, please only use your code if you control every single byte of what is being displayed in the WebView. Exposing startActivity() to arbitrary Web content has significant security implications.

Check Internet Connection before fetching JSON Data | waitFor() returns 1

I fetch JSON data through an AsyncTask in my activity like so:
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
// Load the plants via AsyncTask
new LoadItems().execute();
}
public class LoadItems extends AsyncTask<Void, Void, Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Void... arg0) {
updateJSONData();
return null;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
updateList();
}
}
But before fetching data, I need to check the connectivity. So I created the following class, thanks to snippets of codes from others:
public class ConnectionCheck {
public static boolean isConnectionOnline() {
Runtime runtime = Runtime.getRuntime();
try {
Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
int exitValue = ipProcess.waitFor();
return (exitValue == 0);
} catch (IOException e) { e.printStackTrace(); }
catch (InterruptedException e) { e.printStackTrace(); }
return false;
}
// Dialog box for connection failure
public static void showConnectionFailureDialogBox(final Context context) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.str_dialogBoxMessage);
builder.setPositiveButton(R.string.str_dialogBoxButton,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
((Activity) context).finish();
}
});
AlertDialog alert = builder.create();
alert.show();
}
}
And then I call those specially made functions like this:
#Override
protected void onPreExecute() {
super.onPreExecute();
if (!ConnectionCheck.isConnectionOnline()) {
ConnectionCheck.showConnectionFailureDialogBox(MyActivity.this);
this.cancel(true);
}
}
A dialog is supposed to show up when connection to the internet is non-existent. However, it pops up a dialog box every time. And when I checked the exit value I get, it's always 1. Never a 0. Is there something wrong with my code?
Also, it seems as if the code executes slowly? Is 'that' place the proper place to check the connection?
UPDATE
This may be late but, the problem resides in the emulator I used. Nothing's really wrong with the code. I can't use the method suggested in the answer, as I do need a connection to the Internet. I'm restricting my app to not executing the statements if it doesn't have any network connection, 'cause it'll crash. I've read somewhere that following the method you guys were suggesting, the condition will return true even if there's no connection to the net; as long as the device is connected within a network. Or something along those lines.
I'd try using a more Android API centric way of checking for connectivity. We use the following method within a helper class to check. It won't always be triggered, but works well enough for our purposes.
public static boolean hasConnectivity(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
return (cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isAvailable() && cm.getActiveNetworkInfo().isConnected());
}
You'll need to add the following permission as well if you haven't already:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

How to hide a TextView when the user is logged in

This is my task: When a user is logged in, The TextView will be invisible in my Activity. I'm using : http://www.androidhive.info/2012/01/android-login-and-registration-with-php-mysql-and-sqlite/
And here is my code:
if (session.isLoggedIn())
{
sgnin.setVisibility(View.INVISIBLE); //sgnin is my TextView i need to Invisible it.
}
Actual and General statement in tutorial:
if (!session.isLoggedIn()) {
logoutUser();
}
But after doing this, method ; setVisibility doesnt work!
Any ideas?
You're probably not making that call on the UI thread. Try this instead:
runOnUiThread(new Runnable() {
#Override
public void run() {
sgnin.setVisibility(View.INVISIBLE)
}
});

Android code working slower than intended

Sorry for my bad english,
I'm doing a project for school where i have to move a vehicle via WiFi with an Android App. I achieved my goal but I got surprised to see that, most of the times when I pressed any button, my vehicle took some time to actually do something. On the other hand, when I press any button a few times quickly, the events stack, and after, even when I'm not pressing any button, the vehicle moves. Needless to say, both are several problems. Is there any way to fix them?.
The Android App conects via REST API to an Arduino Yun. With each touch on a button i'm making an HTTP Request in order to move the vehicle Forward, Backwards, Left or Right.
Here's my code (Despite the spanish, I think it's understandable):
public class MainActivity extends Activity {
private Button boton1,
boton2,
boton3,
boton4;
private String valor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
configuracion();
}
public void configuracion(){
StrictMode.ThreadPolicy policy = new StrictMode.
ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
establecerBotones();
try{
definir("continua/0/0");
definir("direccion/0/0");
}
catch(Exception e){
Alerta();
}
}
public void establecerBotones(){
boton1= (Button)findViewById(R.id.boton1); //all buttons do something similar
boton1.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch(action){
case MotionEvent.ACTION_DOWN:
v.setPressed(true);
conectar("continua/1/0");
break;
case MotionEvent.ACTION_OUTSIDE:
case MotionEvent.ACTION_UP:
v.setPressed(false);
try {
conectar("continua/0/0");
} catch (Exception e) {
}
break;
}
return true;
}
});
boton2= (Button)findViewById(R.id.boton2);
boton2.setOnTouchListener(new OnTouchListener() {
});
boton3= (Button)findViewById(R.id.boton3);
boton3.setOnTouchListener(new OnTouchListener() {
});
boton4= (Button)findViewById(R.id.boton4);
boton4.setOnTouchListener(new OnTouchListener() {
});
}
private void conectar(final String selector) {
new Thread() {
#Override
public void run() {
try {
// code runs in a thread
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
definir (selector);
} catch (Exception e) {
System.out.println("holi");
}
}
});
} catch (final Exception ex) {
}
}
}.start();
}
public void definir(String selector) throws Exception{
valor = "http://192.168.240.1/arduino/" + selector;
URL url = new URL(valor);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
leer(in);
}
finally {
urlConnection.disconnect();
}
}
public void leer(InputStream in) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
if ((reader.readLine()) != "1") throw new IOException();
//Arduino is programmed to print "1" when connection succedes
}
public void Alerta(){
Context context = getApplicationContext();
CharSequence text = "Conexion erronea";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
PD: I'm kind of a beginner at programming, and I started learning java (and android) purely on my own this year. I'm probably doing some "dumb" errors on my code. I would appreciate any help or advice. Thank you for reading.
You have a problem with the code, as mentioned in comments. Android behaves badly if you do things that take any time on the UI thread. You need to move external connections onto a separate thread and find a way to communicate through it. As a newbie programmer you are going to find this hard, but there are lots of code samples around to help.
But this (and the code you posted) has nothing to do with your real problem. You have an "open loop" control mechanism and you need to close the loop. You need a way for the controlled device to respond with some information about whether it has moved or is moving, and you need to modify your control strategy accordingly.
Alternatively, you can send more complex commands to the vehicle (like "left 3" or "straight ahead") and leave the loop monitoring to the vehicle's on-board processor.
These are all common problems and you will find plenty of general reading material with very little searching. When you have very specific questions, Stack Overflow may be able to help better.

Categories

Resources