Android has a technique where you can turn text into a button. You set the element to clickable, and then define an onClick() method for it.
On the Appium side, what I'm seeing is that the text for the element ends with an "#" character. For example from "UI Automator Viewer" :
(2) TextView: Purchase an item # [69,1038][1011,1110]
The '#' is displayed as an arrow symbol on the actual phone, and clicking on the arrow, and only the arrow, will take you to a different dialog (one to make a purchase in this case). Manually clicking on the text itself does not move the app to the dialog. Only clicking on the arrow works.
My Python code looks like:
self.driver.find_element_by_id("com.mycompany.project:id/make_a_purchase_text").click()
The click() method does not take me to the correct dialog. In fact, nothing apparent happens at all. I am click()ing on a lot of elements that are buttons in order to get to this point, so I know my setup is good. Is there any support at all in Appium for this sort of control?
I'm not sure whether this is the best way of doing it. To me it seems that selenium WebElement cannot detect the additional properties given to a TextView or a UIAStaticText. So when we assign a click property the base class behind the element cannot do the click event.
So as a workaround i sent a touch event to the required x,y location
driver.executeScript("mobile: tap", new HashMap<String, Double>() {
{
put("tapCount", 1d);
put("touchCount", 1d);
put("duration", 0.52478515625);
put("x", 127d);
put("y", 571d);
}
});
Related
I have a button in Android which has text "Next" written on it.
when, I have the accsessibility cursor focus on the button, it reads out "Next button". This is something I don't want. I want whenever, the cursor to have focus on the "Next" button, it must read out as "Next button. Double tap to select". This I can easily do, by setting the
btn.contentDescription("Next button. Double tap to select"),
but then it reads out as
"Next button. Double tap to select button", means it additionally reads out the last button, which seems very odd, with the "button" text getting read twice.
Is there any way, by which I can stop the last button to be announced?
You're trying to do things that are the responsibility of the AT. The AT knows that the object is a button due to its class type. The AT knows that it is clickable, because Clickable is a valid accessibility action.
TalkBack will then share this information, here is the breakdown:
"Next button, (pause) double tap to select"
"Next" -> Content Description/Text. This is the part you control.
"Button" -> Calculated in TalkBack based off of the valid actions and type(class) of the object.
"Double tap to select" -> This announcement is based off of Clickable being a valid accessibility action.
SO, when you set the contentdescription to "Next ....." you end up with an announcement of "next ....... button (pause) double tap to select" and no, there is no way to override this.
IF you are absolutely intent on making your app less accessible, you could create a custom control, write your own gesture recognizers (as in not using "onClick" events, because this would make your element accessibility clickable) to recognize tap gestures. And then write your own content description, that includes name, role, and instructions yourself.
This would be very silly in my opinion! Just let the content-description be "next" and let TalkBack tell users that your element is a button and how to interact with it. While perhaps not the "perfect" wording you/whoever this requirement came from's vision. It will be the way TalkBack users are accustomed to having this type of control announced. Consistency is sometimes more important than having things "just so".
I know I'm way late to the game, but posting an answer here for anyone that may happen to come across this post.
The others are right... we should not be putting the type of widget or how to interact with the widget in the content description. However, all is not lost.
Starting with API 21, there is a way to customize the interaction text through AccessibilityNodeInfo. You can use this class in two different ways:
AccessibilityNodeInfo has a getActionList() method. You can add customize the text that is read out by TalkBack by adding a new item to that list:
info.getActionList().add(new AccessibilityNodeInfo.AccessibilityAction(AccessibilityAction.ACTION_CLICK, "select");
The above code should change "Double-tap to activate" to "Double-tap to select". I say should because I'm just writing that code from memory... I haven't verified it's 100% correct, but it should be something along those lines.
There are two ways to utilize that class, and the one you choose is going to depend on your situation.
Method 1: Subclass your view:
If you create a subclass of the view you are using (in the case of the OP it would be a subclass of Button) then you can override the onInitializeAccessibilityNodeInfo() method and put the code there.
Documentation: https://developer.android.com/reference/android/view/View.html#onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo)
Method 2: Create a view accessibility delegate
This can be a bit more tricky and involved, but it does offer a ton of flexibility because you don't have to subclass the views you are working with.
Every view has a method that allows you to set an accessibility delegate, which acts like a man-in-the-middle and you can tweak things for accessibility purposes before the info goes to TalkBack.
Documentation: https://developer.android.com/reference/android/view/View.html#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)
So basically you create a subclass of View.AccessibilityDelegate and override it's onInitializeAccessibilityNodeInfo() method with the code I posted above.
Documentation: https://developer.android.com/reference/android/view/View.AccessibilityDelegate.html#onInitializeAccessibilityNodeInfo(android.view.View,%20android.view.accessibility.AccessibilityNodeInfo)
Last but not least...
I did come across a way to stop the "Double tap to activate" text from being spoken out by Talkback. This should only be used when it really does make sense to remove it.
I repeat... this is not normally something you want to do.
I did recently come across a case where it made sense. I was using a TabLayout, and I noticed that Talkback would always read out "Double-tap to select" when the focus was on the selected tab (yes, I had used the method described above to change the text). Well... we don't want to tell the user to select a tab that is already selected, especially when the action results in a no-op. So, I used this little trick to get rid of that, but only for the currently selected tab. I left the unselected tabs alone so that Talkback would still give them the interaction text.
In your onInitializeAccessibilityNodeInfo() method, you can put the following code to remove that text:
info.addAction(AccessibilityNodeInfo.ACTION_FOCUS);
Again, I'm writing this code from memory, so I don't know if that's 100% there, but it gives you the gist of what to do.
Try to uncheck the setting in TalkBack -> verbosity -> speak element type -> uncheck. Now talkback will not announce class type of view at end of content description.
What you want to do is employ android:hint to provide information on inputting information (instead of adding it to the label).
Your label would be "Next" (either using labelFor with an onscreen label or android:contentDescription for hidden labeling)
Then your hint would be "Double tap to select" (using android:hint)
I am creating automated tests using appium to test an android app. The issue that I am facing right now, is that I cannot select a checkbox, because the checkbox contains linked text.
I am using the following code to get checkbox element and click it -
WebElement termsAndConditionsCheckbox = (new WebDriverWait(driver, 60)).until(ExpectedConditions.presenceOfElementLocated(By.id(baseTest.getAndroidElementId("checkbox_terms_and_conditions"))));
termsAndConditionsCheckbox.click();
In app code, the checkbox's text is set as follows -
mCheckboxTermsAndConditions.setText(Html.fromHtml(mSignUpAcceptTermsAndConditions));
mCheckboxTermsAndConditions.setMovementMethod(LinkMovementMethod.getInstance());
From debugging options on android device, I turned on the options to see pointer location of click event, and I see the appium clicks at the center of the checkbox (box + text), and unfortunately, that point contains a linked text, so the webview is launched, as opposed to "checking" the checkbox
I do not see a custom click() in appium, which would allow me to check the checkbox.
Would appreciate any ideas / help.
You can use find element By.className instead of By.id.
So for multiple such elements you can have them referenced with index (in this case 0), for example.
WebElement submit = (WebElement) driver.findElements(By.className(RADIO_BUTTON)).get(0);
submit.click();
Hoping this helps.
In this case, Instead of clicking on the checkbox directly..first get the location of checkbox and adjust the location by adding / subtracting some pixels so that it will always click on the exactly on the checkbox and not in the centre of the whole checkbox element.
You can use below code snippet :
WebElement element =driver.findelement(By.xpath("YourXpath"));
Point p=element.getLocation();
driver.tap(1, p.getX()+10, p.getY()+10, 1);
I just downloaded AOSP and modified TextView for my purpose.
I have added a LongClick Listener to the TextView, which shows a simple Toast.
Since I modified the Android framework, it is reflected into all the apps and entire Android OS.
I have now run into a weird issue where the TextView is getting focus in some places and other underlying widgets are not getting any focus. This is creating lot of issues.
For eg: In Settings app, The 'Wi-Fi' text is receiving focus, but I cannot enter the wi-fi settings unless I click in any empty area in the Wi-Fi list item.
(I hope am clear!)
Another example: I am unable to select the Radio Button just because the text corresponding to Radio Button receives focus.
So my question is:
Is there any way I can make TextView non-focusable but receive Long Click events?
Is there any way I can pass the focus down to the parent layout?
Any other way you can suggest?
(PS: Please do not say what I am doing is right or wrong. It's just a feasibility test for what I am trying to achieve.)
A view does have the attributes "focusable" and "longClickable". Have you tried a combination of these?
I have a EditBox, and on right side of this EditBox I wan't to put a Button representing "Get My Position".
User clicks on this button, and my application get his position and fills EditBox with it.
I found a Compass and added on a ImageButton, but I don't know if this really represent the idea.
Anyone knows a better button to represent "Get My Position"?
Thanks
Your Button looks ok, and will be recognized by most users. If you want to get the System-default (the picture of the Drawalbe may differ on roms from HTC, Samsung Motorola etc) you can get it with
getResources.getDrawable(android.R.drawable.ic_menu_location)
Always check for non-Null here. You can download the standart Android location Button here, (ic_menu_location), as a fallback, if the getDrawable() call fails
I used a 'globe' in my application. If the EditBox is blank until the user requests their location, why not use the put some default text inside it requesting the user to click the button?
Pretty new to android so excuse me if this is a really obvious question.
Say my application has a bunch of TextViews, each one showing the attributes of a certain product (name, price, etc). I have a button next to each of these TextViews labeled "modify".
How do I make it so that when I press the modify button next to a certain attribute, a popup window with a space to enter text into comes up so that the user can enter text into this box and then have the actual attribute listing on the original page change? Actually I just need a push in the right direction with creating this popup text field... not sure if there is already some built in functionality for this or if not, what would be the best way to create this kind of thing.
Thanks.
Why not have the modify button set TextEdit.setEnabled(true); and then change focus with TextEdit.setFocus? Note that both of these are inherited from view
If you really want a dialog you might want to looking into the AlertDialog.Builder. I know you can use it with buttons and radio buttons, but I'm not sure you can get it to work with a TextView.
Use a code like this for the input popup: Android dialog input text
In the positive button handler, set your edittext content programmatically like this:
myEditText.setText(value).
As simple as that. The only difference with a standard GUI framework is that you don't retrieve the value as a result of the popup function. Instead, you must provide an action handler.