Android uiautomator - select multiple items at once - android

I am trying to automate the contact selection process using Android uiautomator. My UI looks like below image. I am using below code to check each contact
for (String contactName : list) {
UiScrollable scrollable = new UiScrollable(new UiSelector().className(
android.widget.ListView.class).scrollable(true))
.setAsVerticalList();
try {
UiObject obj = scrollable.getChildByText(LIST_VIEW_ITEM, contactName, true);
obj.click();
} catch (Exception e) { }
finally {
scrollable.scrollToBeginning(scrollable.getMaxSearchSwipes());
}
}
This code is inefficient. It takes longtime to find each contact and check. Is there away to loop each row and check ?
Thank you.
.

try following code
for(int i=0;i<n;i++)new UiObject(new UiSelector().className("android.widget.CheckBox").instance(i)).click();

I'm not exactly sure but I think it is supposed to work.
Try making a UiCollection (called checkboxes e.g.) of all the checkboxes and then checkboxes.click().
UiCollection inherits this method from UiObject so I would guess it clicks in each of them, but I haven't tried it. If it works I will edit my answer to remove the doubt :)

Related

VrVideoView remove UI

I'm trying to display a 3D stereo video in a googlevr app in a clean fashion, without showing the UI. I know about usability guidelines, but the device running the app will be always kept inside a viewer in a sort of demo, so no touch interaction expected.
I'm using a VrVideoView.
So I already got rid of fullscreen button, info button, stereo mode button, google cardboard tutorial screen named "transition view" and touch tracking to move the view.
videoWidgetView.setFullscreenButtonEnabled(false);
videoWidgetView.setInfoButtonEnabled(false);
videoWidgetView.setStereoModeButtonEnabled(false);
videoWidgetView.setTransitionViewEnabled(false);
videoWidgetView.setTouchTrackingEnabled(false);
I also enabled fullscreen stereo by default.
videoWidgetView.setDisplayMode(VrWidgetView.DisplayMode.FULLSCREEN_STEREO);
But I can't remove the close button "x" and the option button.
I think that the "x" is fullscreenBackButton of VrWidgetView, parent of VrVideoView. Which hasn't methods to control its visibility.
Is there a way to remove those two buttons?
Maybe subclassing and rewriting part of the widget code?
Maybe just a little hack putting a black overlay above those corners?
I've also tried as suggested
findViewById(R.id.ui_back_button).setVisibility(GONE);
or even
findViewById(com.google.vr.widgets.common.R.id.ui_back_button).setVisibility(GONE);
without success, they give:
NullPointerException: Attempt to invoke virtual method 'void android.view.View.setVisibility(int)' on a null object reference
Please check this post: Google VR Unity Divider, Settings and Back button hiding in v0.9.
VrVideoView extends VrWidgetView. There you will find a clue on how to disable the settings button in the updateButtonVisibility() method: vrUiLayer.setSettingsButtonEnabled(displayMode == 3).
Alternatively try tracing the resource ID of the buttons and do:
findViewById(R.id.ui_back_button).setVisibility(GONE);
findViewById(R.id.ui_settings_button).setVisibility(GONE);
You can also iterate on all resources and try disable one by one:
final R.drawable drawableResources = new R.drawable();
final Class<R.drawable> c = R.drawable.class;
final Field[] fields = c.getDeclaredFields();
for (int i = 0, max = fields.length; i < max; i++) {
final int resourceId;
try {
resourceId = fields[i].getInt(drawableResources);
} catch (Exception e) {
continue;
}
/* make use of resourceId for accessing Drawables here */
}
For me this solution works.
It uses field functionality to get vrUiLayer which is a private member of VrWidgetView which is the parent of VrVideoView.
Field f;
try {
f = this.videoWidgetView.getClass().getSuperclass().getDeclaredField("vrUiLayer");
f.setAccessible(true);
UiLayer vrLayer = (UiLayer) f.get(this.videoWidgetView);
// - here you can directly access to the UiLayer class - //
// to hide the up-right settings button
vrLayer.setSettingsButtonEnabled(false);
//setting listener to null hides the x button
vrLayer.setBackButtonListener(null);
// these visibility options are frequently updated when you play videos,
// so you have to call them often
// OR
vrLayer.setEnabled(false); // <- just hide the UI layer
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Don't forget to import the class
import com.google.vr.cardboard.UiLayer
Beware that using vrLayer.setEnabled(false) hides also the center line, leaving a complete clean vr experience.

How To Print Java Program / .Net Program Inside TextView?

Right now i'm doing an educational app.I stucked with some problem.
My app first page has list of java programs name like below
swap two numbers
find biggest number
reverse number
When user press a particular item- it has to go to detail screen and has to display particular program (i mean user press on swap of two no's need to navigate to detail page to display respective program)->right now its going detail view controller
For example I have program like this
/********print star pattern ************/
import java.util.Scanner;
public class Diamond
{
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
System.out.println("Enter N : ");
int n=sc.nextInt();
System.out.print("Enter Symbol : ");
char c = sc.next().charAt(0);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n-i;j++)
{
System.out.print(" ");
}
for(int j=1;j<=i*2-1;j++)
{
System.out.print(c);
}
System.out.println();
}
for(int i=n-1;i>0;i--)
{
for(int j=1;j<=n-i;j++)
{
System.out.print(" ");
}
for(int j=1;j<=i*2-1;j++)
{
System.out.print(c);
}
System.out.println();
}
}
}
How can I print above program in detail in view controller ?
Now am using textview, Is it okay to continue with it or Is any other component that i could make use of ?because some programs have more width and height.
or else any other mechanism is available to achieve this?
I researched a lot but didn't find solution.
Can someone suggest me how to go with this? where to store the program? How to display it?
Thanks.

Appium+Selenium Android: ListView item not clicked without Thread.sleep

I hate using "sleepers" (Thread.sleep(millis)) in tests, but without sleepers some tests fail.
I have a ListView in my Android application and I want to tap on the first item in the list (SAUDI ARABIA in our case).
public AndroidDriver androidDriver;
...
androidDriver = new AndroidDriver(serverAddress, capabilities);
androidDriver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driverWait = new WebDriverWait(androidDriver, 30);
// at this moment everything is initialized and working properly,
// Appium server is up and running
driverWait.until(ExpectedConditions.visibilityOfElementLocated(By.id("com.###.debug:id/countries_list_view")));
WebElement countriesList = driver.findElement(By.id("com.###.debug:id/countries_list_view"));
List<WebElement> countries = countriesList.findElements(By.id("com.###.debug:id/list_item_container"));
WebElement country = countries.get(0);
// country isn't null, and it corresponds to a real ListView row
driverWait.until(ExpectedConditions.elementToBeClickable(country));
Thread.sleep(1000); // <---- country isn't clicked without this
country.click();
The same problem exists in Calabash/Cucumber tests (explicit waits required).
I've tried different ways of waiting for the element which should be clicked
driverWait.until(ExpectedConditions.visibilityOfElementLocated(By));
driverWait.until(ExpectedConditions.visibilityOf(WebElement));
driverWait.until(ExpectedConditions.elementToBeClickable(By));
driverWait.until(ExpectedConditions.presenceOfElementLocated(By));
and none is working. At the moment when I try to tap on the ListView 1st item, ListView exists and is all the list elements are on screen.
I've tried to find the ListView 1st row by getting the list row XPath using Appium Inspector. The result is the same - view isn't clicked without Thread.sleep.
Using Thread.sleep in tests is really bad practice and makes my tests unstable. I can't rely on tests results in this case, as they may fail even if the application is working properly. There's an article about "wait" and "sleep" usage in Selenium tests (Selenium WebDriver wait).
How to fix such issues in tests?
How often Thread.sleep calls used in automation world? (I'm mostly Android developer, and not that experienced in mobile automation).
UPDATE:
I've tried to not to mix up implicit and explicit waits, as JeffC mentioned, and it didn't help.
Here's my test:
#Test
public void selectCountryLanguageAndStartApplication() throws Exception {
countryLanguagePage.loaded();
countryLanguagePage.selectFirstCountry();
countryLanguagePage.pleaseSelectCountryTextIsHidden();
countryLanguagePage.startClick();
}
...
/**
* Verify the page has loaded
*/
public static void loaded() {
driver.findElement(By.id("com.###.debug:id/countries_list_view"));
}
I'm verifying if the page is loaded in every test. If I use only implicit waits - the test fails from time to time; if I use only explicit waits - it's the same, the test fails from time to time.
I've found in Appium tutorial that they use implicit in conjunction with explicit ones 1, 2. It looks weird according to the docs.
The working solution: I've modified a bit loaded method
public static void loaded() {
driver.findElement(By.id("com.###.debug:id/countries_list_view"));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Having that sleep brings the "stability" to test and I can find the elements and press on them with explicit waits or without them.
Does it mean, that I should add "sleep" when the new Activity launched (the only working solution to me)? Or I'm waiting for the Activity initialization in the wrong way?
You could try this:
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.elementToBeClickable(By));
or
while(!driver.findElement(By).isDisplayed())
{
//Thread.sleep(10);
}
I think Thread.sleep calls are fine to use (and almost necessary if your testing involves timing) but for the most part there a better ways to handle most things they would be used for.
Hope this helps,
Liam
I have Tried to write a method , to wait for an element. hope it will work for your case.
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class Utility {
public static AndroidElement element;
public static boolean isElementPresent;
public static boolean waitForPresence(AndroidDriver driver, int timeLimitInSeconds, String targetResourceId){
try{
element = (AndroidElement) driver.findElementByAndroidUIAutomator("new UiSelector().resourceId(\""+targetResourceId+"\")");
WebDriverWait wait = new WebDriverWait(driver, timeLimitInSeconds);
wait.until(ExpectedConditions.visibilityOf(element));
isElementPresent = element.isDisplayed();
return isElementPresent;
}catch(Exception e){
isElementPresent = false;
System.out.println(e.getMessage());
return isElementPresent;
}
}
}

android check if string contains characters other than 0-9

I am creating an app for counting points in games. This app has a edittext component. I want to check if the string retrieved from the edit text contains characters other than 0-9. This is because my app contains a integer.parse function wich crashes if characters other than 0-9 is inputed. All help will be greatly appreciated. Thanks in advance.
If you just want to notify the user of an invalid character then you can wrap it in a try/catch and act accordingly
try
{
int someInt = Integer.parseInt(et.getText().toString());
// other code
}
catch (NumberFormatException e)
{
// notify user with Toast, alert, etc...
}
You also can use a regular expression to look for the characters you want/don't want depending on your needs.
Just to be clear in case my code comment wasn't, I am suggesting that you do something with the exception and notify the user. Don't catch it and let it sit
public static boolean isNumeric(String str)
{
for (char c : str.toCharArray())
{
if (!Character.isDigit(c)) return false;
}
return true;
}
OR
public boolean isNumeric(String s) {
return s.matches("[-+]?\\d*\\.?\\d+");
}
Firstly you can setup edittext as integer numbers only, so in your layout put
android:inputType="number"
It will set to integer numbers only in edit text.
All possible types here:
http://developer.android.com/reference/android/widget/TextView.html#attr_android:inputType
Then you can test with regular expression or/and catch exception when parsing.
Regular expression would be:
"string".matches("\\d+") // true when numbers only, false otherwise
Reference here:
http://developer.android.com/reference/java/lang/String.html#matches(java.lang.String)
http://developer.android.com/reference/java/util/regex/Pattern.html

NotifyDataSetChanged not working on Android 2.1

I am working on an Android app which will support the Ice cream sandwich API but work on older devices such as running android 2.1.
I'm doing this by doing a check of what the current API version is, and if its post ice cream sandwich call one activity and then if its anything below, call a different activity.
I am allowing the user to perform a search, when it gets the results it then clears ArrayList and then adds the items from the search back in, and then calls the arrayadapter.notifydatasetchanged. This code I've copied and pasted from the ICS version into the pre ICS version, the ICS works fine but on the pre ics version the list view doesn't get updated. Below is the code that I have.
public void performSearch(ArrayList<Spanned> searchPasswords)
{
if (searchPasswords.size() > 0)
{
btnClearSearch.setVisibility(View.VISIBLE);
passwords.clear();
for (int i = 0; i < searchPasswords.size(); i++)
{
passwords.add(searchPasswords.get(i));
}
passwordArrayAdapter.notifyDataSetChanged();
btnClearSearch.setOnClickListener(mBtnClearSearch);
common.showToastMessage(searchPasswords.size() + " result(s) found", Toast.LENGTH_LONG);
}
else
{
common.showToastMessage("No search results found", Toast.LENGTH_LONG);
}
}
I've debugged this function so it is definetely calling it, and its displaying the toast messags with saying how many results were found, but the list view doesn't get changed.
Update
I have just made a discovery which is a bit confusing. As a test in the function that does the initial loading of the list view I manually create a new search ArrayList<Spanned> and pass this to the same PerformSearch(ArrayList<Spanned>) that I am having the problem with and this works without any problems.
The problem with the performSearch not updating the ListView only seems to happen when it is being called from onActivityResult. I know that onActivityResult is working fine as when the performSearch function is called it then prints out there is 1 result(s) found so its definitely got data just the list view doesn't get refreshed from the onActivityResult calling the performSearch function.
You can try:
passwordArrayAdapter = new WHAT_EVER_ADAPTER_THIS_IS(searchPasswords, extra_constructor_params);
YOUR_LIST_VIEW.setAdapter(passwordArrayAdapter)
instead of:
passwordArrayAdapter.notifyDataSetChanged();
I had a similar issue. Neither notidfyDataSetChanged() nor setAdapter() worked.
Finally I figured out a solution which may not be as efficient as using notifyDataSetChanged() but it works.
/**
* Updates courses' list adapter.
*/
private void updateListAdapter()
{
final ArrayAdapter a = (ArrayAdapter) coursesList.getAdapter();
runOnUiThread(new Runnable()
{
public void run()
{
populteCoursesList();
a.clear();
for (MainScreenListModel model : listModels)
{
a.add(model);
}
a.notifyDataSetChanged();
}
});
}
courseList is my custom list. populateCoursesList() gets the data from db and listModels is a Vector of models for list view.
As you can see I have to clear the adapter and fill it once again.
I think your mistake is to forget to clear the adapter, if you try it like this it should work:
public void performSearch(ArrayList<Spanned> searchPasswords)
{
if (searchPasswords.size() > 0)
{
btnClearSearch.setVisibility(View.VISIBLE);
passwordArrayAdapter.clear();
for (int i = 0; i < searchPasswords.size(); i++)
{
passwordArrayAdapter.add(searchPasswords.get(i));
}
passwordArrayAdapter.notifyDataSetChanged();
btnClearSearch.setOnClickListener(mBtnClearSearch);
common.showToastMessage(searchPasswords.size() + " result(s) found", Toast.LENGTH_LONG);
}
else
{
common.showToastMessage("No search results found", Toast.LENGTH_LONG);
}
}
passwords.clear();
for (int i = 0; i < searchPasswords.size(); i++)
{
passwords.add(searchPasswords.get(i));
}
passwordArrayAdapter.notifyDataSetChanged();
As per the code, u r modifying the list(passwords), but is it the same instance that is being used by the adapter (passwordArrayAdapter). If not then notifyDataSetChanged() wont work.
From my understanding, you can either set the list again with a new instance of passwordArrayAdapter.
ur_list_view.setAdapter(new PasswordArrayAdapter(newly_formed_password_list, and other parameters));
or use getter and setter to update the list(passwords) and then call notifyDataSetChanged()
I dont know much from only the code snippet you've pasted but from what I see there is no persistent link between passwords and the passwordsArrayAdapter....passwordsArrayAdapter initialises itself with the elements of passwords and passwordsArrayAdapter will not know when passwords changes. To add new items you should call passwordsArrayAdapter.add(searchPasswords).Dont bother calling notifyDataSetChanged() explicitly.
public void performSearch(ArrayList<Spanned> searchPasswords)
{
if (searchPasswords.size() > 0)
{
btnClearSearch.setVisibility(View.VISIBLE);
passwordArrayAdapter.clear();
passwordArrayAdapter.setNotifyOnChange(true);
for (int i = 0; i < searchPasswords.size(); i++)
{
passwordArrayAdapter.add(searchPasswords.get(i));
}
btnClearSearch.setOnClickListener(mBtnClearSearch);
common.showToastMessage(searchPasswords.size() + " result(s) found", Toast.LENGTH_LONG);
}
else
{
common.showToastMessage("No search results found", Toast.LENGTH_LONG);
}
}
I wouldnt think there'd be a relation with the onActivityResult bit -- the above code should fix it.
Call notifyOnChange(false) before clearing and adding the new entries. Otherwise, the clear() and every add() internally trigger a call to notifyDataSetChanged(), which, as I experienced, confuses the ListView. Keep your explicit notifyDataSetChanged(), which also resets the internal notifyOnChange flag to true again.
Thanks everyone for your help and suggestions, I've managed to find out what the problem was.
In my OnResume method for the activity I call a function called populateListArray which retrieves all of the information from the database and lists in the ListView.
When the activity was returned it was calling the OnResume method so after it got the results it then reset the list view back with all the original content.
To get round it I added a variable called performingSearch which I initialise to false. When I perform the search I set this to true and in the onResume, if the variable is true I don't do anything and after the perform search function has finished I set the variable back to false again.
Thanks everyone again for your help

Categories

Resources