lib/appium_lib_core/android/device.rb



# frozen_string_literal: true

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require_relative 'device/emulator'
require_relative 'device/clipboard'
require_relative 'device/performance'
require_relative 'device/screen'
require_relative 'device/auth_finger_print'

module Appium
  module Core
    module Android
      module Device
        extend Forwardable

        # rubocop:disable Layout/LineLength

        # @!method open_notifications
        #   Open Android notifications
        #
        # @example
        #
        #   @driver.open_notifications
        #

        # @!method current_activity
        # Get current activity name
        # @return [String] An activity name
        #
        # @example
        #
        #   @driver.current_activity # '.ApiDemos'
        #

        # @!method current_package
        # Get current package name
        # @return [String] A package name
        #
        # @example
        #
        #   @driver.current_package # 'com.example.android.apis'
        #

        # @!method get_system_bars
        # Get system bar's information
        # @return [String]
        #
        # @example
        #
        #   @driver.get_system_bars
        #   @driver.system_bars
        #

        # @!method get_display_density
        # Get connected device's density.
        # @return [Integer] The size of density
        #
        # @example
        #
        #   @driver.get_display_density # 320
        #

        # @!method location
        # Get the location of the device.
        #
        # @return [::Appium::Location]
        #
        # @example
        #
        #   driver.location #=> ::Appium::Location.new(10, 10, 10)
        #
        # @!method location=
        # Set the [::Appium::Location] of the device.
        #
        # @example
        #
        #   driver.location = ::Appium::Location.new(10, 10, 10)
        #

        # @!method set_location(latitude, longitude, altitude, speed: nil, satellites: nil)
        # Set the location of the device.
        #
        # @param [String, Number] latitude Set the latitude.
        # @param [String, Number] longitude Set the longitude.
        # @param [String, Number] altitude Set the altitude.
        # @param [String, Number] speed Set the speed to apply the location on Android real devices
        #                               in meters/second @since Appium 1.21.0 and in knots for emulators @since Appium 1.22.0.
        # @param [String, Number] satellites Sets the count of geo satellites being tracked in range 1..12 @since Appium 1.22.0.
        #                                    This number is respected on Emulators.
        #
        # @example
        #
        #   driver.set_location 10, 10, 0
        #

        # @!method toggle_location_services
        #   Switch the state of the location service
        #
        # @return [String]
        #
        # @example
        #
        #   @driver.toggle_location_services
        #

        # @!method hide_keyboard(close_key = nil)
        # Hide the onscreen keyboard
        # @param [String] close_key The name of the key which closes the keyboard.
        #   Defaults to 'Done' for iOS(except for XCUITest).
        #
        # @example
        #
        #  @driver.hide_keyboard                   # Close a keyboard with the 'Done' button
        #  @driver.hide_keyboard('Finished')       # Close a keyboard with the 'Finished' button
        #

        # @!method get_performance_data_types
        #   Get the information type of the system state which is supported to read such as
        #   cpu, memory, network, battery via adb commands.
        #   https://github.com/appium/appium-base-driver/blob/be29aec2318316d12b5c3295e924a5ba8f09b0fb/lib/mjsonwp/routes.js#L300
        #
        # @example
        #
        #   @driver.get_performance_data_types #=> ["cpuinfo", "batteryinfo", "networkinfo", "memoryinfo"]
        #

        # @!method get_performance_data(package_name:, data_type:)
        #   Get the resource usage information of the application.
        #   https://github.com/appium/appium-base-driver/blob/be29aec2318316d12b5c3295e924a5ba8f09b0fb/lib/mjsonwp/routes.js#L303
        # @param [String] package_name: Package name
        # @param [String] data_type: Data type get with +get_performance_data_types+
        #
        # @example
        #
        #   @driver.get_performance_data package_name: package_name, data_type: data_type
        #

        # @!method start_recording_screen(remote_path: nil, user: nil, pass: nil, method: 'PUT', file_field_name: nil, form_fields: nil, headers: nil, force_restart: nil, video_size: nil, time_limit: '180', bit_rate: '4000000', bug_report: nil)
        # @param [String] remote_path The path to the remote location, where the resulting video should be uploaded.
        #                             The following protocols are supported: http/https, ftp.
        #                             Null or empty string value (the default setting) means the content of resulting
        #                             file should be encoded as Base64 and passed as the endpoint response value.
        #                             An exception will be thrown if the generated media file is too big to
        #                             fit into the available process memory.
        #                             This option only has an effect if there is screen recording process in progress
        #                             and +forceRestart+ parameter is not set to +true+.
        # @param [String] user The name of the user for the remote authentication.
        # @param [String] pass The password for the remote authentication.
        # @param [String] method The http multipart upload method name. The 'PUT' one is used by default.
        # @param [String] file_field_name The name of the form field containing the binary payload in multipart/form-data
        #                             requests since Appium 1.18.0. Defaults to 'file'.
        # @param [Array<Hash, Array<String>>] form_fields The form fields mapping in multipart/form-data requests since Appium 1.18.0.
        #                             If any entry has the same key in this mapping, then it is going to be ignored.
        # @param [Hash] headers The additional headers in multipart/form-data requests since Appium 1.18.0.
        # @param [Boolean] force_restart Whether to try to catch and upload/return the currently running screen recording
        #                                 (+false+, the default setting on server) or ignore the result of it
        #                                 and start a new recording immediately (+true+).
        #
        # @param [String] video_size The format is widthxheight.
        #                            The default value is the device's native display resolution (if supported),
        #                            1280x720 if not. For best results,
        #                            use a size supported by your device's Advanced Video Coding (AVC) encoder.
        #                            For example, "1280x720"
        # @param [String] time_limit Recording time. 180 seconds is by default.
        #                            Since Appium 1.8.2 the time limit can be up to 1800 seconds (30 minutes).
        #                            Appium will automatically try to merge the 3-minutes chunks recorded
        #                            by the screenrecord utility, however, this requires FFMPEG utility
        #                            to be installed and available in PATH on the server machine. If the utility is not
        #                            present then the most recent screen recording chunk is going to be returned as the result.
        # @param [String] bit_rate The video bit rate for the video, in megabits per second.
        #                          4 Mbp/s(4000000) is by default for Android API level below 27. 20 Mb/s(20000000) for API level 27 and above.
        # @param [Boolean] bug_report Set it to +true+ in order to display additional information on the video overlay,
        #                             such as a timestamp, that is helpful in videos captured to illustrate bugs.
        #                             This option is only supported since API level 27 (Android P).
        # @return [String] Base64 encoded content of the recorded media file or an empty string
        #                  if the file has been successfully uploaded to a remote location (depends on the actual options)
        #
        # @example
        #
        #    @driver.start_recording_screen
        #    @driver.start_recording_screen video_size: '1280x720', time_limit: '180', bit_rate: '5000000'
        #

        # @!method get_clipboard(content_type: :plaintext)
        #   Set the content of device's clipboard.
        # @param [String] content_type: one of supported content types.
        # @return [String]
        #
        # @example
        #
        #   @driver.get_clipboard #=> "happy testing"
        #

        # @!method set_clipboard(content:, content_type: :plaintext, label: nil)
        #   Set the content of device's clipboard.
        # @param [String] label: clipboard data label.
        # @param [String] content_type: one of supported content types.
        # @param [String] content: Contents to be set. (Will encode with base64-encoded inside this method)
        #
        # @example
        #
        #   @driver.set_clipboard(content: 'happy testing') #=> {"protocol"=>"W3C"}
        #

        # @!method finger_print(finger_id)
        #     Authenticate users by using their finger print scans on supported emulators.
        #
        # @param [Integer] finger_id Finger prints stored in Android Keystore system (from 1 to 10)
        #
        # @example
        #
        #   @driver.finger_print 1
        #

        # @!method execute_cdp(cmd, **params)
        #     Execute Chrome Devtools protocol commands
        #     https://chromedevtools.github.io/devtools-protocol
        #
        # @param [String] cmd The name of command
        # @option params The parameter for the command as keyword options.
        #
        # @example
        #
        #   @driver.execute_cdp 'Page.captureScreenshot', quality: 50, format: 'jpeg'
        #   @driver.execute_cdp 'Page.getResourceTree'
        #
        #   # for Ruby 2,7 and 3+ compatibility
        #   params = {'timezoneId': 'Asia/Tokyo'}
        #   driver.execute_cdp 'Emulation.setTimezoneOverride', **params
        #

        ####
        ## class << self
        ####

        # rubocop:enable Layout/LineLength

        class << self
          def extended(_mod)
            ::Appium::Core::Device.extend_webdriver_with_forwardable

            ::Appium::Core::Device.add_endpoint_method(:open_notifications) do
              def open_notifications
                execute_script 'mobile:openNotifications', {}
              end
            end

            ::Appium::Core::Device.add_endpoint_method(:current_activity) do
              def current_activity
                execute_script 'mobile:getCurrentActivity', {}
              end
            end

            ::Appium::Core::Device.add_endpoint_method(:current_package) do
              def current_package
                execute_script 'mobile:getCurrentPackage', {}
              end
            end

            ::Appium::Core::Device.add_endpoint_method(:get_system_bars) do
              def get_system_bars
                execute_script 'mobile:getSystemBars', {}
              end
            end
            # as alias to get_system_bars
            ::Appium::Core::Device.add_endpoint_method(:system_bars) do
              def system_bars
                execute_script 'mobile:getSystemBars', {}
              end
            end

            ::Appium::Core::Device.add_endpoint_method(:toggle_location_services) do
              def toggle_location_services
                execute_script 'mobile:toggleGps', {}
              end
            end

            # Android, Override included method in bridge
            ::Appium::Core::Device.add_endpoint_method(:hide_keyboard) do
              def hide_keyboard(_close_key = nil)
                execute_script 'mobile:hideKeyboard', {}
              end
            end

            # Android, Override included method in bridge
            ::Appium::Core::Device.add_endpoint_method(:background_app) do
              def background_app(duration = 0)
                execute_script 'mobile:backgroundApp', { seconds: duration }
              end
            end

            ::Appium::Core::Device.add_endpoint_method(:execute_cdp) do
              # SeleniumWebdriver could already define this method
              return if method_defined? :execute_cdp

              def execute_cdp(cmd, **params)
                execute :chrome_send_command, {}, { cmd: cmd, params: params }
              end
            end

            Screen.add_methods
            Performance.add_methods
            Clipboard.add_methods
            Emulator.add_methods
            Authentication.add_methods
          end
        end
      end # module Device
    end # module Android
  end
end # module Appium