def _connect(self):
        """
        in my experience, it was better to connect, send commands, disconnect right away
        rather than connect once and send many commands for hours => getting very slow at some point
        Now added auto-reconnect feature with argument auto_reconnect_seconds defaulting to 1 min
        """
        now = time.time()
        if self._device and self._last_connected_time + self.auto_reconnect_seconds < now:
            self._disconnect()

        if self._device:
            return


        if self.verbose:
            print(f">>> connecting to {self.ip}")
        self._last_connected_time = now
        self._device = AdbDeviceTcp(self.ip, default_timeout_s=self.auto_reconnect_seconds)
        if not self.need_auth:
            self._device.connect(auth_timeout_s=0.1)
        else:
            with open(os.path.expanduser('~/.android/adbkey')) as f:
                private_key = f.read()
            signer = PythonRSASigner('', private_key)
            self._device.connect(rsa_keys=[signer], auth_timeout_s=0.1)

        if self.verbose:
            print(f">>> connected")
Beispiel #2
0
    def _adb_init(self):
        """"""
        count = 0
        res = -1
        num_of_try = 60

        # Start Timer
        timer = Timer()
        timer.start()

        while (count < num_of_try):
            if timer.elapsed_time_s(2) >= 1:
                print("- Waiting for SX5 device " + "." * count, end='\r')
                res = subprocess.run(
                    "adb devices", text=True, capture_output=True).stdout.find(
                        self._sx5_config_dict['SX5']['device'])
                if (res != -1):
                    timer.stop()
                    break
                else:
                    timer.reset()

                count += 1
        if res == -1:
            sys.stdout.write("\033[K")
            print("No Device Found")
            raise ADB_Error
        else:
            sys.stdout.write("\033[K")
            self._sx5_device = AdbDeviceTcp(
                host=self._sx5_config_dict['SX5']['ip'],
                port=int(self._sx5_config_dict['SX5']['port']),
                default_transport_timeout_s=9.)
        pass
Beispiel #3
0
def Connect_ADB():
    global ADBDevice
    host = request.args.get('host')
    print("ADB_Driver: host:", host)
    logger.info("ADB_Driver: connecting to host: " + host)
    try:  # Checking if we are already connected.
        ADBDevice = ADBHostList[host]["ADBSocket"]
        return
    except:
        logger.info("Setting up connection ADB with " + host)

    ADBDevice = AdbDeviceTcp(host, 5555, default_transport_timeout_s=5.)
    ## Load the public and private keys so we can connect to Android and authenticate ourself (also for future use)
    adbkey = '/home/neeo/ADB_Shell_key'
    with open(adbkey) as f:
        priv = f.read()

    with open(adbkey + '.pub') as f:
        pub = f.read()
    signer = PythonRSASigner(pub, priv)

    ADBDevice.connect(rsa_keys=[signer], auth_timeout_s=5)

    ADBHostList.setdefault(host, {})["ADBSocket"] = ADBDevice
    logger.info("Hostlist is now ")
    logger.info(ADBHostList)
    return
Beispiel #4
0
    def _read_shell(self, cmd: str):
        """"""
        max_attempt = 10
        attempt_count = 0
        stdout = ""

        while attempt_count < max_attempt:
            try:
                stdout = self._sx5_device.shell(cmd)
            except:
                # Try to establish a new connection if no response...
                try:
                    self._sx5_device = AdbDeviceTcp(
                        host=self._sx5_config_dict['SX5']['ip'],
                        port=int(self._sx5_config_dict['SX5']['port']),
                        default_transport_timeout_s=9.)
                except:
                    pass
                try:
                    self._sx5_device.connect(auth_timeout_s=0.2)
                except:
                    pass

                attempt_count += 1
            else:
                break

        if attempt_count >= max_attempt:
            raise exceptions.TcpTimeoutException
        pass

        return stdout
Beispiel #5
0
def init_device(name):
    lines = os.popen("{} devices -l".format(ADB_PATH)).read()
    mds = re.findall(r"(?m)^([\d\.]+):(\d+).+?model:(\w+) ", lines)
    mds = {name: (ip, int(port)) for ip, port, name in mds}
    ip, port = mds[name]
    device = AdbDeviceTcp(ip, port)
    device.connect()
    return device
Beispiel #6
0
    def __init__(self, address: Text):
        hostname, port = address.split(":", 2)
        assert hostname, "invalid address: missing hostname: %s" % address
        assert port, "invalid port: missing port: %s" % address

        self.hostname = hostname
        self.port = int(port)
        self.device = AdbDeviceTcp(self.hostname, self.port)
        self._height, self._width = 0, 0
Beispiel #7
0
def _connect(target_ip, target_port, target_adbkey):
    # Open private key generated on first connect
    with open(target_adbkey) as f:
        priv = f.read()
    signer = PythonRSASigner('', priv)

    device = AdbDeviceTcp(target_ip, int(target_port), default_timeout_s=9.)
    device.connect(rsa_keys=[signer], auth_timeout_s=1.)

    return device
def connect():
    with open(privkey) as f:
        priv = f.read()
    with open(pubkey) as f:
        pub = f.read()

    signer = PythonRSASigner(pub, priv)
    device = AdbDeviceTcp(address, port, default_transport_timeout_s=9.)
    device.connect(rsa_keys=[signer], auth_timeout_s=0.1)
    return device
Beispiel #9
0
 def connect(self):
     with open(os.path.join(os.path.expanduser('~'),
                            '.android/adbkey')) as f:
         p = f.read()
     signer = PythonRSASigner('', p)
     self.device = AdbDeviceTcp(self.ip, 5555, default_timeout_s=9.)
     self.device.connect(rsa_keys=[signer], auth_timeout_s=0.1)
     # ls -l
     self.ls()
     print('connect')
Beispiel #10
0
    def test_init_tcp(self):
        with patchers.PATCH_TCP_HANDLE:
            tcp_device = AdbDeviceTcp('host')
            tcp_device._handle._bulk_read = self.device._handle._bulk_read

        # Make sure that the `connect()` method works
        self.assertTrue(tcp_device.connect())
        self.assertTrue(tcp_device.available)

        # Clear the `_bulk_read` buffer so that `self.tearDown()` passes
        self.device._handle._bulk_read = b''
Beispiel #11
0
 def __init__(self, adbkey='~/.android/adbkey', ip='localhost', port=5555, timeout=9, **kwargs):
     with open(adbkey) as f:
         priv = f.read()
     with open(adbkey + '.pub') as f:
         pub = f.read()
     signer = PythonRSASigner(pub, priv)
     self.device = AdbDeviceTcp(ip, port, default_transport_timeout_s=float(timeout))
     self.device.connect(rsa_keys=[signer], auth_timeout_s=0.1)
     self.x, self.y = [int(i) for i in self.device.shell('wm size').split(' ')[-1].split('x')]
     if not os.path.exists(os.path.dirname(os.path.realpath(__file__)) + '/.cache'):
         os.makedirs(os.path.dirname(os.path.realpath(__file__)) + '/.cache')
Beispiel #12
0
    def __init__(self, host, port, adbkey=''):
        self.host = host
        self.port = int(port)
        self.adbkey = adbkey
        self._adb = AdbDeviceTcp(host=self.host,
                                 port=self.port,
                                 default_timeout_s=9.)

        # keep track of whether the ADB connection is intact
        self._available = False

        # use a lock to make sure that ADB commands don't overlap
        self._adb_lock = threading.Lock()
    def __init__(self, host, port, adbkey='', signer=None):
        self.host = host
        self.port = int(port)
        self.adbkey = adbkey
        self._adb = AdbDeviceTcp(
            host=self.host,
            port=self.port,
            default_transport_timeout_s=DEFAULT_ADB_TIMEOUT_S)
        self._signer = signer

        # keep track of whether the ADB connection is intact
        self._available = False

        # use a lock to make sure that ADB commands don't overlap
        self._adb_lock = threading.Lock()
Beispiel #14
0
    def connect(self):
        self.device = AdbDeviceTcp(self.server, self.port)

        try:
            if self.signer:
                self.device.connect(rsa_keys=[self.signer], timeout_s=10.0)
            else:
                self.device.connect(timeout_s=10.0)

        except OSError as e:
            logger.error("OSError: {}".format(e))
            raise AdbConnectionError(e)

        except (DeviceAuthError, TcpTimeoutException) as e:
            logger.error("Could not authenticate to the ADB server: {}".format(e))
            raise AdbConnectionError(e)
Beispiel #15
0
class AdbConnection:
    device = None
    TMP_PATH = '/data/local/tmp'
    server = None
    port = 0
    signer = None
    connected = False
    apks = None

    def __init__(self, server, port, signer=None):
        self.server = server
        self.port = port
        self.signer = signer

    def connect(self):
        self.device = AdbDeviceTcp(self.server, self.port)

        try:
            if self.signer:
                self.device.connect(rsa_keys=[self.signer], timeout_s=10.0)
            else:
                self.device.connect(timeout_s=10.0)

        except OSError as e:
            logger.error("OSError: {}".format(e))
            raise AdbConnectionError(e)

        except (DeviceAuthError, TcpTimeoutException) as e:
            logger.error("Could not authenticate to the ADB server: {}".format(e))
            raise AdbConnectionError(e)

    def install_apk(self, apk):
        apk.progress.set_fraction(0.0)
        apk.info('Copying...')

        # Copy the APK to the target
        dst_filename = ''.join(random.choice(string.ascii_lowercase) for i in range(16)) + '.apk'

        dst_path = os.path.join(AdbConnection.TMP_PATH, dst_filename)
        logger.debug("dst_path: {}".format(dst_path))
        self.device.push(apk.src_path, dst_path, total_timeout_s=10.0, progress_callback=apk.update_progress)
        apk.progress.set_fraction(1.0)

        apk.info('Installing...')

        # Install the APK on the target
        try:
            output = self.device.shell('pm install -r {}'.format(dst_path))
        except Exception as e:
            logger.error("Installation failed: {}".format(e))
            raise

        if output != "Success\n":
            apk.fail(output.split('\n')[0])

        else:
            apk.succeed()
Beispiel #16
0
def get_apk_file(adbkey_path, device_ip, device_port, package_name):
    with open(adbkey_path) as f:
        priv = f.read()
    signer = PythonRSASigner('', priv)
    device = AdbDeviceTcp(device_ip, device_port, default_timeout_s=9.)
    device.connect(rsa_keys=[signer], auth_timeout_s=0.1)

    # Send a shell command
    # apk file (base.apk)
    print("<*> Copying APK file to /data/local/tmp/apkSneeze/base.apk (mobile device)...")
    shell_cmd = "su - root -c '\
	mkdir -p /data/local/tmp/apkSneeze && \
	cp /data/app/{}*/base.apk /data/local/tmp/apkSneeze && \
	chmod 777 /data/local/tmp/apkSneeze/base.apk'".format(package_name)

    device.shell(shell_cmd)
    print("<*> Downloading APK file to {}...".format(DEFAULT_APP_NAME))
    device.pull("/data/local/tmp/apkSneeze/base.apk", DEFAULT_APP_NAME)
    print("<*> Download done, check {}".format(DEFAULT_APP_NAME))
    print("<*> Deleting APK file from /data/local/tmp/apkSneeze/base.apk (mobile device)...")
    device.shell("su - root -c 'rm /data/local/tmp/apkSneeze/base.apk'")
Beispiel #17
0
class AndroidTV(ImageSourceBase):
    """ Works via ADB requires USB debugging enabled and require adbkey file for authentication (generate new and copy files to device
    or use old ones usually found at [~/.android/adbkey, %HOMEDRIVE%%HOMEPATH%\.android\adbkey]
    Works with all android based TVs
    """
    def __init__(self, ip, adbkeypath='adbkey', port=5555):
        self.signer = self._get_signer(adbkeypath)
        self.ip = ip
        self.port = port
        self.conn = AdbDeviceTcp(ip, port, default_timeout_s=9.)

    ## context manager
    def __enter__(self):
        self.connect()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

    def connect(self):
        self.conn.connect(rsa_keys=[self.signer], auth_timeout_s=0.1)

    def close(self):
        self.conn.close()

    def get_ss(self):
        """ Take screenshot and create image (PIL) object"""
        raw_bytes = self.conn.shell('screencap -p', decode=False).replace(
            b'\x0D\x0A', b'\x0A')
        return Image.open(BytesIO(raw_bytes))

    def get_theme_color(self):
        return self.get_dom_color_from_image(self.get_ss())
        #return self.get_avg_color_from_image(self.get_ss())

    def _get_signer(self, adbkeypath):
        with open(adbkeypath) as f:
            return PythonRSASigner('', f.read())
Beispiel #18
0
    def __init__(self, host, port, adbkey="", signer=None):
        self.host = host
        self.port = int(port)
        self.adbkey = adbkey

        if host:
            self._adb = AdbDeviceTcp(
                host=self.host,
                port=self.port,
                default_transport_timeout_s=DEFAULT_ADB_TIMEOUT_S)
        else:
            self._adb = AdbDeviceUsb(
                default_transport_timeout_s=DEFAULT_ADB_TIMEOUT_S)

        self._signer = signer

        # use a lock to make sure that ADB commands don't overlap
        self._adb_lock = threading.Lock()
Beispiel #19
0
    def turn_off_tv(self):
        # Load the public and private keys
        with open(self.adb_key_filepath) as f:
            priv = f.read()
        with open(self.adb_key_filepath + '.pub') as f:
            pub = f.read()
        signer = PythonRSASigner(pub, priv)

        # Connect
        android_tv = AdbDeviceTcp(self.tv_ip_address,
                                  self.adb_port,
                                  default_transport_timeout_s=9.)
        android_tv.connect(rsa_keys=[signer], auth_timeout_s=0.1)

        # Send a shell command
        logger.info('Shutting off TV via shell command')
        tv_off_command_key = '26'
        android_tv.shell('input keyevent %s' % tv_off_command_key)

        android_tv.close()
Beispiel #20
0
def scan_phone_tcp(to_search_path, remote_ip, adb_key_file, max_files=None):
    """
    Search in the given directory for .jpg files and copy them to a temporarily folder.
    By default the 5555 port is used.
    After comparison, they're deleted from the original path.
    :param to_search_path: The path where the files are located.
    :param remote_ip: The IP of the device where the files are located.
    :param adb_key_file: The ADB key of the device to be connected.
    :param max_files: The number of files to be moved.
    :return: True
    """
    android_images = []
    with open(adb_key_file) as f:
        priv = f.read()
    signer = PythonRSASigner('', priv)
    device = AdbDeviceTcp(remote_ip, 5555, default_transport_timeout_s=100.)
    if device.connect(rsa_keys=[signer], auth_timeout_s=100.):
        if device.available:
            print("Connected to selected device.\n---")
        directory_scan = device.list(to_search_path, None, 9000)
        if max_files is None:
            max_files = len(directory_scan)
        for file in directory_scan:
            if os.path.splitext(file.filename.decode('utf-8'))[1] == ".jpg":
                save = AndroidPhoto()
                save.name = file.filename.decode("utf-8")
                save.size = file.size
                save.path = to_search_path
                android_images.append(save)
                if len(android_images) >= max_files:
                    break
    print(f"There're listed {len(android_images)} files.\n---")
    for image in android_images:
        device.pull(image.path + image.name, os.path.join(temp_directory, image.name),
                    progress_callback=log_pull_status,
                    transport_timeout_s=100, read_timeout_s=100)
        if image.size == os.path.getsize(os.path.join(temp_directory, image.name)):
            device.shell('rm -f ' + to_search_path + image.name)
            print("\r\r" + image.name + " is now in the temp folder.")
    print("---\nAll files are now in the temp folder.\n---")
    return True
Beispiel #21
0
def get_app_data_dir(adbkey_path, device_ip, device_port, package_name):
    with open(adbkey_path) as f:
        priv = f.read()
    signer = PythonRSASigner('', priv)
    device = AdbDeviceTcp(device_ip, device_port, default_timeout_s=9.)
    device.connect(rsa_keys=[signer], auth_timeout_s=0.1)
    # apk file (base.apk)
    print("<*> Copying app data dir to /data/local/tmp/apkSneeze/{} (mobile device)...".format(DEFAULT_DATA_DIR))
    shell_cmd = "su - root -c '\
	mkdir -p /data/local/tmp/apkSneeze && \
	cp -r /data/data/{} /data/local/tmp/apkSneeze/{} && \
	chmod -R 777 /data/local/tmp/apkSneeze/'".format(package_name,DEFAULT_DATA_DIR)

    device.shell(shell_cmd)
    print("<*> Downloading app data dir file to {}...")
    ### doesnt allow pulling directories, will execute adb from terminal directly
    # device.pull("/data/local/tmp/apkSneeze/{}/")
    
    for line in run("adb -s {}:{} pull /data/local/tmp/apkSneeze/{}".format(device_ip,device_port,DEFAULT_DATA_DIR)):
    	print("    {}".format(line.decode('utf-8')))
    
    print("<*> Download done, check {} dir".format(DEFAULT_DATA_DIR))
    print("<*> Deleting app data dir from /data/local/tmp/apkSneeze/{} (mobile device)...".format(DEFAULT_DATA_DIR))
    device.shell("su - root -c 'rm -r /data/local/tmp/apkSneeze/{}'".format(DEFAULT_DATA_DIR))
Beispiel #22
0
from adb_shell.adb_device import AdbDeviceTcp, AdbDeviceUsb
from adb_shell.auth.sign_pythonrsa import PythonRSASigner

# Load the public and private keys
adbkey = r"C:\Users\patri\.android\adbkey"
with open(adbkey) as f:
    priv = f.read()
with open(adbkey + '.pub') as f:
    pub = f.read()
signer = PythonRSASigner(pub, priv)

# Connect
device1 = AdbDeviceTcp('localhost', 5555, default_transport_timeout_s=9.)
device1.connect(rsa_keys=[signer], auth_timeout_s=0.1)

# Send a shell command
ak = 'com.YoStarEN.Arknights'
response1 = device1.shell('am start -n com.YoStarEN.Arknights')
startup = device1.shell('monkey -p com.YoStarEN.Arknights 1')
Beispiel #23
0
class ADBPython(object):
    """A manager for ADB connections that uses a Python implementation of the ADB protocol.

    Parameters
    ----------
    host : str
        The address of the device; may be an IP address or a host name
    port : int
        The device port to which we are connecting (default is 5555)
    adbkey : str
        The path to the ``adbkey`` file for ADB authentication

    """
    def __init__(self, host, port, adbkey=''):
        self.host = host
        self.port = int(port)
        self.adbkey = adbkey
        self._adb = AdbDeviceTcp(host=self.host,
                                 port=self.port,
                                 default_timeout_s=9.)

        # keep track of whether the ADB connection is intact
        self._available = False

        # use a lock to make sure that ADB commands don't overlap
        self._adb_lock = threading.Lock()

    @property
    def available(self):
        """Check whether the ADB connection is intact.

        Returns
        -------
        bool
            Whether or not the ADB connection is intact

        """
        return self._adb.available

    def close(self):
        """Close the ADB socket connection.

        """
        self._adb.close()

    def connect(self,
                always_log_errors=True,
                auth_timeout_s=DEFAULT_AUTH_TIMEOUT_S):
        """Connect to an Android TV / Fire TV device.

        Parameters
        ----------
        always_log_errors : bool
            If True, errors will always be logged; otherwise, errors will only be logged on the first failed reconnect attempt
        auth_timeout_s : float
            Authentication timeout (in seconds)

        Returns
        -------
        bool
            Whether or not the connection was successfully established and the device is available

        """
        try:
            with _acquire(self._adb_lock):
                # Catch exceptions
                try:
                    # Connect with authentication
                    if self.adbkey:
                        # private key
                        with open(self.adbkey) as f:
                            priv = f.read()

                        # public key
                        try:
                            with open(self.adbkey + '.pub') as f:
                                pub = f.read()
                        except FileNotFoundError:
                            pub = ''

                        signer = PythonRSASigner(pub, priv)

                        self._adb.connect(rsa_keys=[signer],
                                          auth_timeout_s=auth_timeout_s)

                    # Connect without authentication
                    else:
                        self._adb.connect(auth_timeout_s=auth_timeout_s)

                    # ADB connection successfully established
                    _LOGGER.debug(
                        "ADB connection to %s:%d successfully established",
                        self.host, self.port)
                    self._available = True
                    return True

                except OSError as exc:
                    if self._available or always_log_errors:
                        if exc.strerror is None:
                            exc.strerror = "Timed out trying to connect to ADB device."
                        _LOGGER.warning("Couldn't connect to %s:%d.  %s: %s",
                                        self.host, self.port,
                                        exc.__class__.__name__, exc.strerror)

                    # ADB connection attempt failed
                    self.close()
                    self._available = False
                    return False

                except Exception as exc:  # pylint: disable=broad-except
                    if self._available or always_log_errors:
                        _LOGGER.warning("Couldn't connect to %s:%d.  %s: %s",
                                        self.host, self.port,
                                        exc.__class__.__name__, exc)

                    # ADB connection attempt failed
                    self.close()
                    self._available = False
                    return False

        except LockNotAcquiredException:
            _LOGGER.warning(
                "Couldn't connect to %s:%d because adb-shell lock not acquired.",
                self.host, self.port)
            self.close()
            self._available = False
            return False

    def pull(self, local_path, device_path):
        """Pull a file from the device using the Python ADB implementation.

        Parameters
        ----------
        local_path : str
            The path where the file will be saved
        device_path : str
            The file on the device that will be pulled

        """
        if not self.available:
            _LOGGER.debug(
                "ADB command not sent to %s:%d because adb-shell connection is not established: pull(%s, %s)",
                self.host, self.port, local_path, device_path)
            return

        with _acquire(self._adb_lock):
            _LOGGER.debug(
                "Sending command to %s:%d via adb-shell: pull(%s, %s)",
                self.host, self.port, local_path, device_path)
            self._adb.pull(device_path, local_path)
            return

    def push(self, local_path, device_path):
        """Push a file to the device using the Python ADB implementation.

        Parameters
        ----------
        local_path : str
            The file that will be pushed to the device
        device_path : str
            The path where the file will be saved on the device

        """
        if not self.available:
            _LOGGER.debug(
                "ADB command not sent to %s:%d because adb-shell connection is not established: push(%s, %s)",
                self.host, self.port, local_path, device_path)
            return

        with _acquire(self._adb_lock):
            _LOGGER.debug(
                "Sending command to %s:%d via adb-shell: push(%s, %s)",
                self.host, self.port, local_path, device_path)
            self._adb.push(local_path, device_path)
            return

    def shell(self, cmd):
        """Send an ADB command using the Python ADB implementation.

        Parameters
        ----------
        cmd : str
            The ADB command to be sent

        Returns
        -------
        str, None
            The response from the device, if there is a response

        """
        if not self.available:
            _LOGGER.debug(
                "ADB command not sent to %s:%d because adb-shell connection is not established: %s",
                self.host, self.port, cmd)
            return None

        with _acquire(self._adb_lock):
            _LOGGER.debug("Sending command to %s:%d via adb-shell: %s",
                          self.host, self.port, cmd)
            return self._adb.shell(cmd)
Beispiel #24
0
    def connect(self, always_log_errors=True):
        """Connect to an Amazon Fire TV device.

        Will attempt to establish ADB connection to the given host.
        Failure sets state to UNKNOWN and disables sending actions.

        :returns: True if successful, False otherwise
        """
        self._adb_lock.acquire(**LOCK_KWARGS)
        signer = None
        if self.adbkey:
            signer = Signer(self.adbkey)
        try:
            if USE_ADB_SHELL:
                # adb_shell
                host, _, port = self.host.partition(':')
                self._adb_device = AdbDeviceTcp(host=host, port=port)

                # Connect to the device
                connected = False
                from adb_shell.exceptions import DeviceAuthError
                try:
                    if signer:
                        connected = self._adb_device.connect(rsa_keys=[signer])
                    else:
                        connected = self._adb_device.connect()
                except DeviceAuthError as err:
                    print("DeviceAuthError:", err)

                self._available = connected

            elif not self.adb_server_ip:
                # python-adb
                from adb.usb_exceptions import DeviceAuthError
                try:
                    if self.adbkey:
                        signer = Signer(self.adbkey)

                        # Connect to the device
                        self._adb = adb_commands.AdbCommands().ConnectDevice(
                            serial=self.host,
                            rsa_keys=[signer],
                            default_timeout_ms=9000)
                    else:
                        self._adb = adb_commands.AdbCommands().ConnectDevice(
                            serial=self.host, default_timeout_ms=9000)

                    # ADB connection successfully established
                    self._available = True

                except socket_error as serr:
                    if self._available or always_log_errors:
                        if serr.strerror is None:
                            serr.strerror = "Timed out trying to connect to ADB device."
                        logging.warning(
                            "Couldn't connect to host: %s, error: %s",
                            self.host, serr.strerror)

                    # ADB connection attempt failed
                    self._adb = None
                    self._available = False

                except DeviceAuthError as err:
                    print("DeviceAuthError:", err)

                finally:
                    return self._available

            else:
                # pure-python-adb
                try:
                    self._adb_client = AdbClient(host=self.adb_server_ip,
                                                 port=self.adb_server_port)
                    self._adb_device = self._adb_client.device(self.host)
                    self._available = bool(self._adb_device)

                except:
                    self._available = False

                finally:
                    return self._available

        finally:
            self._adb_lock.release()
Beispiel #25
0
class ADBClient(Client):
    key_path: Text = "adb.local.key"

    def __init__(self, address: Text):
        hostname, port = address.split(":", 2)
        assert hostname, "invalid address: missing hostname: %s" % address
        assert port, "invalid port: missing port: %s" % address

        self.hostname = hostname
        self.port = int(port)
        self.device = AdbDeviceTcp(self.hostname, self.port)
        self._height, self._width = 0, 0

    @property
    def width(self) -> int:
        return self._width

    @property
    def height(self) -> int:
        return self._height

    def connect(self):
        if not Path(ADBClient.key_path).exists():
            keygen(self.key_path)
        signer = PythonRSASigner.FromRSAKeyPath(self.key_path)
        self.device.connect(rsa_keys=[signer])

    def tap(self, point: Tuple[int, int]) -> None:
        x, y = point
        command = f"input tap {x} {y}"
        LOGGER.debug("tap: %s", command)
        res = self.device.shell(command)
        assert not res, res
        time.sleep(0.5)

    def start_game(self):
        self.device.shell(
            "am start -n jp.co.cygames.umamusume/jp.co.cygames.umamusume_activity.UmamusumeActivity"
        )

    def load_size(self):
        res = self.device.shell("wm size")
        match = re.match(r"Physical size: (\d+)x(\d+)", res)
        assert match, "unexpected command result: %s" % res
        self._width = int(match.group(2))
        self._height = int(match.group(1))
        if self._width > self._height:
            # handle orientation
            self._height, self._width = self._width, self._height
        LOGGER.debug("screen size: width=%d height=%d", self.width, self.height)

    def setup(self) -> None:
        self.connect()
        self.load_size()
        self.start_game()

    def screenshot(self) -> PIL.Image.Image:
        # img_data = self.device.shell(
        #     f"screencap -p",
        #     decode=False,
        #     transport_timeout_s=None,
        # )
        # img = PIL.Image.open(io.BytesIO(img_data))

        # TODO: compare with png format screenshot
        # https://stackoverflow.com/a/59470924
        img_data = self.device.shell(
            f"screencap",
            decode=False,
            transport_timeout_s=None,
        )
        width = int.from_bytes(img_data[0:4], "little")
        height = int.from_bytes(img_data[4:8], "little")
        pixel_format = int.from_bytes(img_data[8:12], "little")
        # https://developer.android.com/reference/android/graphics/PixelFormat#RGBA_8888
        assert pixel_format == 1, "unsupported pixel format: %s" % pixel_format
        img = PIL.Image.frombuffer(
            "RGBA", (width, height), img_data[12:], "raw", "RGBX", 0, 1
        ).convert("RGBA")
        return img

    def swipe(
        self, point: Tuple[int, int], *, dx: int, dy: int, duration: float
    ) -> None:
        x1, y1 = point
        x2, y2 = x1 + dx, y1 + dy
        duration_ms = int(duration * 1e3)
        duration_ms = max(200, duration_ms)  # not work if too fast
        command = f"input swipe {x1} {y1} {x2} {y2} {duration_ms}"
        LOGGER.debug("swipe: %s", command)
        res = self.device.shell(
            command,
            read_timeout_s=10 + duration,
        )
        assert not res, res
        time.sleep(0.5)
Beispiel #26
0
class FireTV:
    """Represents an Amazon Fire TV device."""
    def __init__(self,
                 host,
                 adbkey='',
                 adb_server_ip='',
                 adb_server_port=5037):
        """Initialize FireTV object.

        :param host: Host in format <address>:port.
        :param adbkey: The path to the "adbkey" file
        :param adb_server_ip: the IP address for the ADB server
        :param adb_server_port: the port for the ADB server
        """
        self.host = host
        self.adbkey = adbkey
        self.adb_server_ip = adb_server_ip
        self.adb_server_port = adb_server_port

        # keep track of whether the ADB connection is intact
        self._available = False

        # use a lock to make sure that ADB commands don't overlap
        self._adb_lock = threading.Lock()

        # the attributes used for sending ADB commands; filled in in `self.connect()`
        self._adb = None  # python-adb
        self._adb_client = None  # pure-python-adb
        self._adb_device = None  # pure-python-adb && adb_shell

        # the methods used for sending ADB commands
        if USE_ADB_SHELL:
            # adb_shell
            self.adb_shell = self._adb_shell_adb_shell
            self.adb_streaming_shell = self._adb_shell_adb_shell
        elif not self.adb_server_ip:
            # python-adb
            self.adb_shell = self._adb_shell_python_adb
            self.adb_streaming_shell = self._adb_streaming_shell_python_adb
        else:
            # pure-python-adb
            self.adb_shell = self._adb_shell_pure_python_adb
            self.adb_streaming_shell = self._adb_streaming_shell_pure_python_adb

        # establish the ADB connection
        self.connect()

    # ======================================================================= #
    #                                                                         #
    #                               ADB methods                               #
    #                                                                         #
    # ======================================================================= #
    def _adb_shell_adb_shell(self, cmd):
        if not self.available:
            return None

        if self._adb_lock.acquire(**LOCK_KWARGS):
            try:
                return self._adb_device.shell(cmd)
            finally:
                self._adb_lock.release()

    def _adb_shell_python_adb(self, cmd):
        if not self.available:
            return None

        if self._adb_lock.acquire(**LOCK_KWARGS):
            try:
                return self._adb.Shell(cmd)
            finally:
                self._adb_lock.release()

    def _adb_shell_pure_python_adb(self, cmd):
        if not self._available:
            return None

        if self._adb_lock.acquire(**LOCK_KWARGS):
            try:
                return self._adb_device.shell(cmd)
            finally:
                self._adb_lock.release()

    def _adb_streaming_shell_adb_shell(self, cmd):
        if not self.available:
            return []

        if self._adb_lock.acquire(**LOCK_KWARGS):
            try:
                return self._adb_device.shell(cmd)
            finally:
                self._adb_lock.release()

    def _adb_streaming_shell_python_adb(self, cmd):
        if not self.available:
            return []

        if self._adb_lock.acquire(**LOCK_KWARGS):
            try:
                return self._adb.StreamingShell(cmd)
            finally:
                self._adb_lock.release()

    def _adb_streaming_shell_pure_python_adb(self, cmd):
        if not self._available:
            return None

        # this is not yet implemented
        if self._adb_lock.acquire(**LOCK_KWARGS):
            try:
                return []
            finally:
                self._adb_lock.release()

    def _dump(self, service, grep=None):
        """Perform a service dump.

        :param service: Service to dump.
        :param grep: Grep for this string.
        :returns: Dump, optionally grepped.
        """
        if grep:
            return self.adb_shell('dumpsys {0} | grep "{1}"'.format(
                service, grep))
        return self.adb_shell('dumpsys {0}'.format(service))

    def _dump_has(self, service, grep, search):
        """Check if a dump has particular content.

        :param service: Service to dump.
        :param grep: Grep for this string.
        :param search: Check for this substring.
        :returns: Found or not.
        """
        dump_grep = self._dump(service, grep=grep)

        if not dump_grep:
            return False

        return dump_grep.strip().find(search) > -1

    def _key(self, key):
        """Send a key event to device.

        :param key: Key constant.
        """
        self.adb_shell('input keyevent {0}'.format(key))

    def _ps(self, search=''):
        """Perform a ps command with optional filtering.

        :param search: Check for this substring.
        :returns: List of matching fields
        """
        if not self.available:
            return
        result = []
        ps = self.adb_streaming_shell('ps')
        try:
            for bad_line in ps:
                # The splitting of the StreamingShell doesn't always work
                # this is to ensure that we get only one line
                for line in bad_line.splitlines():
                    if search in line:
                        result.append(line.strip().rsplit(' ', 1)[-1])
            return result
        except InvalidChecksumError as e:
            print(e)
            self.connect()
            raise IOError

    def _send_intent(self, pkg, intent, count=1):

        cmd = 'monkey -p {} -c {} {}; echo $?'.format(pkg, intent, count)
        logging.debug("Sending an intent %s to %s (count: %s)", intent, pkg,
                      count)

        # adb shell outputs in weird format, so we cut it into lines,
        # separate the retcode and return info to the user
        res = self.adb_shell(cmd)
        if res is None:
            return {}

        res = res.strip().split("\r\n")
        retcode = res[-1]
        output = "\n".join(res[:-1])

        return {"retcode": retcode, "output": output}

    def connect(self, always_log_errors=True):
        """Connect to an Amazon Fire TV device.

        Will attempt to establish ADB connection to the given host.
        Failure sets state to UNKNOWN and disables sending actions.

        :returns: True if successful, False otherwise
        """
        self._adb_lock.acquire(**LOCK_KWARGS)
        signer = None
        if self.adbkey:
            signer = Signer(self.adbkey)
        try:
            if USE_ADB_SHELL:
                # adb_shell
                host, _, port = self.host.partition(':')
                self._adb_device = AdbDeviceTcp(host=host, port=port)

                # Connect to the device
                connected = False
                from adb_shell.exceptions import DeviceAuthError
                try:
                    if signer:
                        connected = self._adb_device.connect(rsa_keys=[signer])
                    else:
                        connected = self._adb_device.connect()
                except DeviceAuthError as err:
                    print("DeviceAuthError:", err)

                self._available = connected

            elif not self.adb_server_ip:
                # python-adb
                from adb.usb_exceptions import DeviceAuthError
                try:
                    if self.adbkey:
                        signer = Signer(self.adbkey)

                        # Connect to the device
                        self._adb = adb_commands.AdbCommands().ConnectDevice(
                            serial=self.host,
                            rsa_keys=[signer],
                            default_timeout_ms=9000)
                    else:
                        self._adb = adb_commands.AdbCommands().ConnectDevice(
                            serial=self.host, default_timeout_ms=9000)

                    # ADB connection successfully established
                    self._available = True

                except socket_error as serr:
                    if self._available or always_log_errors:
                        if serr.strerror is None:
                            serr.strerror = "Timed out trying to connect to ADB device."
                        logging.warning(
                            "Couldn't connect to host: %s, error: %s",
                            self.host, serr.strerror)

                    # ADB connection attempt failed
                    self._adb = None
                    self._available = False

                except DeviceAuthError as err:
                    print("DeviceAuthError:", err)

                finally:
                    return self._available

            else:
                # pure-python-adb
                try:
                    self._adb_client = AdbClient(host=self.adb_server_ip,
                                                 port=self.adb_server_port)
                    self._adb_device = self._adb_client.device(self.host)
                    self._available = bool(self._adb_device)

                except:
                    self._available = False

                finally:
                    return self._available

        finally:
            self._adb_lock.release()

    # ======================================================================= #
    #                                                                         #
    #                          Home Assistant Update                          #
    #                                                                         #
    # ======================================================================= #
    def update(self, get_running_apps=True):
        """Get the state of the device, the current app, and the running apps.

        :param get_running_apps: whether or not to get the ``running_apps`` property
        :return state: the state of the device
        :return current_app: the current app
        :return running_apps: the running apps
        """
        # The `screen_on`, `awake`, `wake_lock_size`, `current_app`, and `running_apps` properties.
        screen_on, awake, wake_lock_size, _current_app, running_apps = self.get_properties(
            get_running_apps=get_running_apps, lazy=True)

        # Check if device is off.
        if not screen_on:
            state = STATE_OFF
            current_app = None
            running_apps = None

        # Check if screen saver is on.
        elif not awake:
            state = STATE_IDLE
            current_app = None
            running_apps = None

        else:
            # Get the current app.
            if isinstance(_current_app, dict) and 'package' in _current_app:
                current_app = _current_app['package']
            else:
                current_app = None

            # Get the running apps.
            if running_apps is None and current_app:
                running_apps = [current_app]

            # Get the state.
            # TODO: determine the state differently based on the `current_app`.
            if current_app in [PACKAGE_LAUNCHER, PACKAGE_SETTINGS]:
                state = STATE_STANDBY

            # Amazon Video
            elif current_app == AMAZON_VIDEO:
                if wake_lock_size == 5:
                    state = STATE_PLAYING
                else:
                    # wake_lock_size == 2
                    state = STATE_PAUSED

            # Netflix
            elif current_app == NETFLIX:
                if wake_lock_size > 3:
                    state = STATE_PLAYING
                else:
                    state = STATE_PAUSED

            # Check if `wake_lock_size` is 1 (device is playing).
            elif wake_lock_size == 1:
                state = STATE_PLAYING

            # Otherwise, device is paused.
            else:
                state = STATE_PAUSED

        return state, current_app, running_apps

    # ======================================================================= #
    #                                                                         #
    #                              App methods                                #
    #                                                                         #
    # ======================================================================= #
    def app_state(self, app):
        """Informs if application is running."""
        if not self.available or not self.screen_on:
            return STATE_OFF
        if self.current_app["package"] == app:
            return STATE_ON
        return STATE_OFF

    def launch_app(self, app):
        """Launch an app."""
        return self._send_intent(app, INTENT_LAUNCH)

    def stop_app(self, app):
        """Stop an app."""
        return self.adb_shell("am force-stop {0}".format(app))

    # ======================================================================= #
    #                                                                         #
    #                               properties                                #
    #                                                                         #
    # ======================================================================= #
    @property
    def state(self):
        """Compute and return the device state.

        :returns: Device state.
        """
        # Check if device is disconnected.
        if not self.available:
            return STATE_UNKNOWN
        # Check if device is off.
        if not self.screen_on:
            return STATE_OFF
        # Check if screen saver is on.
        if not self.awake:
            return STATE_IDLE
        # Check if the launcher is active.
        if self.launcher or self.settings:
            return STATE_STANDBY
        # Check for a wake lock (device is playing).
        if self.wake_lock:
            return STATE_PLAYING
        # Otherwise, device is paused.
        return STATE_PAUSED

    @property
    def available(self):
        """Check whether the ADB connection is intact."""

        if USE_ADB_SHELL:
            # adb_shell
            if not self._adb_device:
                return False

            return self._adb_device.available

        if not self.adb_server_ip:
            # python-adb
            return bool(self._adb)

        # pure-python-adb
        try:
            # make sure the server is available
            adb_devices = self._adb_client.devices()

            # make sure the device is available
            try:
                # case 1: the device is currently available
                if any(
                    [self.host in dev.get_serial_no() for dev in adb_devices]):
                    if not self._available:
                        self._available = True
                    return True

                # case 2: the device is not currently available
                if self._available:
                    logging.error('ADB server is not connected to the device.')
                    self._available = False
                return False

            except RuntimeError:
                if self._available:
                    logging.error(
                        'ADB device is unavailable; encountered an error when searching for device.'
                    )
                    self._available = False
                return False

        except RuntimeError:
            if self._available:
                logging.error('ADB server is unavailable.')
                self._available = False
            return False

    @property
    def running_apps(self):
        """Return a list of running user applications."""
        ps = self.adb_shell(RUNNING_APPS_CMD)
        if ps:
            return [
                line.strip().rsplit(' ', 1)[-1] for line in ps.splitlines()
                if line.strip()
            ]
        return []

    @property
    def current_app(self):
        """Return the current app."""
        current_focus = self.adb_shell(CURRENT_APP_CMD)
        if current_focus is None:
            return None

        current_focus = current_focus.replace("\r", "")
        matches = WINDOW_REGEX.search(current_focus)

        # case 1: current app was successfully found
        if matches:
            (pkg, activity) = matches.group("package", "activity")
            return {"package": pkg, "activity": activity}

        # case 2: current app could not be found
        logging.warning("Couldn't get current app, reply was %s",
                        current_focus)
        return None

    @property
    def screen_on(self):
        """Check if the screen is on."""
        return self.adb_shell(SCREEN_ON_CMD + SUCCESS1_FAILURE0) == '1'

    @property
    def awake(self):
        """Check if the device is awake (screensaver is not running)."""
        return self.adb_shell(AWAKE_CMD + SUCCESS1_FAILURE0) == '1'

    @property
    def wake_lock(self):
        """Check for wake locks (device is playing)."""
        return self.adb_shell(WAKE_LOCK_CMD + SUCCESS1_FAILURE0) == '1'

    @property
    def wake_lock_size(self):
        """Get the size of the current wake lock."""
        output = self.adb_shell(WAKE_LOCK_SIZE_CMD)
        if not output:
            return None
        return int(output.split("=")[1].strip())

    @property
    def launcher(self):
        """Check if the active application is the Amazon TV launcher."""
        return self.current_app["package"] == PACKAGE_LAUNCHER

    @property
    def settings(self):
        """Check if the active application is the Amazon menu."""
        return self.current_app["package"] == PACKAGE_SETTINGS

    def get_properties(self, get_running_apps=True, lazy=False):
        """Get the ``screen_on``, ``awake``, ``wake_lock_size``, ``current_app``, and ``running_apps`` properties."""
        if get_running_apps:
            output = self.adb_shell(SCREEN_ON_CMD +
                                    (SUCCESS1 if lazy else SUCCESS1_FAILURE0) +
                                    " && " + AWAKE_CMD +
                                    (SUCCESS1 if lazy else SUCCESS1_FAILURE0) +
                                    " && " + WAKE_LOCK_SIZE_CMD + " && " +
                                    CURRENT_APP_CMD + " && " +
                                    RUNNING_APPS_CMD)
        else:
            output = self.adb_shell(SCREEN_ON_CMD +
                                    (SUCCESS1 if lazy else SUCCESS1_FAILURE0) +
                                    " && " + AWAKE_CMD +
                                    (SUCCESS1 if lazy else SUCCESS1_FAILURE0) +
                                    " && " + WAKE_LOCK_SIZE_CMD + " && " +
                                    CURRENT_APP_CMD)

        # ADB command was unsuccessful
        if output is None:
            return None, None, None, None, None

        # `screen_on` property
        if not output:
            return False, False, -1, None, None
        screen_on = output[0] == '1'

        # `awake` property
        if len(output) < 2:
            return screen_on, False, -1, None, None
        awake = output[1] == '1'

        lines = output.strip().splitlines()

        # `wake_lock_size` property
        if len(lines[0]) < 3:
            return screen_on, awake, -1, None, None
        wake_lock_size = int(lines[0].split("=")[1].strip())

        # `current_app` property
        if len(lines) < 2:
            return screen_on, awake, wake_lock_size, None, None

        matches = WINDOW_REGEX.search(lines[1])
        if matches:
            # case 1: current app was successfully found
            (pkg, activity) = matches.group("package", "activity")
            current_app = {"package": pkg, "activity": activity}
        else:
            # case 2: current app could not be found
            current_app = None

        # `running_apps` property
        if not get_running_apps or len(lines) < 3:
            return screen_on, awake, wake_lock_size, current_app, None

        running_apps = [
            line.strip().rsplit(' ', 1)[-1] for line in lines[2:]
            if line.strip()
        ]

        return screen_on, awake, wake_lock_size, current_app, running_apps

    # ======================================================================= #
    #                                                                         #
    #                           turn on/off methods                           #
    #                                                                         #
    # ======================================================================= #
    def turn_on(self):
        """Send power action if device is off."""
        self.adb_shell(SCREEN_ON_CMD +
                       " || (input keyevent {0} && input keyevent {1})".format(
                           POWER, HOME))

    def turn_off(self):
        """Send power action if device is not off."""
        self.adb_shell(SCREEN_ON_CMD + " && input keyevent {0}".format(SLEEP))

    # ======================================================================= #
    #                                                                         #
    #                      "key" methods: basic commands                      #
    #                                                                         #
    # ======================================================================= #
    def power(self):
        """Send power action."""
        self._key(POWER)

    def sleep(self):
        """Send sleep action."""
        self._key(SLEEP)

    def home(self):
        """Send home action."""
        self._key(HOME)

    def up(self):
        """Send up action."""
        self._key(UP)

    def down(self):
        """Send down action."""
        self._key(DOWN)

    def left(self):
        """Send left action."""
        self._key(LEFT)

    def right(self):
        """Send right action."""
        self._key(RIGHT)

    def enter(self):
        """Send enter action."""
        self._key(ENTER)

    def back(self):
        """Send back action."""
        self._key(BACK)

    def space(self):
        """Send space keypress."""
        self._key(SPACE)

    def menu(self):
        """Send menu action."""
        self._key(MENU)

    def volume_up(self):
        """Send volume up action."""
        self._key(VOLUME_UP)

    def volume_down(self):
        """Send volume down action."""
        self._key(VOLUME_DOWN)

    # ======================================================================= #
    #                                                                         #
    #                      "key" methods: media commands                      #
    #                                                                         #
    # ======================================================================= #
    def media_play_pause(self):
        """Send media play/pause action."""
        self._key(PLAY_PAUSE)

    def media_play(self):
        """Send media play action."""
        self._key(PLAY)

    def media_pause(self):
        """Send media pause action."""
        self._key(PAUSE)

    def media_next(self):
        """Send media next action (results in fast-forward)."""
        self._key(NEXT)

    def media_previous(self):
        """Send media previous action (results in rewind)."""
        self._key(PREVIOUS)

    # ======================================================================= #
    #                                                                         #
    #                       "key" methods: key commands                       #
    #                                                                         #
    # ======================================================================= #
    def key_0(self):
        """Send 0 keypress."""
        self._key(KEY_0)

    def key_1(self):
        """Send 1 keypress."""
        self._key(KEY_1)

    def key_2(self):
        """Send 2 keypress."""
        self._key(KEY_2)

    def key_3(self):
        """Send 3 keypress."""
        self._key(KEY_3)

    def key_4(self):
        """Send 4 keypress."""
        self._key(KEY_4)

    def key_5(self):
        """Send 5 keypress."""
        self._key(KEY_5)

    def key_6(self):
        """Send 6 keypress."""
        self._key(KEY_6)

    def key_7(self):
        """Send 7 keypress."""
        self._key(KEY_7)

    def key_8(self):
        """Send 8 keypress."""
        self._key(KEY_8)

    def key_9(self):
        """Send 9 keypress."""
        self._key(KEY_9)

    def key_a(self):
        """Send a keypress."""
        self._key(KEY_A)

    def key_b(self):
        """Send b keypress."""
        self._key(KEY_B)

    def key_c(self):
        """Send c keypress."""
        self._key(KEY_C)

    def key_d(self):
        """Send d keypress."""
        self._key(KEY_D)

    def key_e(self):
        """Send e keypress."""
        self._key(KEY_E)

    def key_f(self):
        """Send f keypress."""
        self._key(KEY_F)

    def key_g(self):
        """Send g keypress."""
        self._key(KEY_G)

    def key_h(self):
        """Send h keypress."""
        self._key(KEY_H)

    def key_i(self):
        """Send i keypress."""
        self._key(KEY_I)

    def key_j(self):
        """Send j keypress."""
        self._key(KEY_J)

    def key_k(self):
        """Send k keypress."""
        self._key(KEY_K)

    def key_l(self):
        """Send l keypress."""
        self._key(KEY_L)

    def key_m(self):
        """Send m keypress."""
        self._key(KEY_M)

    def key_n(self):
        """Send n keypress."""
        self._key(KEY_N)

    def key_o(self):
        """Send o keypress."""
        self._key(KEY_O)

    def key_p(self):
        """Send p keypress."""
        self._key(KEY_P)

    def key_q(self):
        """Send q keypress."""
        self._key(KEY_Q)

    def key_r(self):
        """Send r keypress."""
        self._key(KEY_R)

    def key_s(self):
        """Send s keypress."""
        self._key(KEY_S)

    def key_t(self):
        """Send t keypress."""
        self._key(KEY_T)

    def key_u(self):
        """Send u keypress."""
        self._key(KEY_U)

    def key_v(self):
        """Send v keypress."""
        self._key(KEY_V)

    def key_w(self):
        """Send w keypress."""
        self._key(KEY_W)

    def key_x(self):
        """Send x keypress."""
        self._key(KEY_X)

    def key_y(self):
        """Send y keypress."""
        self._key(KEY_Y)

    def key_z(self):
        """Send z keypress."""
        self._key(KEY_Z)
Beispiel #27
0
 def Connect(self,uHost:str, uPort:str ,fTimeOut:float) -> cADB_Helper:
     self.uHost   = uHost
     self.oDevice = AdbDeviceTcp(uHost, int(uPort), default_transport_timeout_s=fTimeOut)
     self.oDevice.connect(rsa_keys=self.aGlobalRSA_KEYS, auth_timeout_s=20.1)
     return self
Beispiel #28
0
 def __init__(self, grid_size, host='localhost', port=5555):
     self.dev = AdbDeviceTcp(host, port, default_transport_timeout_s=9.)
     self.dev.connect()
     self.swidth, self.sheight = self.screen_dimensions()
     self.grid_size = grid_size
Beispiel #29
0
class GridInputter:
    # fractions of the screen that the grid takes up
    START_X = 0.0
    START_Y = 0.22
    END_X = 1.0
    END_Y = 0.78

    GEV_MULTIPLIER = 17.4

    def __init__(self, grid_size, host='localhost', port=5555):
        self.dev = AdbDeviceTcp(host, port, default_transport_timeout_s=9.)
        self.dev.connect()
        self.swidth, self.sheight = self.screen_dimensions()
        self.grid_size = grid_size

    def __del__(self):
        self.dev.close()

    def screen_dimensions(self):
        line = self.dev.shell('wm size')
        result = re.match(r"Physical size: (?P<height>\d+)x(?P<width>\d+)\n",
                          line)
        return int(result.group('width')), int(result.group('height'))

    def input_swipe(self, p1, p2, time=100):
        start_pix = self.get_pixels(p1)
        end_pix = self.get_pixels(p2)

        self.dev.shell(
            f'input swipe {start_pix[0]} {start_pix[1]} {end_pix[0]} {end_pix[1]} {time}'
        )

    def simplify_path(self, path):
        path = path[:]
        new_path = []
        i = 0
        while i + 2 < len(path):
            if path[i + 0][0] == path[i + 1][0] == path[i + 2][0]:
                # we can remove the middle one
                path.remove(path[i + 1])
            elif path[i + 0][1] == path[i + 1][1] == path[i + 2][1]:
                path.remove(path[i + 1])
            else:
                new_path.append(path[i + 0])
                i += 1
        new_path += path[i:]

        # lastly, the game wants to help us complete paths so if the last two are neighbors we remove the last one
        if len(new_path) >= 3:
            if abs(new_path[-1][0] -
                   new_path[-2][0]) + abs(new_path[-1][1] -
                                          new_path[-2][1]) == 1:
                new_path = new_path[:-1]
        return new_path

    def get_pixels(self, point):
        # translate grid point to pixel offset
        x, y = point

        dx = self.swidth / self.grid_size
        dy = self.sheight * (self.END_Y - self.START_Y) / self.grid_size

        px = x * dx + dx / 2
        py = y * dy + dy / 2 + self.START_Y * self.sheight

        #print(f"{x,y} becomes {px,py}")
        return round(px), round(py)
Beispiel #30
0
class AdbConnect:
    def __init__(self, ip):
        self.ip = ip
        self.device = None
        self.user_root = '/storage/emulated/0/'
        self.current_dir = None
        self.dirs = []
        self.files = []
        if sys.platform.startswith('win'):
            import winreg
            key = winreg.OpenKey(
                winreg.HKEY_CURRENT_USER,
                r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders'
            )
            self.default_download_dir = Path(
                winreg.QueryValueEx(key, "Desktop")[0]).as_posix()
        else:
            self.default_download_dir = os.path.expanduser('~')
        self.current_down_dir = self.default_download_dir

    def set_ip(self, ip):
        self.ip = ip

    def connect(self):
        with open(os.path.join(os.path.expanduser('~'),
                               '.android/adbkey')) as f:
            p = f.read()
        signer = PythonRSASigner('', p)
        self.device = AdbDeviceTcp(self.ip, 5555, default_timeout_s=9.)
        self.device.connect(rsa_keys=[signer], auth_timeout_s=0.1)
        # ls -l
        self.ls()
        print('connect')

    def disconnect(self):
        if self.device is not None:
            self.device.close()
        print('close')

    def check_dir_or_file(self, names):
        detailed_names = re.split('\n', names)[1:-1]
        # print(detailed_names)
        # 7 -> support space in filename
        self.dirs, self.files = [], []
        for e in detailed_names:
            if e.startswith('d'):
                self.dirs.append(re.split('\s+', e, maxsplit=7)[-1])
            else:
                self.files.append(re.split('\s+', e, maxsplit=7)[-1])

    def ls(self, dir_name=None):
        if dir_name is None:
            self.current_dir = self.user_root
        else:
            self.current_dir = dir_name
        dir_file_names = self.device.shell('ls -la "' + self.current_dir + '"')
        self.check_dir_or_file(dir_file_names)
        # print('dirs', self.dirs, 'files', self.files, sep='\n')

    def change_directory(self, dir_name):
        if dir_name == '.':
            # do nothing
            pass
        elif dir_name == '..':
            self.current_dir = Path(self.current_dir).parent.as_posix()
        else:
            self.current_dir = Path(os.path.join(self.current_dir,
                                                 dir_name)).as_posix()
        self.ls(self.current_dir)
        # print(self.current_dir, 'dirs', self.dirs, 'files', self.files, sep='\n')

    def pull_file(self, filename):
        download_dir = self.current_down_dir
        d_thread = DownloadThread(f=self.device.pull,
                                  filename=Path(
                                      os.path.join(self.current_dir,
                                                   filename)).as_posix(),
                                  local_dir=download_dir)
        d_thread.start()
        # self.device.pull(
        #     Path(os.path.join(self.current_dir, filename)).as_posix(),
        #     os.path.join(download_dir, filename)
        # )

    def thread_upload(self, local_files):
        # remote_dir -> current dir
        u_thread = UploadThread(f=self.device.push,
                                filenames=local_files,
                                remote_dir=self.current_dir)
        u_thread.start()