lib/calabash-cucumber/keyboard_helpers.rb in calabash-cucumber-0.16.2 vs lib/calabash-cucumber/keyboard_helpers.rb in calabash-cucumber-0.16.3

- old
+ new

@@ -4,10 +4,22 @@ require 'calabash-cucumber/environment_helpers' require 'calabash-cucumber/utils/logging' module Calabash module Cucumber + + + # Raised when there is a problem involving a keyboard mode. There are + # three keyboard modes: docked, split, and undocked. + # + # All iPads support these keyboard modes, but the user can disable them + # in Settings.app. + # + # The iPhone 6+ family also supports keyboard modes, but Calabash does + # support keyboard modes on these devices. + class KeyboardModeError < StandardError; ; end + # Collection of methods for interacting with the keyboard. # # We've gone to great lengths to provide the fastest keyboard entry possible. # # If you are having trouble with skipped or are receiving JSON octet @@ -78,40 +90,27 @@ # Keyboards on the iPhone and iPod are docked. # # @return [Boolean] if a keyboard is visible and docked. def docked_keyboard_visible? res = query(_qstr_for_keyboard).first + return false if res.nil? return true if device_family_iphone? - rect = res['rect'] - o = status_bar_orientation.to_sym - case o - when :left - if ios8? - rect['center_x'] == 512 and rect['center_y'] == 592 - else - rect['center_x'] == 592 and rect['center_y'] == 512 - end - when :right - if ios8? - rect['center_x'] == 512 and rect['center_y'] == 592 - else - rect['center_x'] == 176 and rect['center_y'] == 512 - end - when :up - if ios8? - rect['center_x'] == 384 and rect['center_y'] == 892 - else - rect['center_x'] == 384 and rect['center_y'] == 132 - end - when :down - rect['center_x'] == 384 and rect['center_y'] == 892 - else - false + orientation = status_bar_orientation.to_sym + keyboard_height = res['rect']['height'] + keyboard_y = res['rect']['y'] + scale = screen_dimensions[:scale] + + if orientation == :left || orientation == :right + screen_height = screen_dimensions[:width]/scale + else + screen_height = screen_dimensions[:height]/scale end + + screen_height - keyboard_height == keyboard_y end # Returns true if an undocked keyboard is visible. # # A undocked keyboard is floats in the middle of the view. @@ -591,14 +590,10 @@ raise 'the keyboard mode does not exist on the on the iphone' if device_family_iphone? raise 'cannot detect keyboard mode key without launching with instruments' unless uia_available? res = send_uia_command({:command => "#{_query_uia_hide_keyboard_button}.rect()"}) origin = res['value']['origin'] {:x => origin['x'], :y => origin['y']} - - # this did not work. - #size = res['value']['size'] - #{:x => (origin['x'] (size['width']/2)), :y => (origin['y'] (size['height']/2))} end # @!visibility private # Returns a query string for touching one of the options that appears when # the iPad mode key is touched and held. @@ -698,12 +693,14 @@ if uia_available? start_pt = _point_for_ipad_keyboard_mode_key # there are 10 pt btw the key and the popup and each row is 50 pt # NB: no amount of offsetting seems to allow touching the top row # when the keyboard is split + + x_offset = 40 y_offset = 10 + 50 + 25 - end_pt = {:x => (start_pt[:x] - 40), :y => (start_pt[:y] - y_offset)} + end_pt = {:x => (start_pt[:x] - x_offset), :y => (start_pt[:y] - y_offset)} uia_pan_offset(start_pt, end_pt, {:duration => 1.0}) else pan(_query_for_keyboard_mode_key, nil, {}) touch(_query_for_touch_for_keyboard_mode_option(:top, mode)) sleep(0.5) @@ -724,19 +721,27 @@ wait_for_keyboard return if device_family_iphone? mode = ipad_keyboard_mode - case mode - when :split then - _touch_bottom_keyboard_mode_row - when :undocked then - _touch_top_keyboard_mode_row - when :docked then - # already docked - else - screenshot_and_raise "expected '#{mode}' to be one of #{_ipad_keyboard_modes}" + + return if mode == :docked + + if ios9? + raise KeyboardModeError, + 'Changing keyboard modes is not supported on iOS 9' + else + case mode + when :split then + _touch_bottom_keyboard_mode_row + when :undocked then + _touch_top_keyboard_mode_row + when :docked then + # already docked + else + screenshot_and_raise "expected '#{mode}' to be one of #{_ipad_keyboard_modes}" + end end begin wait_for({:post_timeout => 1.0}) do docked_keyboard_visible? @@ -746,11 +751,10 @@ o = status_bar_orientation screenshot_and_raise "expected keyboard to be ':docked' but found '#{mode}' in orientation '#{o}'" end end - # Ensures that the iPad keyboard is undocked. # # Undocked means the keyboard is floating in the middle of the view. # # If the device is not an iPad, this is behaves like a call to @@ -760,39 +764,46 @@ # `wait_for_keyboard`. # # @raise [RuntimeError] if there is no visible keyboard # @raise [RuntimeError] an undocked keyboard was not achieved def ensure_undocked_keyboard - wait_for_keyboard() + wait_for_keyboard return if device_family_iphone? mode = ipad_keyboard_mode - case mode - when :split then - # keep these condition separate because even though they do the same - # thing, the else condition is a hack - if ios5? - # iOS 5 has no 'Merge' feature in split keyboard, so dock first then - # undock from docked mode - _touch_bottom_keyboard_mode_row - _wait_for_keyboard_in_mode(:docked) + + return if mode == :undocked + + if ios9? + raise KeyboardModeError, + 'Changing keyboard modes is not supported on iOS 9' + else + case mode + when :split then + # keep these condition separate because even though they do the same + # thing, the else condition is a hack + if ios5? + # iOS 5 has no 'Merge' feature in split keyboard, so dock first then + # undock from docked mode + _touch_bottom_keyboard_mode_row + _wait_for_keyboard_in_mode(:docked) + else + # in iOS > 5, it seems to be impossible consistently touch the + # the top keyboard mode popup button, so we punt + _touch_bottom_keyboard_mode_row + _wait_for_keyboard_in_mode(:docked) + end + _touch_top_keyboard_mode_row + when :undocked then + # already undocked + when :docked then + _touch_top_keyboard_mode_row else - # in iOS > 5, it seems to be impossible consistently touch the - # the top keyboard mode popup button, so we punt - _touch_bottom_keyboard_mode_row - _wait_for_keyboard_in_mode(:docked) - end - _touch_top_keyboard_mode_row - when :undocked then - # already undocked - when :docked then - _touch_top_keyboard_mode_row - else - screenshot_and_raise "expected '#{mode}' to be one of #{_ipad_keyboard_modes}" + screenshot_and_raise "expected '#{mode}' to be one of #{_ipad_keyboard_modes}" + end end - _wait_for_keyboard_in_mode(:undocked) end # Ensures that the iPad keyboard is split. @@ -812,20 +823,27 @@ wait_for_keyboard return if device_family_iphone? mode = ipad_keyboard_mode - case mode - when :split then - # already split - when :undocked then - _touch_bottom_keyboard_mode_row - when :docked then - _touch_bottom_keyboard_mode_row - else - screenshot_and_raise "expected '#{mode}' to be one of #{_ipad_keyboard_modes}" - end + return if mode == :split + + if ios9? + raise KeyboardModeError, + 'Changing keyboard modes is not supported on iOS 9' + else + case mode + when :split then + # already split + when :undocked then + _touch_bottom_keyboard_mode_row + when :docked then + _touch_bottom_keyboard_mode_row + else + screenshot_and_raise "expected '#{mode}' to be one of #{_ipad_keyboard_modes}" + end + end _wait_for_keyboard_in_mode(:split) end # @!visibility private def _wait_for_keyboard_in_mode(mode, opts={})