I need to get the exact coordinates of a point relative to the screen regardless of the app window's dimensions or offsets/insets. The phone I'm developing on has a 1080x2280 resolution and android 9. I tried to find the screen dimensions using getDefaultDisply, but the notch height is getting subtracted from the screen:
// Testing with notch hidden; the screen is pushed down below it
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); // 1080x2062 (-notification bar height!)
getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics); // 1080x2192 (actual window height when notch is hidden)
How do I get the real resolution and the notch heigh when it's hidden?
Solution I found was to use getRealMetrics to get the height of the screen.
getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics)
This calculates the height of the screen by including the height of the notch as well. Works for both Notched Mode ON/OFF also for devices without Notch
I found my own solution that works on rooted devices only (requires Shell library):
public static int getCutoutHeight() {
CommandResult result = Shell.SU.run("dumpsys display | grep mCurrentDisplayRect");
String output = result.getStdout();
String regex = "^\\s+mCurrentDisplayRect=Rect\\(\\d+, (\\d+) - \\d+, \\d+\\)*$";
if (output != null) {
if (output.matches(regex)) {
Pattern patt = Pattern.compile(regex);
Matcher matcher = patt.matcher(output);
if (matcher.find()) {
return Integer.parseInt(matcher.group(1));
}
}
else Log.e(TAG, "Unexpedted outptu: " + output);
}
else Log.e(TAG, "Command failed: " + result.getStderr());
return 0;
}
Hopefully a better answer will come up soon.
Related
For my Native Android App , I have been trying for the past 2 weeks to get appium to scroll down on my native app. I have tried driver.scrollTo("Accounts");
Then I got this error
[org.openqa.selenium.WebDriverException: CATCH_ALL: io.selendroid.server.common.exceptions.SelendroidException: method (by) not found: -android uiautomator
and many other examples that I have found. Nothing seems to work . This is the latest example that I have tried .
Using appium 1.5.2 and appium java client version: ‘3.3.0'. When I try to run the following code.
TouchAction tAction=new TouchAction(driver);
int startx = driver.findElement(By.id("line_chart_line_chart")).getLocation().getX();
int starty = driver.findElement(By.id("line_chart_line_chart")).getLocation().getY();
int endx = driver.findElement(By.id("actionBarLogo")).getLocation().getX();
int endy = driver.findElement(By.id("actionBarLogo")).getLocation().getY();
System.out.println(startx + " ::::::: " + starty + " ::::::: " + endx + " ::::::: " + endy);
// This is what the console printed out startX=560 ::::::: starty=1420 ::::::: endx=560 ::::::: endy=240
//First tap on the screen and swipe up using moveTo function
tAction.press(startx,starty).moveTo(endx,endy).release().perform();
Then I get this error message
org.openqa.selenium.WebDriverException: An unknown server-side error occurred while processing the command. Original error: Could not proxy. Proxy
error: Could not proxy command to remote server. Original error: 404 - undefined (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 27 milliseconds
I am at a loss on what to do. In order to click on an element it has to be visible on the screen . In order for this element to appear on the screen I need to scroll down to it.
Is there something that I am doing wrong??? I just can't seem to figure it out.
You used Selendroid mode, which does not support UiAutomator By method.
You can change your appium running mode to UiAutomator by setting desired capability automationName to Appium
This function does the trick for me, put in "Accounts" for elementName when calling it in your case.
public static void scrollToElementAndroid(AndroidDriver driver, String elementName, boolean scrollDown) {
String listID = ((RemoteWebElement) driver.findElementByAndroidUIAutomator("new UiSelector().className(android.widget.ListView)")).getId();
String direction;
if (scrollDown) {
direction = "down";
} else {
direction = "up";
}
HashMap<String, String> scrollObject = new HashMap<String, String>();
scrollObject.put("direction", direction);
scrollObject.put("element", listID);
scrollObject.put("text", elementName);
driver.executeScript("mobile: scrollTo", scrollObject);
}
Use code like below:
Dimension size = driver.manage().window().getSize();
int x = size.width / 2;
int endy = (int) (size.height * 0.75);
int starty = (int) (size.height * 0.20);
driver.swipe(x, starty, x, endy, 1000);
I'm using Java to automate tests for mobile web on ios safari
Everything seems to be set up correctly but appium is crashing with the error:
uncaughtException: Cannot read property 'x' of undefined
the touch command comes through in the logs like so:
info: --> POST /wd/hub/session/1a925d31-d3cd-4231-9698-f7ff4db739fd/touch/perform {"actions":[{"action":"press","options":{"element":"5001"}},{"action":"wait","options":{"ms":1}},{"action":"release","options":{}}]}
info: [debug] Pushing command to appium work queue: "au.getElement('5001').rect()"
info: [debug] Sending command to instruments: au.getElement('5001').rect()
my code looks like this:
public void tap(MobileElement element) {
appiumDriver.context(getContext("NATIVE"));
element.tap(1,1);
appiumDriver.context(getContext("WEBVIEW"));
}
protected String getContext(String partial) {
String result = null;
Set<String> contextNames = driver.getContextHandles();
for (String contextName : contextNames) {
if(contextName.contains(partial)){
result = contextName;
}
}
if (result == null){
throw new NoSuchContextException("Could not find requested context");
}
return result;
}
and I'm feeding it a mobileElement.
I can get the element location by treating it like a WebElement and doing getlocation() and then I can use a TouchAction, which works in terms of what appium is doing, but the location is super off so I'm trying to use the mobileElement tap() action here instead.
Does anyone know a workaround or see what I might be doing wrong? My site has a lot of elements that require a tap().
This also occurs when I define a WebElement, then move into Native context and use iosDriver.tap(1, webelement, 1); with the same crash on the appium side.
Try below:
AppiumDriver appiumDriver = new AppiumDriver();
String originalContext = appiumDriver.getContext();
Point coordinate = element.getLocation();
Dimension loc = element.getSize();
int centerX = loc.getWidth() / 2 + coordinate.getX();
int centerY = loc.getHeight() / 2 + coordinate.getY();
appiumDriver.context("NATIVE_APP");
appiumDriver.tap(1, centerX, centerY, 2);
appiumDriver.context(originalContext);
The Issues is that, in Native context Appium does not have any visibility to webelements on the webPage, You need to get the coordinated and then click using Tap method with coordinates
In the settings of the printer I made a new Format named custom1 with width 57 and height 100. Also I changed the custom format to the same width and height.
With the following routine I tried to figure out the supported mediasizes:
Media[] res = (Media[])printService.getSupportedAttributeValues(Media.class, null, null);
for (Media media : res) {
if (media instanceof MediaSizeName) {
MediaSizeName msn = (MediaSizeName) media;
MediaSize ms = MediaSize.getMediaSizeForName(msn);
float width = ms.getX(MediaSize.MM);
float height = ms.getY(MediaSize.MM);
System.out.println("Class:" + msn.getClass().getName()
+ "; toString:" + msn.toString() + "; width:"
+ width + "; height:" + height);
}
}
But in the list is neither custom nor custom1. Also about the half number of the formats are missing in the list.
What is the problem? Does this printer not support the MediaSizes in Java?
What can I do?
When I test this on another printer the custom MediaSize with the right width and height is supported. Where is the problem with this printer?
Thanks for all answers
Using some code from this question I have set up some code to detect when an android device is rotated. It works great for the asus tablet (4.0.3) and two simulators (4.0.3 and 2.1), but for the kindle fire (2.3.4), and droidx (2.3.4) it switches the width and height.
Code:
<script type="text/javascript">
var supportsOrientationChange = "onorientationchange" in window,orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";
window.addEventListener(orientationEvent, function() {
alert("The rotation is " + window.orientation + " and the resolution is " + screen.width + " x " + screen.height);
modRule();
}, false);
</script>
Output from asus tablet
Holding it in what looks like landscape:
The rotation is 0 and the resolution is 1280 x 800
Portrait
The rotation is -90 and the resolution is 800 x 1280
Output from Kindle Fire
Landscape
The rotation is 90 and the resolution is 600 x 819
Portrait:
The rotation is 0 and the resolution is 1024 x 395
output from droidx
landscape:
The rotation is 90 and the resolution is 320x488
Portrait:
The rotation is 0 and the resolution is 569x239
Is there a way I can
a) Make the javascript detect if it should use height instead of width or width instead of height
OR
b) Make the devices report the correct values for their width and height?
After looking for a while longer I found out that this is a bug with the 2.2 and 2.3 OS. I fixed the bug with 2.3.4 by putting this code in my app.
browser = (WebView)findViewById(R.id.webBrowser);
browser.setBackgroundColor(Color.BLACK);
WebSettings webSettings = browser.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setUserAgentString("Android " + android.os.Build.VERSION.SDK);//this is so the JavaScript knows what version of the OS I'm using
And then for detecting if I'm in landscape mode:
var uagent = navigator.userAgent.toLowerCase();
function isLandscape()
{
var width = screen.width;
var height = screen.height;
if (isBugged())
{
var temp = width;
width = height;
height = temp;
}
var landscape = width > height;
return landscape;
}
function isBugged()
{
return uagent == "android 10"
}
And if that wasn't confusing enough, when the body initially loads, it's right about if it's in landscape mode or not. So I had to bypass my own workaround.
<body onload="if(isBugged()){uagent = 'bypass';}/*code that depends on isLandscape()*/;uagent = navigator.userAgent.toLowerCase();">
It's a real pain, a lot more work than it should be. Especially since it works in 2.1 but not 2.3.4. Really frustrating, but that's what I have. At the moment, I only check for sdk 10, I'm going to add checking for the other bugged versions soon.
My friend made an application using javascript, and uploaded it to his website.
Now I'm trying to wrap it into a webview in android, and that's working fine in some ways.
The page is 480x320
But no matter what screensize I select on Android, there is a white space at the bottom on the webview. I have tried a lot of ways to make it zoom, but nothing worked.
My code at this moment is this
final WebView browser = (WebView)findViewById(R.id.webview);
browser.getSettings().setJavaScriptEnabled(true);
browser.loadUrl("http://page.xx");
I needed to scale-to-fit for the width and this variation of FunkTheMonk's answer worked well for me:
#Override
public void onPageFinished(android.webkit.WebView view, String url)
{
super.onPageFinished(view, url);
WindowManager manager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(metrics);
metrics.widthPixels /= metrics.density;
loadUrl("javascript:var scale = " + metrics.widthPixels + " / document.body.scrollWidth; document.body.style.zoom = scale;");
}
wb.loadUrl("javascript:document.body.style.zoom = "+String.valueOf(scale)+";");
Where scale is a float, which you could calculate - I think in your case you want something like the following: browser.getHeight() / 480dp.
Load this Url after your webpage has finished loading.
Can you try to add :
browser.getSettings().setBuiltInZoomControls(true);
browser.setInitialScale(1);
browser.setPadding(0, 0, 0, 0);
And see if it's working ?