cyandroemu 1.0.2
Very fast Android automation framework with 7 backends (uiautomator 1+2, fragment parser, window dump ...)
License: MIT
Keywords: android, bot, uiautomator, magisk, kernelsu


# 📱 **CyAndroEmu: Advanced Android Automation Library**

<!-- PROJECT LOGO -->
<br />
<div align="center">
  <a href="https://github.com/hansalemaos/cyandroemu">
    <img src="https://github.com/hansalemaos/cyandroemu/blob/main/images/logo.png?raw=true" alt="Logo" width="400" height="400">
  </a>

  <h3 align="center">Python / Cython Automation for Android Emulators</h3>

  <p align="center">
    Android automations without ADB - directly on emulators
  </p>
</div>


## About The Project

**CyAndroEmu** is a powerful [**Python**](https://www.python.org/) library designed for advanced Android automation. For performance reasons, it’s primarily written in [**C++**](https://cplusplus.com/) and [**Cython**](https://cython.readthedocs.io/) __(Line count - C++: 20229 lines /  Python: 2960 lines / Cython:  9397 lines)__, providing multiple backends for interacting with UI elements, handling input events, and efficiently extracting screen data.

Unlike any other Android automation library, **CyAndroEmu** is designed to run **directly and independently** on the emulator or rooted device **without relying on ADB**. This architecture offers significant performance and reliability advantages.

---

## 🚀 **Why Choose CyAndroEmu?**

### ✅ **Key Advantages:**

- **No Broken Connections:**
  Since it operates independently of ADB, you’ll never face issues with unstable or dropped connections.

- **Blazing Fast Automation:**
  No need for slow ADB screenshot transmissions—screen data is processed directly on the device.

- **Unlimited Device Scalability:**
  Run as many emulators as your hardware can handle without hitting ADB’s device limits.

- **Natural Mouse Movements:**
  Supports smooth, human-like mouse movements, making it perfect for bypassing CAPTCHA and anti-bot detection systems.

- **Fingerprint Avoidance:**
  Eliminate the risk of device fingerprinting. Curious about how easy it is to fingerprint your device?
  👉 [Check it here](https://amiunique.org/fingerprint)

- **Direct Botting Mode with Magisk/KernelSU:**
  With Magisk or KernelSU, you can start your device and go straight into botting mode—no manual intervention needed.

- **Easy Device-Wide Proxying:**
  Effortlessly proxy all network traffic using tools like [**Proxifier**](https://www.proxifier.com/) or [**SocksDroid**](https://github.com/bndeff/socksdroid) for enhanced privacy and IP rotation.

---

## ⚡ **Additional Highlights:**

- **Low-Level Performance:**
  Thanks to its C++ core, CyAndroEmu achieves unparalleled speed and efficiency, even in resource-intensive environments.

- **Multi-Backend Support:**
  Choose from various parsers and input methods tailored to different Android environments (real devices, emulators, custom ROMs).

- **Seamless Emulator Integration:**
  Designed to work flawlessly with popular emulators like **BlissOS**, **BlueStacks**, **VMware**, and more.

- **Root-Friendly:**
  Full support for rooted devices, enabling deep system-level automation capabilities.

- **Magisk / KernelSU Plugins:**
  Start your Python automation **automatically** when the emulator or device boots—**no human interaction needed**.

---

## Getting Started

### Installation

**1. Download and install your favorite Android emulator, and ensure it has root access. CyAndroEmu should also work on any rooted smartphone (not tested yet). A non-root version is available [here](https://github.com/hansalemaos/cyandrocel). CyAndroEmu has been tested with the following:**
  * [BlueStacks 5](https://www.bluestacks.com/)
  * [BlissOs 14, 15, 16 Go](https://blissos.org/) (on [ProxMox](https://www.proxmox.com/), [Virtual Box - Windows](https://www.virtualbox.org/) and [VMWare - Windows](https://www.vmware.com/))
  * [LDPlayer](https://ldplayer.net/)
  * [MeMuPlay](https://www.memuplay.com/)
  * [MuMuPlayer](https://www.mumuplayer.com/)
  * [GenyMotion](https://www.genymotion.com/)
  * [Nox Player](https://pt.bignox.com/)
  * [Android Studio - Magisk Patched PlayStore API 30 - Android 11](https://developer.android.com/studio)

**Although neither [Magisk](https://github.com/topjohnwu/Magisk) nor [KernelSU](https://kernelsu.org/) is required, using them can significantly simplify tasks such as [running Python scripts at Android startup](https://github.com/hansalemaos/python_autostart_debug/tree/220d88549687375e53ec6cf3e7f9641553cc4375) and automatically [adding the Termux folder to the PATH when accessing the ADB shell ](https://github.com/hansalemaos/termuxtoadb/tree/bd119fd61ed8c60e399f81de26a1e202c2a5ffa3) . They also assist in hiding root access and automating actions - [writing your own Plugins is really simple](https://topjohnwu.github.io/Magisk/guides.html). [Here are some of my tutorials in Portuguese/English](https://github.com/hansalemaos/install_python_on_android_emulators) that teach you how to install them:**

| How to install Python on an emulator |  |
|-----------|-----------|
| [![Video](https://img.youtube.com/vi/99mOZ3nhG8I/0.jpg)](https://www.youtube.com/watch?v=99mOZ3nhG8I) | [![Video](https://img.youtube.com/vi/tAFduUpmxnA/0.jpg)](https://www.youtube.com/watch?v=tAFduUpmxnA) |
| [![Video](https://img.youtube.com/vi/_mgQo6OVxYg/0.jpg)](https://www.youtube.com/watch?v=_mgQo6OVxYg) | [![Video](https://img.youtube.com/vi/OPB7qnj70e4/0.jpg)](https://www.youtube.com/watch?v=OPB7qnj70e4) |
| [![Video](https://img.youtube.com/vi/GvkM1oBJR4M/0.jpg)](https://www.youtube.com/watch?v=GvkM1oBJR4M) | [![Video](https://img.youtube.com/vi/XBH4YEZZEXI/0.jpg)](https://www.youtube.com/watch?v=XBH4YEZZEXI) |
| [![Video](https://img.youtube.com/vi/KMPGV4d0q08/0.jpg)](https://www.youtube.com/watch?v=KMPGV4d0q08) | [![Video](https://img.youtube.com/vi/_j325L8wXY0/0.jpg)](https://www.youtube.com/watch?v=_j325L8wXY0) |
| [![Video](https://img.youtube.com/vi/7LDgi3qS_lU/0.jpg)](https://www.youtube.com/watch?v=7LDgi3qS_lU) | [![Video](https://img.youtube.com/vi/edHqLJot6pk/0.jpg)](https://www.youtube.com/watch?v=edHqLJot6pk) |



***

**2. Install [Termux](https://github.com/termux/termux-app) and [TermuxBoot - optional](https://github.com/termux/termux-boot)**

***

**3. Use the following command to install the required packages ([Python](https://www.python.org/), [Pandas](https://pandas.pydata.org/), [NumPy](https://numpy.org/) and some other stuff):**
  * Open a [ADB shell](https://developer.android.com/tools/adb), and Termux on your emulator and copy and paste this command to the ADB shell to save some typing:
    * __necessary packages:__
    ```sh
    input text 'yes | pkg up;pkg install -y openssh;pkg install -y git;pkg install -y openssl;pkg install -y python;pkg install -y python-numpy;pkg install -y python-pip;pkg install -y clang;pkg install -y cmake;pkg install -y coreutils;pkg install -y termux-tools;pkg install -y root-repo;pkg install -y cpulimit;pkg install -y tur-repo;pkg install -y python-pandas;pkg install -y tesseract;pkg install -y imagemagick; pkg install -y imagemagick-static;yes | python -m pip install ptpython;yes | python -m pip install cyandroemu;yes | python -m pip install regex;yes | python -m pip install ptpython;yes | python -m pip install setuptools;yes | python -m pip install Cython;yes | python -m pip install requests';input keyevent KEYCODE_ENTER;input keyevent KEYCODE_ENTER
    ```

    * __recommended packages:__

    ```sh
    input text 'yes | pkg up;yes | pkg install -y openssh;yes | pkg install -y ripgrep;yes | pkg rei libexpat;pkg install -y git;pkg install -y openssl;pkg install -y python;pkg install -y cloneit;pkg install -y python-lxml;pkg install -y python-numpy;pkg install -y python-pillow;pkg install -y python-pip;pkg install -y python-scipy;pkg install -y vim-python;pkg install -y clang;pkg install -y cmake;pkg install -y coreutils;pkg install -y termux-exec;pkg install -y termux-tools;pkg install -y root-repo;pkg install -y matplotlib;pkg install -y cpulimit;pkg install -y tur-repo;pkg install -y python-pandas;pkg install -y tmux;pkg install -y opencv-python;pkg install -y boost;pkg install -y boost-headers;pkg install -y boost-static;pkg install -y tesseract; pkg install -y tor; pkg install -y torsocks; pkg install -y fzf; pkg install -y imagemagick; pkg install -y imagemagick-static;pkg install -y python-scikit-image; pkg install -y python-polars; pkg install -y nodejs-20; pkg install -y gcc-14; pkg install -y ffmpeg7;yes | python -m pip install ptpython;yes | python -m pip install cyandroemu;yes | python -m pip install regex;yes | python -m pip install ptpython;yes | python -m pip install setuptools;yes | python -m pip install Cython;yes | python -m pip install requests';input keyevent KEYCODE_ENTER;input keyevent KEYCODE_ENTER
    ```

***


**4. Accessing Python from the ADB shell. Choose one of the 3 solutions:**
  1. **Recommended:** Install the [Magisk/KernelSU plugin to automatically add the Termux bin folder to the PATH](https://github.com/hansalemaos/termuxtoadb/tree/bd119fd61ed8c60e399f81de26a1e202c2a5ffa3)
  2. Add `export PATH="$PATH:/data/data/com.termux/files/usr/bin"` to `/system/etc/mkshrc` (don't forget to set the correct owner/group ... afterwards)

  3. Manually type `export PATH="$PATH:/data/data/com.termux/files/usr/bin"` each time you enter the **ADB su shell**.


***
***


## Writing Python scripts

### Cyandroemu will be compiled the first time you import it! Since this process is very CPU- and memory-intensive, I recommend setting the memory to 8 GB of RAM. Later on, you can reduce it. The SO files can be copied to other instances of your chosen emulator, but be careful: the CPU must be the same, as the C++ files are compiled with the flags `-march=native` and `-mtune=native` to ensure the highest possible performance."

Cyandroemu is primarily written in [C++](https://cplusplus.com/)  (6 out of 7 parsers, modified sendevent, etc.) and [Cython](https://cython.readthedocs.io/) (1 parser and the Python interface), but all automation is handled using the Python class TermuxAutomation.

***

### The Constructor

#### May Look Intimidating, but It’s Easy to Understand

```py
TermuxAutomation:
    parsers: dict,
    parser_timeout: int = 30,
    add_input_tap: bool = True,
    add_sendevent_mouse_click: bool = True,
    add_sendevent_tap: bool = True,
    add_mouse_action: bool = True,
    mouse_device: str = "/dev/input/event4",
    touch_device: str = "/dev/input/event5",
    keyboard_device: str = "/dev/input/event1",
    touch_device_max: int = 32767,
    mouse_device_max: int = 65535,
    input_cmd_tap: str = "/system/bin/input tap",
    input_cmd_text: str = "/system/bin/input text",
    sendevent_path: str = "/system/bin/sendevent",
    screen_height: int = 768,
    screen_width: int = 1024,
    sh_exe: str = "/bin/sh",
    su_exe: str = "su",
    uiautomator_dump_path: str = "/sdcard/window_dump.xml",
    uiautomator_cpu_limit: int = 5,
    system_bin_path: str = "/system/bin/",
    path_screencap: str = "screencap",
    path_exe_tesseract: str = "/data/data/com.termux/files/usr/bin/tesseract",
    path_exe_imagemagick: str = "/data/data/com.termux/files/usr/bin/magick",
    tesseract_args: str = '"-l por+eng --oem 3"',
    imagemagick_args: object = None,
    tesseract_path_outpic: str = "/sdcard/screenshot.ppm",
    uiautomator2_download_link1: str = "https://github.com/hansalemaos/uiautomator2tocsv/raw/refs/heads/main/app-uiautomator-test.apk",
    uiautomator2_download_link2: str = "https://github.com/hansalemaos/uiautomator2tocsv/raw/refs/heads/main/app-uiautomator.apk",
    uiautomator2_save_path1: str = "/sdcard/app-uiautomator-test.apk",
    uiautomator2_save_path2: str = "/sdcard/app-uiautomator.apk",
    lcp_deque_size: int = 40960,
    lcp_print_stdout: bool = False,
    lcp_print_stderr: bool = False,
    kwargs: object = None,
    adb_keyboard_link="https://github.com/hansalemaos/ADBKeyBoard/raw/refs/heads/master/ADBKeyboard.apk",
    adb_keyboard_save_path="/sdcard/ADBKeyboard.apk",
    valid_adb_keyboards=(
        "com.android.adbkeyboard/.AdbIME",
        "com.github.uiautomator/.AdbKeyboard",
    ),
```
### Each constructor argument explained

***

#### `parsers: dict`

The heart of the library, containing all the C++ applications required to run the automation.
To obtain the dictionary, use the following command.
The first time you run it, it will take about 5 minutes as the C++ files will be downloaded and compiled using GCC.

```py
parsers = TermuxAutomation.load_parsers_or_download_and_compile("g++")
```

***

#### `parser_timeout: int = 30`

The timeout (in seconds) for `subprocess.run`.

***

#### `add_input_tap: bool = True`

Wether to add the option to `input tap` any elment.

***

#### `add_sendevent_mouse_click: bool = True`

Whether to add the option to perform mouse clicks on any element using `sendevent`.

***


#### `add_sendevent_tap: bool = True`

Whether to add the option to tap any element using `sendevent`.

***


#### `add_mouse_action: bool = True`

Whether to add the option to perform mouse actions on elements (e.g., move to, right-click, left-click, middle-click, etc.)
using [a modified version of sendevent](https://github.com/hansalemaos/mouse_sendevent_android/tree/88ce6d1a54a3fbd2389ad00c7ede20cd60197dbe).

***


#### `mouse_device: str = "/dev/input/event4"`
#### `touch_device: str = "/dev/input/event5"`
#### `keyboard_device: str = "/dev/input/event1"`
#### `touch_device_max: int = 32767`
#### `mouse_device_max: int = 65535`

The mouse/keyboard/touch devices and their corresponding device max can be identified using
```sh
getevent -lp
```
or by using the static method `find_suitable_devices_for_input_events`:

```py
df_devices = TermuxAutomation.find_suitable_devices_for_input_events() # returns a pandas DataFrame
```

***


#### `input_cmd_tap: str = "/system/bin/input tap"`
#### `input_cmd_text: str = "/system/bin/input text"`
#### `sendevent_path: str = "/system/bin/sendevent"`

These are the standard input commands. In most cases, there’s no need to modify them.

***

#### `screen_height: int = 768`
#### `screen_width: int = 1024`

Screen height and screen width,  can be identified using
```sh
wm size
```

or by using the static method `get_resolution_of_screen`
```py
screen_width, screen_height = TermuxAutomation.get_resolution_of_screen()
```
> [!CAUTION]
> **MAKE SURE TO PROVIDE THE CORRECT VALUES HERE AND DO NOT ROTATE THE SCREEN DURING AUTOMATION!
> Many parsers rely on this information to function correctly.**

***

#### `sh_exe: str = "/bin/sh"`

The path to the shell executable, in most cases, there’s no need to modify it.

***

#### `su_exe: str = "su"`

The command used to enter `su` (superuser) mode. In most cases, there’s no need to modify it.

***

#### `uiautomator_dump_path: str = "/sdcard/window_dump.xml"`

Dump path for uiautomator. In most cases, there’s no need to modify it.

***



#### `uiautomator_cpu_limit: int = 5`

The CPU usage limit for the UIAutomator + cpulimit backend.

***



#### `system_bin_path: str = "/system/bin/"`

The path where system executables are stored. In most cases, there’s no need to modify it.

***



#### `path_screencap: str = "screencap"`

The command used for taking screenshots. In most cases, there’s no need to modify it.


***


#### `path_exe_tesseract: str = "/data/data/com.termux/files/usr/bin/tesseract"`

The path to the Tesseract executable. In most cases, there’s no need to modify it.

***



#### `path_exe_imagemagick: str = "/data/data/com.termux/files/usr/bin/magick"`

The path to the ImageMagick executable. Used for tesseract preprocessing. In most cases, there’s no need to modify it.

***


#### `tesseract_args: str = '"-l por+eng --oem 3"'`

Default Tesseract arguments. The default languages are Portuguese (por) and English (eng), with fully automatic page segmentation but no OSD (default).
Use `tesseract --help-extra` to view all available options. Words are grouped using pandas

**Note:
Be aware that changing the output format may cause the parser to crash, as it requires the output to be in hOCR format.**

***


#### `imagemagick_args: object = None`

Pass None if you don’t want to preprocess the screenshot before passing it to Tesseract.
If you choose to preprocess, you can provide ImageMagick command-line arguments to adjust
the image (e.g., converting to grayscale, increasing contrast) to improve OCR accuracy.

***


#### `tesseract_path_outpic: str = "/sdcard/screenshot.ppm"`

The C++ Tesseract parser captures a screenshot using screencap, converts the image to a [PPM format](https://en.wikipedia.org/wiki/Portable_Anymap), and saves the converted output to disk before invoking Tesseract. In most cases, there’s no need to modify this path.


***


#### `uiautomator2_download_link1: str = "https://github.com/hansalemaos/uiautomator2tocsv/raw/refs/heads/main/app-uiautomator-test.apk"`
#### `uiautomator2_download_link2: str = "https://github.com/hansalemaos/uiautomator2tocsv/raw/refs/heads/main/app-uiautomator.apk"`

Backups APKs from the [Uiautomator2 project](https://github.com/openatx/uiautomator2). 

You can also use my modified version which shows all hidden elements (good for web scraping)

`https://github.com/hansalemaos/uiautomator2tocsv/raw/refs/heads/main/app-uiautomator-test_with_hidden_elements.apk`

`https://github.com/hansalemaos/uiautomator2tocsv/raw/refs/heads/main/app-uiautomator_with_hidden_elements.apk`


***


#### `uiautomator2_save_path1: str = "/sdcard/app-uiautomator-test.apk"`
#### `uiautomator2_save_path2: str = "/sdcard/app-uiautomator.apk"`

Download path for the APKs from the [Uiautomator2 project](https://github.com/openatx/uiautomator2). In most cases, there’s no need to modify them.

***


#### `lcp_deque_size: int = 40960`

The ring buffer size of the C++ vector used by the Logcat Parser backend. In most cases, there’s no need to modify it.

***


#### `lcp_print_stdout: bool = False`
#### `lcp_print_stderr: bool = False`

Debug print options for the Logcat Parser backend. These should only be enabled if you encounter issues with the Logcat Parser backend.

***


#### `kwargs: object = None`

kwargs for `subprocess.run` In most cases, there’s no need to modify it.


***


#### `adb_keyboard_link: str = "https://github.com/hansalemaos/ADBKeyBoard/raw/refs/heads/master/ADBKeyboard.apk"`

Backup APK from the [ADBKeyboard project](https://github.com/senzhk/ADBKeyBoard). It allows sending Unicode characters but may not work on all devices. In most cases, there’s no need to modify it.

***


#### `adb_keyboard_save_path: str = "/sdcard/ADBKeyboard.apk"`

The download path for the APK from the [ADBKeyboard project](https://github.com/senzhk/ADBKeyBoard) project. In most cases, there’s no need to modify it.

***


#### `valid_adb_keyboards: tuple = ("com.android.adbkeyboard/.AdbIME", "com.github.uiautomator/.AdbKeyboard",)`

Possible package names for ADBKeyboard.

* The first name is the original from the [ADBKeyboard project](https://github.com/senzhk/ADBKeyBoard) project.
* The second name is from the [Uiautomator2 project](https://github.com/openatx/uiautomator2) project.

In most cases, there’s no need to modify them.

***
***


## Creating an instance

```py
from cyandroemu import TermuxAutomation, clean_zombies

import pandas as pd
from time import sleep as timesleep
import atexit

# Ensure background parsers and shells are terminated on exit
atexit.register(clean_zombies)

# Load parsers (first time may take ~5 mins due to download and compilation)
parsers = TermuxAutomation.load_parsers_or_download_and_compile("g++")

# Detect input devices dynamically (returns a pandas DataFrame)
df_devices = TermuxAutomation.find_suitable_devices_for_input_events()
print(df_devices)
screen_width, screen_height = TermuxAutomation.get_resolution_of_screen()

# On VMware and BlissOS, device order may change after a reboot, so hardcoding is avoided.
# If device order doesn't change on your emulator, you can hardcode the path, e.g.:
# mouse_device = "/dev/input/event4"

te = TermuxAutomation(
    parsers=parsers,
    mouse_device=df_devices.loc[
        (df_devices["max"].str.len() == 2) & (df_devices["type"] == "mouse")
    ]["path"].iloc[0],
    keyboard_device=df_devices.loc[
        (df_devices["keys_found"]) & (df_devices["type"] == "keyboard")
    ]["path"].iloc[0],
    mouse_device_max=df_devices.loc[
        (df_devices["max"].str.len() == 2) & (df_devices["type"] == "mouse")
    ]["max"].iloc[0][0],
    screen_height=screen_height,
    screen_width=screen_width,
)
# Clean up any leftover background processes (e.g., uiautomator2 server) from earlier automations.
# atexit should handle this, but "Doppelt genaeht haelt besser :)" (German proverb - double-stitched holds better).

te.kill_zombies()
```
***

## Automation - it's all about pandas DataFrames

Most automation tools implement their own logic for finding elements, which often looks like this:

`self.find(text="Some text").children[0].click()`

That looks beautiful and very Pythonic, but most of the time, it’s just unreliable — mainly when the attributes and positions of objects vary, or when the objects aren’t loaded on the screen yet.

Instead of bothering you with my own "great" ideas, I decided to rely on battle-tested solutions: [pandas DataFrames](https://pandas.pydata.org/). 

**With DataFrames, you can leverage powerful features like:**

* Fast sorting algorithms
* All kinds of comparisons
* Regular expressions (regex)
* Custom filter functions

If you know how to work with pandas DataFrames, you basically already know everything you need to automate whatever you want.
If not, you can learn everything from the official documentation: https://pandas.pydata.org/docs/
That’s where I got 95% of my pandas knowledge from.

***

### Pretty Print


The default `__repr__` and `__str__` functions in pandas are not ideal for displaying DataFrames, which is why they’ve been monkey-patched to ensure the entire DataFrame is pretty-printed.

```py
df = te.get_df_uiautomator2(with_screenshot=True)
print(df)
```

Now, when you print the DataFrame, you’ll see the complete content neatly formatted, making it easier to analyze UI elements.
For a line-break-free experience, I recommend using the [VTM terminal](https://github.com/directvt/vtm)

***

#### Example of a pandas DataFrame in the VTM terminal

[![Video 1](https://img.youtube.com/vi/e-lqgiDWDNQ/0.jpg)](https://www.youtube.com/watch?v=e-lqgiDWDNQ)

***

#### Getting screenshots of each element

In the example above, the elements are very easy to locate. However, this is not always the case.
You might want to see a screenshot of each element to write your script faster. In this case, you can use the following command on the device:

```py
df.bb_save_screenshots_as_png("/sdcard/uiautomator2screenshots")
```

Then, pull the screenshots using ADB to review them on your computer:

```sh
adb -s 192.168.115.131:5555 pull /sdcard/uiautomator2screenshots
```

The screenshot filenames correspond to the location of the elements in the DataFrame.
For example, if you want to locate the third element (index 2), simply run:

```py
df.iloc[2]
```
This will extract the element’s information, allowing you to build your pandas query from there.

***

#### Example of element screenshots


[![Video 1](https://img.youtube.com/vi/ZIs4z4xKBOU/0.jpg)](https://www.youtube.com/watch?v=ZIs4z4xKBOU)

***
***

## The Backends

***

### [Uiautomator2 Backend](https://github.com/hansalemaos/uiautomator2tocsv/tree/d5022bd0bb5864ba3b36cfb9c444f6557c2381c8)

| **Advantages ✅**                               | **Disadvantages ❌**                                      |
|------------------------------------------------|----------------------------------------------------------|
| Very fast parsing                              | Blocks other parsers like the Logcat parser and traditional UIAutomator |
| Never fails due to excessive screen movement (unlike UIAutomator) | Requires APKs to be installed                              |
| Includes both element text and description     | The server needs to run in the background                 |
| Great for web scraping and interacting with web elements | Automation might be detected when used with installed apps |
| Runs on any emulator                           | Useless with specific engines like the Unreal Engine                 |

***

#### Video - in action

[![Video 1](https://img.youtube.com/vi/ZeXCKHQi-bE/0.jpg)](https://www.youtube.com/watch?v=ZeXCKHQi-bE)

***

#### Python Code


```py
from cyandroemu import TermuxAutomation, clean_zombies
import pandas as pd
from time import sleep as timesleep
import atexit

# Ensure all background processes are terminated on exit
atexit.register(clean_zombies)

# Load parsers (first time may take ~5 mins due to download/compilation)
parsers = TermuxAutomation.load_parsers_or_download_and_compile("g++")

# Detect input devices dynamically (Necessary on BlissOS 16 Go with VMWare)
df_devices = TermuxAutomation.find_suitable_devices_for_input_events()
screen_width, screen_height = TermuxAutomation.get_resolution_of_screen()



# Initialize TermuxAutomation with dynamic device paths
te = TermuxAutomation(
    parsers=parsers,
    mouse_device=df_devices.loc[
        (df_devices["max"].str.len() == 2) & (df_devices["type"] == "mouse")
    ]["path"].iloc[0],
    keyboard_device=df_devices.loc[
        (df_devices["keys_found"]) & (df_devices["type"] == "keyboard")
    ]["path"].iloc[0],
    mouse_device_max=df_devices.loc[
        (df_devices["max"].str.len() == 2) & (df_devices["type"] == "mouse")
    ]["max"].iloc[0][0],
    screen_height=screen_height,
    screen_width=screen_width,
)

# Kill any leftover background processes
te.kill_zombies()

# You can install the APK using:
# te.download_and_install_uiautomator2_apks()

# Ensure elements are loaded on the screen instead of relying solely on sleep
df = pd.DataFrame()
while df.empty:
    # First DataFrame load may take ~5 seconds (UIAutomator2 server startup)
    # For production scripts, set with_screenshot=False for better performance
    # You can also pass these kwargs to temporarily change the default paramenters passed to the class constructor (valid for all backends, but not recommended)
        # If you pass anything else than None, it will override the default parameters once.
        # add_input_tap=None,
        # add_sendevent_mouse_click=None,
        # add_sendevent_tap=None,
        # add_mouse_action=None,
        # x_column=None,
        # y_column=None,
        # mouse_device=None,
        # touch_device=None,
        # touch_device_max=None,
        # mouse_device_max=None,
        # input_cmd=None,
        # sendevent_path=None,
        # screen_height=None,
        # screen_width=None,
        # mouse_action_exe=None,
        # sh_exe=None,
        # su_exe=None,
        # kwargs=None,
        # timeout=None,
    df = te.get_df_uiautomator2(with_screenshot=True)
    # Filter elements to target the TikTok app
    df = df.loc[
        (df.aa_text == "TikTok")
        & (df.aa_content_desc == "TikTok")
        & (df.aa_clickable == 1)
    ]

# Click the first matching element using input tap
# Optional: Add offset like df.aa_input_tap.iloc[0](20, 40)

df.aa_input_tap.iloc[0]()

# Clear DataFrame for the next loop

df = pd.DataFrame()

# optional sleep
timesleep(2)

# Repeating the same process for other UI elements
while df.empty:
    df = te.get_df_uiautomator2(with_screenshot=True)
    df = df.loc[
        (df.aa_text == "Already have an account? Log in")
        & (df.aa_clazz == "android.widget.Button")
        & (df.aa_content_desc == "")
    ]
df.aa_input_tap.iloc[0]()
df = pd.DataFrame()
timesleep(2)
while df.empty:
    df = te.get_df_uiautomator2(with_screenshot=True)
    df = df.loc[
        (df.aa_text == "Use phone / email / username")
        & (df.aa_clazz == "android.widget.TextView")
        & (df.aa_content_desc == "")
    ]
df.aa_input_tap.iloc[0]()
df = pd.DataFrame()
timesleep(2)
while df.empty:
    df = te.get_df_uiautomator2(with_screenshot=True)
    df = df.loc[
        (df.aa_text == "Email / Username")
        & (df.aa_clazz == "android.widget.TextView")
        & (df.aa_content_desc == "")
    ]
df.aa_input_tap.iloc[0]()
df = pd.DataFrame()
timesleep(2)

# Send text input naturally using a lightweight Cython class
# In this example, __call__ is used directly to enter the email once

te.get_cmd_send_text_natural("myemailtest@gmail.com")()
```

***

#### Example of a Pandas DataFrame (column width cropped to 30 chars)

|**index**                     |**aa_index**                  |**aa_indent**                 |**aa_text**                   |**aa_resource_id**            |**aa_clazz**                  |**aa_package**                |**aa_content_desc**           |**aa_checkable**              |**aa_checked**                |**aa_clickable**              |**aa_enabled**                |**aa_focusable**              |**aa_focused**                |**aa_scrollable**             |**aa_long_clickable**         |**aa_password**               |**aa_selected**               |**aa_visible_to_user**        |**aa_bounds**                 |**aa_drawing_order**          |**aa_hint**                   |**aa_display_id**             |**aa_line_index**             |**aa_children**               |**aa_parents**                |**aa_start_x**                |**aa_start_y**                |**aa_end_x**                  |**aa_end_y**                  |**aa_center_x**               |**aa_center_y**               |**aa_width**                  |**aa_height**                 |**aa_area**                   |**aa_w_h_relation**           |**aa_input_tap**              |**aa_sendevent_mouse_click**  |**aa_sendevent_tap**          |**aa_mouse_action**           |**aa_screenshot**             |
|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|------------------------------|
|**0**                           |0                             |4                             |                              |com.android.systemui:id/status|android.widget.FrameLayout    |com.android.systemui          |                              |0                             |0                             |0                             |1                             |0                             |0                             |0                             |0                             |0                             |0                             |1                             |[0,0][1024,24]                |1                             |                              |0                             |1                             |()                            |()                            |0                             |0                             |1024                          |24                            |512                           |12                            |1024                          |24                            |24576                         |42.666668                     |(offset_x=0, offset_y=0)      |(offset_x=0, offset_y=0, durat|(offset_x=0, offset_y=0, durat|(offset_x=0, offset_y=0, actio|[[[255 255 255]   [255 255 255|
|**1**                           |0                             |6                             |8:18                          |com.android.systemui:id/clock |android.widget.TextView       |com.android.systemui          |8:18 PM                       |0                             |0                             |0                             |1                             |0                             |0                             |0                             |0                             |0                             |0                             |1                             |[16,0][45,24]                 |2                             |                              |0                             |2                             |()                            |()                            |16                            |0                             |45                            |24                            |30                            |12                            |29                            |24                            |696                           |1.208333                      |(offset_x=0, offset_y=0)      |(offset_x=0, offset_y=0, durat|(offset_x=0, offset_y=0, durat|(offset_x=0, offset_y=0, actio|[[[255 255 255]   [255 255 255|
|**2**                           |1                             |6                             |                              |                              |android.widget.ImageView      |com.android.systemui          |Termux notification: 1 session|0                             |0                             |0                             |1                             |0                             |0                             |0                             |0                             |0                             |0                             |1                             |[45,0][69,24]                 |4                             |                              |0                             |3                             |()                            |()                            |45                            |0                             |69                            |24                            |57                            |12                            |24                            |24                            |576                           |1.0                           |(offset_x=0, offset_y=0)      |(offset_x=0, offset_y=0, durat|(offset_x=0, offset_y=0, durat|(offset_x=0, offset_y=0, actio|[[[255 255 255]   [255 255 255|
|**3**                           |2                             |6                             |                              |                              |android.widget.ImageView      |com.android.systemui          |Settings notification: NECVMWa|0                             |0                             |0                             |1                             |0                             |0                             |0                             |0                             |0                             |0                             |1                             |[69,0][93,24]                 |5                             |                              |0                             |4                             |()                            |()                            |69                            |0                             |93                            |24                            |81                            |12                            |24                            |24                            |576                           |1.0                           |(offset_x=0, offset_y=0)      |(offset_x=0, offset_y=0, durat|(offset_x=0, offset_y=0, durat|(offset_x=0, offset_y=0, actio|[[[255 255 255]   [255 255 255|
|**4**                           |3                             |6                             |                              |                              |android.widget.ImageView      |com.android.systemui          |Ethernet.                     |0                             |0                             |0                             |1                             |0                             |0                             |0                             |0                             |0                             |0                             |1                             |[959,1][978,23]               |12                            |                              |0                             |5                             |()                            |()                            |959                           |1                             |978                           |23                            |968                           |12                            |19                            |22                            |418                           |0.863636                      |(offset_x=0, offset_y=0)      |(offset_x=0, offset_y=0, durat|(offset_x=0, offset_y=0, durat|(offset_x=0, offset_y=0, actio|[[[255 255 255]   [255 255 255|
|**5**                           |4                             |6                             |                              |com.android.systemui:id/batter|android.widget.LinearLayout   |com.android.systemui          |Battery percentage unknown.   |0                             |0                             |0                             |1                             |0                             |0                             |0                             |0                             |0                             |0                             |1                             |[984,0][996,24]               |16                            |                              |0                             |6                             |()                            |()                            |984                           |0                             |996                           |24                            |990                           |12                            |12                            |24                            |288                           |0.5                           |(offset_x=0, offset_y=0)      |(offset_x=0, offset_y=0, durat|(offset_x=0, offset_y=0, durat|(offset_x=0, offset_y=0, actio|[[[255 255 255]   [255 255 255|
|**6**                           |0                             |2                             |                              |                              |android.widget.FrameLayout    |com.zhiliaoapp.musically      |                              |0                             |0                             |0                             |1                             |0                             |0