diff --git a/CHANGELOG.md b/CHANGELOG.md index bcda8af8..4898486b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. - `0, 1, 2, 3, 4` or `NOT_INSTALLED, NOT_RUNNING, RUNNING_IN_BACKGROUND_SUSPENDED, RUNNING_IN_BACKGROUND, RUNNING_IN_FOREGROUND` - After: Symbol. - `:not_installed, :not_running, :running_in_background_suspended, :running_in_background, :running_in_foreground` +- add `battery_info` to get battery information - add `is_keyboard_shown` for iOS ( see also https://github.com/appium/appium-xcuitest-driver/pull/664/files ) ### Bug fixes diff --git a/lib/appium_lib_core/android/uiautomator2/bridge.rb b/lib/appium_lib_core/android/uiautomator2/bridge.rb index f10ae1f5..5e1074c9 100644 --- a/lib/appium_lib_core/android/uiautomator2/bridge.rb +++ b/lib/appium_lib_core/android/uiautomator2/bridge.rb @@ -6,6 +6,7 @@ module Bridge def self.for(target) target.extend Appium::Android::Device Core::Android::SearchContext.extend + target.extend Appium::Core::Android::Uiautomator2::Device end end end diff --git a/lib/appium_lib_core/android/uiautomator2/device.rb b/lib/appium_lib_core/android/uiautomator2/device.rb new file mode 100644 index 00000000..7fcbe092 --- /dev/null +++ b/lib/appium_lib_core/android/uiautomator2/device.rb @@ -0,0 +1,50 @@ +module Appium + module Core + module Android + module Uiautomator2 + module Device + extend Forwardable + + # @since 1.6.0 + # @!method battery_info + # + # Get battery information. + # + # @return [Hash] Return battery level and battery state. + # Battery level in range [0.0, 1.0], where 1.0 means 100% charge. -1 is returned + # if the actual value cannot be retrieved from the system. + # Battery state. The following symbols are possible + # `:unknown, :charging, :discharging, :not_charging, :full` + # + # @example + # + # @driver.battery_info #=> { state: :charging, level: 0.7 } + # + + #### + ## class << self + #### + + class << self + def extended(_mod) + ::Appium::Core::Device.add_endpoint_method(:battery_info) do + def battery_info + response = execute_script 'mobile: batteryInfo', {} + + state = case response['state'] + when 2, 3, 4, 5 + ::Appium::Core::Device::BatteryStatus::ANDROID[response['state']] + else + Appium::Logger.warn("The state is unknown or undefined: #{response['state']}") + ::Appium::Core::Device::BatteryStatus::ANDROID[1] # :unknown + end + { state: state, level: response['level'] } + end + end + end + end # class << self + end # module Device + end # module Uiautomator2 + end # module Android + end # module Core +end # module Appium diff --git a/lib/appium_lib_core/android_uiautomator2.rb b/lib/appium_lib_core/android_uiautomator2.rb index eaedd65f..0cf058cc 100644 --- a/lib/appium_lib_core/android_uiautomator2.rb +++ b/lib/appium_lib_core/android_uiautomator2.rb @@ -1,4 +1,6 @@ # loaded in common/driver.rb require_relative 'android/search_context' require_relative 'android/device' + require_relative 'android/uiautomator2/bridge' +require_relative 'android/uiautomator2/device' diff --git a/lib/appium_lib_core/device/multi_touch.rb b/lib/appium_lib_core/common/touch_action/multi_touch.rb similarity index 100% rename from lib/appium_lib_core/device/multi_touch.rb rename to lib/appium_lib_core/common/touch_action/multi_touch.rb diff --git a/lib/appium_lib_core/device/touch_actions.rb b/lib/appium_lib_core/common/touch_action/touch_actions.rb similarity index 88% rename from lib/appium_lib_core/device/touch_actions.rb rename to lib/appium_lib_core/common/touch_action/touch_actions.rb index 7700ebe1..099ff581 100644 --- a/lib/appium_lib_core/device/touch_actions.rb +++ b/lib/appium_lib_core/common/touch_action/touch_actions.rb @@ -1,23 +1,23 @@ module Appium - # Perform a series of gestures, one after another. Gestures are chained - # together and only performed when `perform()` is called. Default is conducted by global driver. - # - # Each method returns the object itself, so calls can be chained. - # - # Consider to use W3C spec touch action like the followings. - # https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/W3CActionBuilder.html - # https://github.com/appium/ruby_lib_core/blob/master/test/functional/android/webdriver/w3c_actions_test.rb - # https://github.com/appium/ruby_lib_core/blob/master/test/functional/ios/webdriver/w3c_actions_test.rb - # - # @example - # - # @driver = Appium::Core.for(self, opts).start_driver - # action = TouchAction.new(@driver).press(x: 45, y: 100).wait(5).release - # action.perform - # action = TouchAction.new(@driver).swipe(....) - # action.perform - # module Core + # Perform a series of gestures, one after another. Gestures are chained + # together and only performed when `perform()` is called. Default is conducted by global driver. + # + # Each method returns the object itself, so calls can be chained. + # + # Consider to use W3C spec touch action like the followings. + # https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/W3CActionBuilder.html + # https://github.com/appium/ruby_lib_core/blob/master/test/functional/android/webdriver/w3c_actions_test.rb + # https://github.com/appium/ruby_lib_core/blob/master/test/functional/ios/webdriver/w3c_actions_test.rb + # + # @example + # + # @driver = Appium::Core.for(self, opts).start_driver + # action = TouchAction.new(@driver).press(x: 45, y: 100).wait(5).release + # action.perform + # action = TouchAction.new(@driver).swipe(....) + # action.perform + # class TouchAction ACTIONS = %i(move_to long_press double_tap two_finger_tap press release tap wait perform).freeze COMPLEX_ACTIONS = %i(swipe).freeze diff --git a/lib/appium_lib_core/device.rb b/lib/appium_lib_core/device.rb index a3432000..2c90c2b8 100644 --- a/lib/appium_lib_core/device.rb +++ b/lib/appium_lib_core/device.rb @@ -1,5 +1,5 @@ -require_relative 'device/touch_actions' -require_relative 'device/multi_touch' +require_relative 'common/touch_action/touch_actions' +require_relative 'common/touch_action/multi_touch' require_relative 'device/screen_record' require_relative 'device/app_state' require_relative 'device/clipboard_content_type' diff --git a/lib/appium_lib_core/device/battery_status.rb b/lib/appium_lib_core/device/battery_status.rb new file mode 100644 index 00000000..1c3885fe --- /dev/null +++ b/lib/appium_lib_core/device/battery_status.rb @@ -0,0 +1,23 @@ +module Appium + module Core + module Device + module BatteryStatus + ANDROID = [ + :undefined, # 0, dummy + :unknown, # 1 + :charging, # 2 + :discharging, # 3 + :not_charging, # 4 + :full # 5 + ].freeze + + IOS = [ + :unknown, # 0 + :unplugged, # 1 + :charging, # 2 + :full # 3 + ].freeze + end + end + end +end diff --git a/lib/appium_lib_core/ios/xcuitest/device.rb b/lib/appium_lib_core/ios/xcuitest/device.rb index 96e0d912..09f87a35 100644 --- a/lib/appium_lib_core/ios/xcuitest/device.rb +++ b/lib/appium_lib_core/ios/xcuitest/device.rb @@ -109,6 +109,23 @@ module Device # @driver.get_performance_record # @driver.get_performance_record(save_file_path: './performance', profile_name: 'Activity Monitor') + # @since 1.6.0 + # @!method battery_info + # + # Get battery information. + # + # @return [Hash] Return battery level and battery state from the target real device. (Simulator has no battery.) + # https://developer.apple.com/documentation/uikit/uidevice/ 's `batteryLevel` and `batteryState`. + # Battery level in range [0.0, 1.0], where 1.0 means 100% charge. -1 is returned + # if the actual value cannot be retrieved from the system. + # Battery state. The following symbols are possible + # `:unplugged, :charging, :full` + # + # @example + # + # @driver.battery_info #=> { state: :full, level: 0.7 } + # + # rubocop:enable Metrics/LineLength #### @@ -117,8 +134,6 @@ module Device class << self def extended(_mod) - ::Appium::Core::Device.extend_webdriver_with_forwardable - # Override ::Appium::Core::Device.add_endpoint_method(:hide_keyboard) do def hide_keyboard(close_key = nil, strategy = nil) @@ -143,10 +158,28 @@ def background_app(duration = 0) add_performance add_screen_recording + add_battery_info end private + def add_battery_info + Appium::Core::Device.add_endpoint_method(:battery_info) do + def battery_info + response = execute_script 'mobile: batteryInfo', {} + + state = case response['state'] + when 1, 2, 3 + ::Appium::Core::Device::BatteryStatus::IOS[response['state']] + else + Appium::Logger.warn("The state is unknown or undefined: #{response['state']}") + ::Appium::Core::Device::BatteryStatus::IOS[0] # :unknown + end + { state: state, level: response['level'] } + end + end + end + def add_performance Appium::Core::Device.add_endpoint_method(:start_performance_record) do def start_performance_record(timeout: 300_000, profile_name: 'Activity Monitor', pid: nil) diff --git a/lib/appium_lib_core/ios_xcuitest.rb b/lib/appium_lib_core/ios_xcuitest.rb index 00123b6d..e26c37ad 100644 --- a/lib/appium_lib_core/ios_xcuitest.rb +++ b/lib/appium_lib_core/ios_xcuitest.rb @@ -5,3 +5,5 @@ require_relative 'ios/xcuitest/search_context' require_relative 'ios/xcuitest/device' require_relative 'ios/xcuitest/bridge' + +require_relative 'device/battery_status' diff --git a/test/functional/android/android/device_test.rb b/test/functional/android/android/device_test.rb index e3a3dd03..ab32c079 100644 --- a/test/functional/android/android/device_test.rb +++ b/test/functional/android/android/device_test.rb @@ -389,6 +389,13 @@ def test_image_comparison_get_images_result File.delete 'get_images_result_visual.png' end + def test_battery_info + result = @@driver.battery_info + + assert !result[:state].nil? + assert !result[:level].nil? + end + private def scroll_to(text) diff --git a/test/functional/ios/ios/device_test.rb b/test/functional/ios/ios/device_test.rb index 4ee034ab..8b8f7a5a 100644 --- a/test/functional/ios/ios/device_test.rb +++ b/test/functional/ios/ios/device_test.rb @@ -44,11 +44,11 @@ def test_close_and_launch_app end def test_lock_unlock - @@driver.lock 5 - assert @@driver.device_locked? + @@driver.lock + @@core.wait { assert @@driver.device_locked? } @@driver.unlock - assert !@@driver.device_locked? + @@core.wait { assert !@@driver.device_locked? } end def test_background_reset @@ -301,6 +301,13 @@ def test_image_comparison_get_images_result File.delete 'get_images_result_visual.png' end + + def test_battery_info + result = @@driver.battery_info + + assert !result[:state].nil? + assert !result[:level].nil? + end end end end diff --git a/test/unit/android/device_test.rb b/test/unit/android/device_test.rb index 02371334..c5d57933 100644 --- a/test/unit/android/device_test.rb +++ b/test/unit/android/device_test.rb @@ -755,6 +755,18 @@ def test_image_comparison_get_images_similarity assert_requested(:post, "#{SESSION}/appium/compare_images", times: 1) end + + def test_get_battery_info + stub_request(:post, "#{SESSION}/execute") + .with(body: { script: 'mobile: batteryInfo', args: [{}] }.to_json) + .to_return(headers: HEADER, status: 200, body: { value: { state: 2, level: 1.0 } }.to_json) + + info = @driver.battery_info + + assert_requested(:post, "#{SESSION}/execute", times: 1) + assert_equal :charging, info[:state] + assert_equal 1.0, info[:level] + end end end end diff --git a/test/unit/android/device_w3c_test.rb b/test/unit/android/device_w3c_test.rb index e1bfff54..8968d9a7 100644 --- a/test/unit/android/device_w3c_test.rb +++ b/test/unit/android/device_w3c_test.rb @@ -732,6 +732,18 @@ def test_image_comparison_get_images_similarity assert_requested(:post, "#{SESSION}/appium/compare_images", times: 1) end + + def test_get_battery_info + stub_request(:post, "#{SESSION}/execute/sync") + .with(body: { script: 'mobile: batteryInfo', args: [{}] }.to_json) + .to_return(headers: HEADER, status: 200, body: { value: { state: 5, level: 0.5 } }.to_json) + + info = @driver.battery_info + + assert_requested(:post, "#{SESSION}/execute/sync", times: 1) + assert_equal :full, info[:state] + assert_equal 0.5, info[:level] + end end end end diff --git a/test/unit/ios/device_test.rb b/test/unit/ios/device_test.rb index e96cdc92..558c3c1e 100644 --- a/test/unit/ios/device_test.rb +++ b/test/unit/ios/device_test.rb @@ -128,6 +128,18 @@ def test_stop_recording_screen_custom assert_requested(:post, "#{SESSION}/appium/stop_recording_screen", times: 1) end + + def test_get_battery_info + stub_request(:post, "#{SESSION}/execute") + .with(body: { script: 'mobile: batteryInfo', args: [{}] }.to_json) + .to_return(headers: HEADER, status: 200, body: { value: { state: 3, level: 1.0 } }.to_json) + + info = @driver.battery_info + + assert_requested(:post, "#{SESSION}/execute", times: 1) + assert_equal :full, info[:state] + assert_equal 1.0, info[:level] + end end end end diff --git a/test/unit/ios/device_w3c_test.rb b/test/unit/ios/device_w3c_test.rb index ff7dc6d8..7c0530fb 100644 --- a/test/unit/ios/device_w3c_test.rb +++ b/test/unit/ios/device_w3c_test.rb @@ -115,6 +115,18 @@ def test_stop_recording_screen_custom assert_requested(:post, "#{SESSION}/appium/stop_recording_screen", times: 1) end + + def test_get_battery_info + stub_request(:post, "#{SESSION}/execute/sync") + .with(body: { script: 'mobile: batteryInfo', args: [{}] }.to_json) + .to_return(headers: HEADER, status: 200, body: { value: { state: 1, level: 0.5 } }.to_json) + + info = @driver.battery_info + + assert_requested(:post, "#{SESSION}/execute/sync", times: 1) + assert_equal :unplugged, info[:state] + assert_equal 0.5, info[:level] + end end end end