class Calabash::Cucumber::Automator::DeviceAgent

@!visibility private

Constants

RETURN_KEY_TYPE

@!visibility private

Keys are from the UIReturnKeyType enum.

The values are localization independent identifiers - these are stable across localizations and keyboard languages. The exception is Continue which is not stable.

SPECIAL_ACTION_CHARS

@!visibility private

Don’t change the double quotes.

Attributes

client[R]

Public Class Methods

expect_valid_args(args) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 29
        def self.expect_valid_args(args)
          if args.nil?
            raise ArgumentError, "Expected args to be a non-nil Array"
          end

          if !args.is_a?(Array)
            raise ArgumentError, %Q[Expected args to be an Array, found:

args = #{args}

]
          end

          if args.count != 1
            raise(ArgumentError,
                  %Q[Expected args to be an Array with one element, found:

args = #{args}

])
          end

          if !args[0].is_a?(RunLoop::DeviceAgent::Client)
            raise(ArgumentError, %Q[
Expected first element of args to be a RunLoop::DeviceAgent::Client instance, found:
args[0] = #{args[0]}])
          end

          true
        end
new(*args) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 63
def initialize(*args)
  DeviceAgent.expect_valid_args(args)
  @client = args[0]
end

Public Instance Methods

char_for_keyboard_action(action_key) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 271
def char_for_keyboard_action(action_key)
  SPECIAL_ACTION_CHARS[action_key]
end
dismiss_ipad_keyboard() click to toggle source

@!visibility private

Stable across different keyboard languages.

# File lib/calabash-cucumber/automator/device_agent.rb, line 307
def dismiss_ipad_keyboard
  client.touch({marked: "Hide keyboard"})
end
double_tap(options) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 99
def double_tap(options)
  hash = query_for_coordinates(options)
  client.perform_coordinate_gesture("double_tap",
                                    hash[:coordinates][:x],
                                    hash[:coordinates][:y])
  [hash[:view]]
end
enter_char_with_keyboard(char) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 266
def enter_char_with_keyboard(char)
  client.enter_text_without_keyboard_check(char)
end
enter_text_with_keyboard(string, options={}) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 261
def enter_text_with_keyboard(string, options={})
  client.enter_text_without_keyboard_check(string)
end
fast_enter_text(text) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 300
def fast_enter_text(text)
  client.enter_text_without_keyboard_check(text)
end
flick(options) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 235
def flick(options)
  gesture_options = {
    duration: 0.2
  }

  delta = options[:delta]

  # The UIA deltas are too small.
  scaled_delta = {
    :x => delta[:x] * 2.0,
    :y => delta[:y] * 2.0
  }

  hash = query_for_coordinates(options)
  view = hash[:view]

  start_point = point_from(view)
  end_point = point_from(view, {:offset => scaled_delta})

  client.pan_between_coordinates(start_point,
                                 end_point,
                                 gesture_options)
  [view]
end
name() click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 69
def name
  :device_agent
end
pan(from_query, to_query, options) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 197
def pan(from_query, to_query, options)
  dupped_options = options.dup

  dupped_options[:query] = from_query
  from_hash = query_for_coordinates(dupped_options)
  from_point = from_hash[:coordinates]

  dupped_options[:query] = to_query
  to_hash = query_for_coordinates(dupped_options)
  to_point = to_hash[:coordinates]

  gesture_options = {
    duration: dupped_options[:duration],
    num_fingers: dupped_options.fetch(:num_fingers, 1),
    first_touch_hold_duration:
      dupped_options.fetch(:first_touch_hold_duration, 0.0)
  }

  client.pan_between_coordinates(from_point, to_point, gesture_options)

  [from_hash[:view], to_hash[:view]]
end
pan_coordinates(from_point, to_point, options) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 221
def pan_coordinates(from_point, to_point, options)

  gesture_options = {
    duration: options[:duration],
    num_fingers: options.fetch(:num_fingers, 1),
    first_touch_hold_duration:
      options.fetch(:first_touch_hold_duration, 0.0)
  }

  client.pan_between_coordinates(from_point, to_point, gesture_options)
  [first_element_for_query("*")]
end
pinch(in_out, options) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 166
def pinch(in_out, options)
  dupped_options = options.dup

  if dupped_options[:query].nil?
    element = element_for_device_screen
    coordinates = point_from(element, options)
  else
    hash = query_for_coordinates(dupped_options)
    element = hash[:view]
    coordinates = hash[:coordinates]
  end

  in_out = in_out.to_s
  duration = dupped_options[:duration]
  amount = dupped_options[:amount]

  gesture_options = {
    :pinch_direction => in_out,
    :amount => amount,
    :duration => duration
  }

  client.perform_coordinate_gesture("pinch",
                                    coordinates[:x],
                                    coordinates[:y],
                                    gesture_options)

  [element]
end
rotate(direction) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 312
def rotate(direction)
  # Caller is responsible for normalizing and verifying direction.
  current_orientation = status_bar_orientation.to_sym
  key = orientation_key(direction, current_orientation)
  position = orientation_for_key(key)
  rotate_home_button_to(position)
end
rotate_home_button_to(position) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 321
def rotate_home_button_to(position)
  # Caller is responsible for normalizing and verifying position.
  client.rotate_home_button_to(position)
  status_bar_orientation.to_sym
end
running?() click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 79
def running?
  client.send(:running?)
end
session_delete() click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 84
def session_delete
  client.send(:session_delete)
end
stop() click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 74
def stop
  client.send(:shutdown)
end
swipe(options) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 129
def swipe(options)
  dupped_options = options.dup

  if dupped_options[:query].nil?
    element = element_for_device_screen
    from_point = point_from(element, options)
  else
    hash = query_for_coordinates(dupped_options)
    from_point = hash[:coordinates]
    element = hash[:view]
  end

  # DeviceAgent does not understand the :force. Does anyone?
  force = dupped_options[:force]
  case force
    when :strong
      duration = 0.2
    when :normal
      duration = 0.4
    when :light
      duration = 0.7
    else
      # Caller is responsible for validating the :force option.
      duration = 0.5
  end

  gesture_options = {
    :duration => duration
  }

  direction = dupped_options[:direction]
  to_point = Coordinates.end_point_for_swipe(direction, element, force)
  client.pan_between_coordinates(from_point, to_point, gesture_options)
  [element]
end
tap_keyboard_action_key() click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 276
def tap_keyboard_action_key
  mark = mark_for_return_key_of_first_responder
  if mark
    begin
      # The underlying query for coordinates always expects results.
      value = client.touch({type: "Button", marked: mark})
      return value
    rescue RuntimeError => _
      RunLoop.log_debug("Cannot find mark '#{mark}' with query; will send a newline")
    end
  else
    RunLoop.log_debug("Cannot find keyboard return key type; sending a newline")
  end

  code = char_for_keyboard_action("Return")
  client.enter_text_without_keyboard_check(code)
end
tap_keyboard_delete_key() click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 295
def tap_keyboard_delete_key
  client.touch({marked: "delete"})
end
touch(options) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 89
def touch(options)
  hash = query_for_coordinates(options)

  client.perform_coordinate_gesture("touch",
                                    hash[:coordinates][:x],
                                    hash[:coordinates][:y])
  [hash[:view]]
end
touch_hold(options) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 117
def touch_hold(options)
  hash = query_for_coordinates(options)

  duration = options[:duration] || 3
  client.perform_coordinate_gesture("touch",
                                    hash[:coordinates][:x],
                                    hash[:coordinates][:y],
                                    {:duration => duration})
  [hash[:view]]
end
two_finger_tap(options) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 108
def two_finger_tap(options)
  hash = query_for_coordinates(options)
  client.perform_coordinate_gesture("two_finger_tap",
                                    hash[:coordinates][:x],
                                    hash[:coordinates][:y])
  [hash[:view]]
end

Private Instance Methods

element_for_device_screen() click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 393
def element_for_device_screen
  screen_dimensions = device.screen_dimensions

  scale = screen_dimensions[:scale]
  height = (screen_dimensions[:height]/scale).to_i
  center_y = (height/2)
  width = (screen_dimensions[:width]/scale).to_i
  center_x = (width/2)

  {
    "screen" => true,
    "rect" => {
      "height" => height,
      "width" => width,
      "center_x" => center_x,
      "center_y" => center_y
    }
  }
end
first_element_for_query(uiquery) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 376
def first_element_for_query(uiquery)

  if uiquery.nil?
    raise ArgumentError, "Query cannot be nil"
  end

  # Will raise if response "outcome" is not SUCCESS
  results = Calabash::Cucumber::Map.raw_map(uiquery, :query)["results"]

  if results.empty?
    nil
  else
    results[0]
  end
end
mark_for_return_key_of_first_responder() click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 482
def mark_for_return_key_of_first_responder
  number = return_key_type_of_first_responder
  mark_for_return_key_type(number)
end
mark_for_return_key_type(number) click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 447
def mark_for_return_key_type(number)
  # https://xamarin.atlassian.net/browse/TCFW-361
  value = RETURN_KEY_TYPE[number]
  if value == "Join" && !simulator?
    "Join:"
  else
    value
  end
end
query_for_coordinates(options) click to toggle source

@!visibility private

Calls point_from which applies any :offset supplied in the options.

# File lib/calabash-cucumber/automator/device_agent.rb, line 332
        def query_for_coordinates(options)
          uiquery = options[:query]

          if uiquery.nil?
            offset = options[:offset]

            if offset && offset[:x] && offset[:y]
              {
                :coordinates => offset,
                :view => offset
              }
            else
              raise ArgumentError, %Q[
If query is nil, there must be a valid offset in the options.

Expected: options[:offset] = {:x => NUMERIC, :y => NUMERIC}
  Actual: options[:offset] = #{offset ? offset : "nil"}

              ]
            end
          else

            first_element = first_element_for_query(uiquery)

            if first_element.nil?
              msg = %Q[
Could not find any views with query:

  #{uiquery}

Make sure your query returns at least one view.

]
              Calabash::Cucumber::Map.new.screenshot_and_raise(msg)
            else
              {
                :coordinates => point_from(first_element, options),
                :view => first_element
              }
            end
          end
        end
return_key_type_of_first_responder() click to toggle source

@!visibility private

# File lib/calabash-cucumber/automator/device_agent.rb, line 458
def return_key_type_of_first_responder

  query = "* isFirstResponder:1"
  raw = Calabash::Cucumber::Map.raw_map(query, :query, :returnKeyType)
  elements = raw["results"]
  return nil if elements.count == 0

  return_key_type = elements[0]

  # first responder did not respond to :text selector
  if return_key_type == "*****"
    RunLoop.log_debug("First responder does not respond to :returnKeyType")
    return nil
  end

  if return_key_type.nil?
    RunLoop.log_debug("First responder has nil :returnKeyType")
    return nil
  end

  return_key_type
end