michael@0: package org.mozilla.gecko.tests; michael@0: michael@0: import org.mozilla.gecko.Actions; michael@0: import org.mozilla.gecko.PaintedSurface; michael@0: michael@0: import android.net.Uri; michael@0: michael@0: /** michael@0: * A test to ensure that when an input field is focused, it is not obscured by the VKB. michael@0: * - Loads a page with an input field past the bottom of the visible area. michael@0: * - scrolls down to make the input field visible at the bottom of the screen. michael@0: * - taps on the input field to bring up the VKB michael@0: * - verifies that the input field is still visible. michael@0: */ michael@0: public class testVkbOverlap extends PixelTest { michael@0: private static final int CURSOR_BLINK_PERIOD = 500; michael@0: private static final int LESS_THAN_CURSOR_BLINK_PERIOD = CURSOR_BLINK_PERIOD - 50; michael@0: private static final int PAGE_SETTLE_TIME = 5000; michael@0: michael@0: public void testVkbOverlap() { michael@0: blockForGeckoReady(); michael@0: testSetup("initial-scale=1.0, user-scalable=no", false); michael@0: testSetup("initial-scale=1.0", false); michael@0: testSetup("", "phone".equals(mDevice.type)); michael@0: } michael@0: michael@0: private void testSetup(String viewport, boolean shouldZoom) { michael@0: loadAndPaint(getAbsoluteUrl("/robocop/test_viewport.sjs?metadata=" + Uri.encode(viewport))); michael@0: michael@0: // scroll to the bottom of the page and let it settle michael@0: Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint(); michael@0: MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop()); michael@0: meh.dragSync(10, 150, 10, 50); michael@0: michael@0: // the input field has a green background, so let's count the number of green pixels michael@0: int greenPixelCount = 0; michael@0: michael@0: PaintedSurface painted = waitForPaint(paintExpecter); michael@0: paintExpecter.unregisterListener(); michael@0: try { michael@0: greenPixelCount = countGreenPixels(painted); michael@0: } finally { michael@0: painted.close(); michael@0: } michael@0: michael@0: mAsserter.ok(greenPixelCount > 0, "testInputVisible", "Found " + greenPixelCount + " green pixels after scrolling"); michael@0: michael@0: paintExpecter = mActions.expectPaint(); michael@0: // the input field should be in the bottom-left corner, so tap thereabouts michael@0: meh.tap(5, mDriver.getGeckoHeight() - 5); michael@0: michael@0: // After tapping in the input field, the page needs some time to do stuff, like draw and undraw the focus highlight michael@0: // on the input field, trigger the VKB, process any resulting events generated by the system, and scroll the page. So michael@0: // we give it a few seconds to do all that. We are sufficiently generous with our definition of "few seconds" to michael@0: // prevent intermittent test failures. michael@0: try { michael@0: Thread.sleep(PAGE_SETTLE_TIME); michael@0: } catch (InterruptedException ie) { michael@0: ie.printStackTrace(); michael@0: } michael@0: michael@0: // now that the focus is in the text field we will repaint every 500ms as the cursor blinks, so we need to use a smaller michael@0: // "no paints" threshold to consider the page painted michael@0: paintExpecter.blockUntilClear(LESS_THAN_CURSOR_BLINK_PERIOD); michael@0: paintExpecter.unregisterListener(); michael@0: painted = mDriver.getPaintedSurface(); michael@0: try { michael@0: // if the vkb scrolled into view as expected, then the number of green pixels now visible should be about the michael@0: // same as it was before, since the green pixels indicate the text input is in view. use a fudge factor of 0.9 to michael@0: // account for borders and such of the text input which might still be out of view. michael@0: int newCount = countGreenPixels(painted); michael@0: michael@0: // if zooming is allowed, the number of green pixels visible should have increased substatially michael@0: if (shouldZoom) { michael@0: mAsserter.ok(newCount > greenPixelCount * 1.5, "testVkbOverlap", "Found " + newCount + " green pixels after tapping; expected " + greenPixelCount); michael@0: } else { michael@0: mAsserter.ok((Math.abs(greenPixelCount - newCount) / greenPixelCount < 0.1), "testVkbOverlap", "Found " + newCount + " green pixels after tapping; expected " + greenPixelCount); michael@0: } michael@0: } finally { michael@0: painted.close(); michael@0: } michael@0: } michael@0: michael@0: private int countGreenPixels(PaintedSurface painted) { michael@0: int count = 0; michael@0: for (int y = painted.getHeight() - 1; y >= 0; y--) { michael@0: for (int x = painted.getWidth() - 1; x >= 0; x--) { michael@0: int pixel = painted.getPixelAt(x, y); michael@0: int r = (pixel >> 16) & 0xFF; michael@0: int g = (pixel >> 8) & 0xFF; michael@0: int b = (pixel & 0xFF); michael@0: if (g > (r + 0x30) && g > (b + 0x30)) { michael@0: // there's more green in this pixel than red or blue, so count it. michael@0: // the reason this is so hacky-looking is because even though green is supposed to michael@0: // be (r,g,b) = (0x00, 0x80, 0x00), the GL readback ends up coming back quite michael@0: // different. michael@0: count++; michael@0: } michael@0: // uncomment for debugging: michael@0: // if (pixel != -1) mAsserter.dumpLog("Pixel at " + x + ", " + y + ": " + Integer.toString(pixel, 16)); michael@0: } michael@0: } michael@0: return count; michael@0: } michael@0: }