Exemple #1
0
class adb():
    def __init__(self, path: str) -> None:
        self.path = path ##
        self.adb_exe = '{}\\platform-tools\\adb.exe'.format(self.path)
    
    def connect_to_BS(self, ip: str, port: int) -> None:
        '''
        待測試 => 重開機直接執行
        '''
        self.client = AdbClient(host="127.0.0.1", port=5037)
        try:
            self.client.remote_connect(ip, port)
        except:
            subprocess.Popen('{} start-server'.format(self.adb_exe), stdout=subprocess.PIPE).stdout.read()
        print('Connect success!')

    def list_devices(self) -> None:
        devices = self.client.devices()
        print('List of devices attached:')
        for device in devices:
            print('    {}'.format(device.serial))
    
    def tap(self, device, x: str, y: str) -> None:
        device.shell('input tap {} {}'.format(x, y))

    def get_device(self, serial: str):
        return self.client.device(serial)

    def screencap(self, device):
        image_bytes = device.screencap()
        img = cv2.imdecode(np.frombuffer(image_bytes, dtype='uint8'), cv2.IMREAD_COLOR)
        return img
Exemple #2
0
def main():
    with open('/opt/tachiyomimangaexporter/secrets.json') as json_file2:
        secrets = json.load(json_file2)
    client = AdbClient(host="127.0.0.1", port=5037)
    # print(client.version())
    ip = conectar(secrets)
    client.remote_connect(ip, 5555)
    device = client.device(ip + ":5555")
    device.pull("/storage/emulated/0/Tachiyomi",
                "/media/cristian/Datos/Comics/Tachiyomi")
Exemple #3
0
def get_device(proxy_port):
    client = AdbClient(host="localhost", port=5037)
    if client.remote_connect("backend", proxy_port):
        device = client.devices()[0]
        print("Using device : %s" % device.serial)
        waiting = True
        while waiting:
            try:
                whoami = device.shell('whoami')
                # This will always be root on an eng build
                if 'root' not in whoami:
                    print("Unlikely this will work... : %s" % whoami)
                else:
                    waiting = False
            except Exception as e:
                print("Hit exception waiting, will retry in 1 second... ", e)
                time.sleep(1)
        return device
Exemple #4
0
class FireTV:
    """Represents an Amazon Fire TV device."""
    def __init__(self,
                 host,
                 port=5555,
                 adb_server_ip="127.0.0.1",
                 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.port = port
        self.adb_server_port = adb_server_port
        self.adb_server_ip = adb_server_ip

        # 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

        # 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 _keyboard(self, literal):
        """Send text to device

        :param key: text string to send.
        """
        self.adb_shell(f'input text "{literal}"')

    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)
        try:
            # pure-python-adb
            try:
                self._adb_client = AdbClient()
                self._adb_client.remote_connect(self.host, self.port)
                print(self._adb_client.devices())
                self._adb_device = self._adb_client.device(
                    f"{self.host}:{self.port}")
                self._available = bool(self._adb_device)
            except:
                traceback.print_exc()
                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 backspace(self):
        """Send backspace action."""
        self._key(DELETE)

    def search(self):
        """Send search action."""
        self._key(SEARCH)

    def info(self):
        """Send info action."""
        self._key(INFO)

    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 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)

    def grave(self):
        """Send backtick action."""
        self._key(GRAVE)

    def settings(self):
        """Send settings action."""
        self._key(SETTINGS)

    def backslash(self):
        """Send backslash action."""
        self._key(BACKSLASH)

    # ======================================================================= #
    #                                                                         #
    #                      "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)

    def media_fast_forward(self):
        """Send media fast forward action."""
        self._key(FAST_FORWARD)

    def media_rewind(self):
        """Send media rewind action."""
        self._key(REWIND)

    def media_skip_backwards(self):
        """Send media skip backward action."""
        self._key(SKIP_BACKWARD)

    # ======================================================================= #
    #                                                                         #
    #                       "key" methods: key commands                       #
    #                                                                         #
    # ======================================================================= #
    def keyboard(self, literal):
        """Send keyboard literal keypress."""
        self._keyboard(literal)