diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 04859e3c..5f651d92 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -6,7 +6,7 @@ patreon: # Replace with a single Patreon username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username +liberapay: OpenAndroidInstaller issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5b1823ce..233deb9f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -2,7 +2,7 @@ name: Bug report about: Create a report to help us improve title: '' -labels: '' +labels: 'bug' assignees: '' --- diff --git a/.github/ISSUE_TEMPLATE/device-support-request.md b/.github/ISSUE_TEMPLATE/device-support-request.md deleted file mode 100644 index 325b5f8e..00000000 --- a/.github/ISSUE_TEMPLATE/device-support-request.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: Device support request -about: Request support for a new device -title: '' -labels: '' -assignees: '' - ---- - -**Device name** -Please enter the name of the device you would like to request support for. -If you know the device code, please also add it here. - -**Device images** -Please provide links to any available images of the device, such as official stock firmware or custom ROMs you would like to install. - -**Do you own the device and would be willing to test the installer?** -- [ ] - -**Additional context** -Please provide any additional context or information that may be helpful in adding support for this device. diff --git a/.github/ISSUE_TEMPLATE/device-support-request.yaml b/.github/ISSUE_TEMPLATE/device-support-request.yaml new file mode 100644 index 00000000..9823d1f5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/device-support-request.yaml @@ -0,0 +1,89 @@ +name: Device support request +description: Request support for a new device +title: Add support for +labels: ["device"] +body: + - type: markdown + attributes: + value: "Thank you for your interest in OpenAndroidInstaller!" + - type: markdown + attributes: + value: "To get your device supported, please take the time to fill out this form." + - type: markdown + attributes: + value: "---" + - type: checkboxes + attributes: + label: Is your device already requested? + description: Please search to see if an issue for your device already exists. + options: + - label: I have searched the existing issues + required: true + - type: markdown + attributes: + value: "---" + - type: markdown + attributes: + value: "**Please input your device's details below:**" + - type: input + attributes: + label: Brand + description: The brand / manufacturer of your device + placeholder: Google + validations: + required: true + - type: input + attributes: + label: Name + description: The name of your device + placeholder: Pixel 3a + validations: + required: true + - type: input + attributes: + label: Device code + description: The device code OAI gave you in the error message + placeholder: sargo + validations: + required: true + - type: input + attributes: + label: Model + description: The model name of your device (only required, if there are several models) + placeholder: G020F + validations: + required: false + - type: markdown + attributes: + value: "---" + - type: textarea + attributes: + label: Device images + description: "Please provide links to any available images for the device, such as official stock firmware, Custom ROMs and Recoveries you would like to install." + placeholder: | + - Custom ROM: https://wiki.lineageos.org/devices/sargo + - Recovery: https://twrp.me/google/googlepixel3a.html + #value: | + # - Custom ROM: + # - Recovery: + # - Stock firmware (if needed & existing): + render: Markdown + validations: + required: false + - type: markdown + attributes: + value: "---" + - type: checkboxes + attributes: + label: Do you own the device and would be willing to test the installer? + options: + - label: I own the device and am willing to test the installer on it. + required: true + - type: markdown + attributes: + value: "---" + - type: textarea + attributes: + label: Additional context + description: Please provide any additional context or information that might be helpful in adding support for this device. + render: Markdown diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index bbcbbe7d..36014cde 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -2,7 +2,7 @@ name: Feature request about: Suggest an idea for this project title: '' -labels: '' +labels: 'enhancement' assignees: '' --- diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index e00a8c1f..26dd3907 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -14,8 +14,8 @@ jobs: matrix: os: ['ubuntu-20.04', 'ubuntu-latest'] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 with: python-version: 3.9 - run: pip install -r requirements.txt @@ -32,8 +32,8 @@ jobs: matrix: os: ['ubuntu-20.04', 'ubuntu-latest', 'macos-latest'] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 with: python-version: 3.9 - run: pip install -r requirements.txt @@ -48,8 +48,8 @@ jobs: needs: ci runs-on: 'windows-latest' steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 with: python-version: 3.9 - run: pip install -r requirements.txt @@ -66,7 +66,7 @@ jobs: - build-windows runs-on: 'ubuntu-latest' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Download artifact uses: actions/download-artifact@v3 - name: Display structure of downloaded files @@ -86,7 +86,7 @@ jobs: - name: Display structure of downloaded files run: ls -R - name: Create release - uses: marvinpinto/action-automatic-releases@latest + uses: dciborow/action-github-releases@v1.0.1 if: startsWith(github.ref, 'refs/tags/') with: repo_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/manual-build.yml b/.github/workflows/manual-build.yml index 91a8cb3c..1b55c315 100644 --- a/.github/workflows/manual-build.yml +++ b/.github/workflows/manual-build.yml @@ -13,8 +13,8 @@ jobs: os: ['ubuntu-20.04', 'ubuntu-latest', 'macos-latest', 'windows-latest'] steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 with: python-version: 3.9 - run: pip install -r requirements.txt diff --git a/README.md b/README.md index 8c865894..5e4846ef 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,46 @@ -
+ + OpenAndroidInstaller + +

OpenAndroidInstaller

+

Makes installing alternative Android distributions nice and easy!

- [![License](https://img.shields.io/github/license/openandroidinstaller-dev/openandroidinstaller?color=green&style=flat-square)](https://github.com/openandroidinstaller-dev/openandroidinstaller/blob/main/LICENSE) - [![Release](https://img.shields.io/github/v/release/openandroidinstaller-dev/openandroidinstaller?include_prereleases&style=flat-square)](https://github.com/openandroidinstaller-dev/openandroidinstaller/releases) - [![Downloads](https://img.shields.io/github/downloads/openandroidinstaller-dev/openandroidinstaller/total?style=flat-square)](https://github.com/openandroidinstaller-dev/openandroidinstaller/releases) - [![Flathub](https://img.shields.io/flathub/downloads/org.openandroidinstaller.OpenAndroidInstaller?label=flathub%20installs&style=flat-square)](https://flathub.org/apps/org.openandroidinstaller.OpenAndroidInstaller) + [![License](https://img.shields.io/github/license/openandroidinstaller-dev/openandroidinstaller?color=green)](https://github.com/openandroidinstaller-dev/openandroidinstaller/blob/main/LICENSE) + [![Release](https://img.shields.io/github/v/release/openandroidinstaller-dev/openandroidinstaller?include_prereleases)](https://github.com/openandroidinstaller-dev/openandroidinstaller/releases) + [![Downloads](https://img.shields.io/github/downloads/openandroidinstaller-dev/openandroidinstaller/total)](https://github.com/openandroidinstaller-dev/openandroidinstaller/releases) + [![Flathub](https://img.shields.io/flathub/downloads/org.openandroidinstaller.OpenAndroidInstaller?label=flathub%20installs)](https://flathub.org/apps/org.openandroidinstaller.OpenAndroidInstaller) [![Twitter](https://img.shields.io/twitter/follow/oainstaller?style=social)](https://twitter.com/OAInstaller) [![Mastodon](https://img.shields.io/mastodon/follow/109341220262803943?domain=https%3A%2F%2Ffosstodon.org&style=social)](https://fosstodon.org/@openandroidinstaller) -

Makes installing alternative Android distributions nice and easy.

- - OpenAndroidInstaller - -

-
+

The OpenAndroidInstaller project helps Android users to keep their smartphone's operating system up to date with free software and to continue using the device even though the manufacturer no longer offers updates. With a graphical installation software, users are easily guided through the installation process of free Android operating systems like LineageOS. -
-
- Report Bug - · - Website - · - Request Feature -
+

+ + Website + · + Report Bugs + · + Request Feature +

-> **Warning**: This application is currently in beta state, so use at your own risk! While many people tested the application so far and we heard of no bricked devices, things might still go wrong. - -> **Note**: Unlocking the bootloader will erase all data on your device! -This also includes your DRM keys, which are stored in the Trim Area partition (also called TA) in case your device is fairly recent and supports DRM L1. Those devices will be downgraded to DRM L3. Devices on DRM L3 by default will not be affected. -Before proceeding, ensure the data you would like to retain is backed up to your PC and/or your Google account, or equivalent. Please note that OEM backup solutions like Samsung and Motorola backup may not be accessible from LineageOS once installed. -If you wish to backup the TA partition first, you can find tutorials related to your device on the internet. +> [!WARNING] +> This application is currently in beta state, so use at your own risk! While many people tested the application so far and we heard of no bricked devices, things might still go wrong. +> [!IMPORTANT] +> Unlocking the bootloader will erase all data on your device! +> This also includes your DRM keys, which are stored in the Trim Area partition (also called TA) in case your device is fairly recent and supports DRM L1. Those devices will be downgraded to DRM L3. Devices on DRM L3 by default will not be affected. +> Before proceeding, ensure the data you would like to retain is backed up to your PC and/or your Google account, or equivalent. Please note that OEM backup solutions like Samsung and Motorola backup may not be accessible from LineageOS once installed. +> If you wish to backup the TA partition first, you can find tutorials related to your device on the internet. ## Usage -Linux is currently the best supported platform (tested with Ubuntu 20.04/22.04 LTS). Windows and MacOS are also supported but you might experience more issues. So far there is no support for ARM-based systems. +Linux is currently the best supported platform (tested with Ubuntu 20.04/22.04 LTS). Windows and macOS are also supported but you might experience more issues. So far there is no support for ARM-based systems. 1. Download the [.exe or appropriate executable file for your OS](https://github.com/openandroidinstaller-dev/openandroidinstaller/releases) from the releases or get the [official flatpak from flathub](https://flathub.org/apps/org.openandroidinstaller.OpenAndroidInstaller). You might need to change permissions to run the executable. - - On Windows also [install the Universal USB Drivers](https://adb.clockworkmod.com/) and other potentially drivers needed for your device. + - On Windows also [install the Universal USB Drivers](https://adb.clockworkmod.com) and other potentially drivers needed for your device. 2. Download the custom ROM image and the TWRP recovery image for your device and optionally some addons. A source for files can be found on the following websites: - some custom ROMs: - [LineageOS](https://wiki.lineageos.org/devices) @@ -60,11 +60,9 @@ Linux is currently the best supported platform (tested with Ubuntu 20.04/22.04 L - or you can just search the web or the [xda-developers forum](https://forum.xda-developers.com) for an appropriate version for your device. 3. Start the desktop app and follow the instructions. - ## Officially supported devices -Currently, the **we support 62 devices** by various vendors and working on adding more soon! - +Currently, the **we support 73 devices** by various vendors and working on adding more soon! Support for these devices is provided as best effort, but things might still go wrong. Help to improve the tool by reporting any issues you might face. @@ -83,11 +81,12 @@ Samsung | Galaxy Grand Prime VE | grandprimevelte | SM-G531F | tested Samsung | Galaxy S III Neo | s3ve3g | GT-I9301I | tested Samsung | Galaxy Tab S2 | [gts210vewifi](https://wiki.lineageos.org/devices/gts210vewifi/) | T813 | tested Samsung | Galaxy S4 Mini LTE| [serranoltexx](https://wiki.lineageos.org/devices/serranoltexx) | | tested +Samsung | Galaxy S5 | [klte](https://wiki.lineageos.org/devices/klte) | G900F/M/R4/R7/T/V/W8 | tested Samsung | Galaxy S6 | [zerofltexx](https://wiki.lineageos.org/devices/zerofltexx) | | tested Samsung | Galaxy S6 Edge | [zeroltexx](https://wiki.lineageos.org/devices/zeroltexx) | | tested Samsung | Galaxy S7 | [herolte](https://wiki.lineageos.org/devices/herolte) | SM-G930F | tested Samsung | Galaxy S7 Edge | [hero2lte](https://wiki.lineageos.org/devices/hero2lte) | | tested -Samsung | Galaxy S8 | [dreamlte](https://wiki.lineageos.org/devices/dreamlte) | | tested +Samsung | Galaxy S8 | dreamlte | | tested Samsung | Galaxy S9 | [starlte](https://wiki.lineageos.org/devices/starlte) | | tested Samsung | Galaxy S10 | [beyond1lte](https://wiki.lineageos.org/devices/beyond1lte) | | tested Samsung | Galaxy S10e | [beyond0lte](https://wiki.lineageos.org/devices/beyond0lte) | | tested @@ -97,6 +96,7 @@ Samsung | Galaxy Note 8 | greatlte | SM-N950F | tested Samsung | Galaxy Note 9 | [crownlte](https://wiki.lineageos.org/devices/crownlte) | | tested Samsung | Galaxy Note 10 | [d1](https://wiki.lineageos.org/devices/d1) | | tested Samsung | Galaxy Note 10+ | [d2s](https://wiki.lineageos.org/devices/d2s) | | tested +
Google @@ -114,6 +114,7 @@ Google | Pixel 4 XL | [coral](https://wiki.lineageos.org/devices/coral) | coral Google | Pixel 4a | [sunfish](https://wiki.lineageos.org/devices/sunfish) | sunfish | tested Google | Pixel 5 | [redfin](https://wiki.lineageos.org/devices/redfin) | redfin | tested Google | Pixel 5a | [barbet](https://wiki.lineageos.org/devices/barbet) | barbet | tested +
Sony @@ -128,6 +129,7 @@ Sony | Xperia XA2 | [pioneer](https://wiki.lineageos.org/devices/pioneer) | | te Sony | Xperia XZ2 | [akari](https://wiki.lineageos.org/devices/akari) | | tested Sony | Xperia XZ3 | [akatsuki](https://wiki.lineageos.org/devices/akatsuki) | | tested Sony | Xperia ZX | kagura | | planned +
Fairphone @@ -137,6 +139,7 @@ Vendor | Device Name | CodeName | Models | Status Fairphone | Fairphone 2 | [FP2](https://wiki.lineageos.org/devices/FP2) | | tested Fairphone | Fairphone 3 | [FP3](https://wiki.lineageos.org/devices/FP3) | | tested Fairphone | Fairphone 4 | [FP4](https://wiki.lineageos.org/devices/FP4) | | tested +
Motorola @@ -150,6 +153,7 @@ Motorola | moto g 5G plus / one 5G | [nairo](https://wiki.lineageos.org/devices/ Motorola | moto g 5G / one 5G ace | [kiev](https://wiki.lineageos.org/devices/kiev) | | tested Motorola | edge | [racer](https://wiki.lineageos.org/devices/racer) | | tested Motorola | moto z | [griffin](https://wiki.lineageos.org/devices/griffin) | | tested +
OnePlus @@ -168,19 +172,28 @@ OnePlus | 7T Pro | [hotdog](https://wiki.lineageos.org/devices/hotdog) | | teste OnePlus | Nord | [avicii](https://wiki.lineageos.org/devices/avicii) | | tested OnePlus | Nord N200 | [dre](https://wiki.lineageos.org/devices/dre) | | tested OnePlus | 9 | lemonade | | under development -
- -And more to come! + -## Run OpenAndroidInstaller for development +
Xiaomi -Currently development is only supported on Ubuntu Linux. MacOS and Windows should also work fine. You might need to install additional USB-drivers on Windows. +Vendor | Device Name | CodeName | Models | Status +---|---|---|---|--- +Xiaomi | Redmi Note 7 | [lavender](https://wiki.lineageos.org/devices/lavender) | | tested +Xiaomi | Redmi 7A / 8 / 8A / 8A Dual | [Mi439](https://wiki.lineageos.org/devices/Mi439) : pine / olive / olivelite / olivewood | | tested +Xiaomi | Redmi Note 8 / 8T | [ginkgo](https://wiki.lineageos.org/devices/ginkgo) / willow | | untested +Xiaomi | Redmi Note 8 Pro | begonia | | untested +Xiaomi | Redmi 9A / 9C / 9AT / 9i / 9A Sport / 10A / 10A Sport | garden / dandelion / blossom / angelican | | tested +Xiaomi | Mi 9T / Redmi K20 | [davinci](https://wiki.lineageos.org/devices/davinci) / davinciin | | untested +Xiaomi | Redmi K20 Pro / Mi 9T Pro | raphael / raphaelin | | untested +Xiaomi | Redmi Note 9S / 9 Pro / 9 Pro Max / 10 Lite / Poco M2 pro | [miatoll](https://wiki.lineageos.org/devices/lavender) : gram / curtana / excalibur / joyeuse | | untested +Xiaomi | Redmi Note 10S / 11SE / Poco M5S | [rosemary](https://wiki.lineageos.org/devices/rosemary) / maltose / secret /rosemary_p | | untested +Xiaomi | Poco X3 Pro | [vayu](https://wiki.lineageos.org/devices/vayu) | | untested +Xiaomi | 12 | cupid | | untested +
-1. Clone the main branch of this repository -2. Run `make poetry` and `make install` to install poetry to manage python and install the required dependencies like adb, fastboot and heimdall. -3. Run `make app` to start the desktop app from the source. +And more to come! ## Contributing @@ -193,62 +206,16 @@ All kinds of contributions are welcome. These include: - Add features and/or improve the code base. - Report bugs. -More details on how to contribute can be found [here](https://github.com/openandroidinstaller-dev/openandroidinstaller/blob/main/CONTRIBUTING.md). -Please have a look before opening an issue or starting to contribute. - -A detailed list can be found [here](https://openandroidinstaller.org/#contribute). - -### How to contribute your own installation configurations - -If you want to use the tool for a non-supported smartphone, the fastest way is to adapt an [existing config file](https://github.com/openandroidinstaller-dev/openandroidinstaller/tree/main/openandroidinstaller/assets/configs). The file should be named after the official `device code` of the device. Add the code output by `adb shell getprop | grep ro.product.device` (when the devices is connected to the computer) as well as the official device code to the `supported_device_codes` list in the config. You can also get the device code by connecting the device to the computer and run OpenAndroidInstaller to detect the device. - -**To test your config file with the executable** without using the developer setup, place it in the same directory as the executable. There it will be detected by name. After you created a config file and it works fine, you can open a pull request to make the file available to other users. Please also add the device to the supported devices table above. - -#### Content of a config file - -A config file consists of two parts. The first part are some metadata about the device and the second parts are the steps to unlock the bootloader, boot a recovery and install the ROMs. - -##### How to write Metadata -Every config file should have `metadata` with the following fields: -- `maintainer`: str; Maintainer and author of the config file. -- `device_name`: str; Name of the device. -- `is_ab_device`: bool; A boolean to determine if the device is a/b-partitioned or not. -- `device_code`: str; The official device code. -- `supported_device_codes`: List[str]; A list of supported device codes for the config. The config will be loaded based on this field. -- `twrp-link`: [OPTIONAL] str; name of the corresponding twrp page. +[How to contribute your own installation configurations](https://github.com/openandroidinstaller-dev/openandroidinstaller/blob/main/docs/how_to_contribute_your_own_installation_configurations.md) -In addition to these metadata, every config can have optional `requirements`. If these are set, the user is asked to check if they are meet. -- `android`: [OPTIONAL] int|str; Android version to install prior to installing a custom ROM. -- `firmware`: [OPTIONAL] str; specific firmware version to install before installing a custom ROM. +[How to build the application for your platform](https://github.com/openandroidinstaller-dev/openandroidinstaller/blob/main/docs/building_the_application_for_your_platform.md) -##### How to write steps: -Every step in the config file corresponds to one view in the application. These steps should contain the following fields: -- `type`: str; Corresponds to the type of view to generate. There are the following options: - - `text`: Just display the text given in content. - - `confirm_button`: Display the content, as well as a button to allow the user to go to the next step. - - `call_button`: Display the content text and a button that runs a given command. After the command is run, a confirm button is displayed to allow the user to move to the next step. - - `call_button_with_input`: Display the content text, an input field and a button that runs a given command. The inputtext, can be used in the command by using the `` placeholder in the command field. After the command is run, a confirm button is displayed to allow the user to move to the next step. - - `link_button_with_confirm`: Display a button that opens a browser with a given link, confirm afterwards. Link is given in `link`. -- `img`: [OPTIONAL] Display an image on the left pane of the step view. Images are loaded from `openandroidinstaller/assets/imgs/`. -- `content`: str; The content text displayed alongside the action of the step. Used to inform the user about what's going on. For consistency and better readability the text should be moved into the next line using `>`. -- `link`: [OPTIONAL] Link to use for the link button if type is `link_button_with_confirm`. -- `command`: [ONLY for call_button* steps] str; The command to run. One of `adb_reboot`, `adb_reboot_bootloader`, `adb_reboot_download`, `adb_sideload`, `adb_twrp_wipe_and_install`, `adb_twrp_copy_partitions`, `fastboot_boot_recovery`, `fastboot_unlock_with_code`, `fastboot_unlock`, `fastboot_oem_unlock`, `fastboot_get_unlock_data`, `fastboot_reboot`, `heimdall_flash_recovery`. -- `allow_skip`: [OPTIONAL] boolean; If a skip button should be displayed to allow skipping this step. Can be useful when the bootloader is already unlocked. +[On unlocking the bootloader](https://github.com/openandroidinstaller-dev/openandroidinstaller/blob/main/docs/unlocking_the_bootloader.md) -**Please try to retain this order of these fields in your config to ensure consistency.** - -## How to build the application for your platform - -The executables for the OpenAndroidInstaller are build with [pyinstaller](https://pyinstaller.org/en/stable/index.html). You can create builds for MacOS or Linux with `make build-app`. For Windows the paths need to be modified. For now, you can have a look [here](https://github.com/openandroidinstaller-dev/openandroidinstaller/blob/v0.1.2-alpha/.github/workflows/manual-build-windows.yml#L22) on how it's done. - -If you build the application for your platform and want to contribute the build, please reach out to me. - -#### On unlocking the bootloader -Devices by *Samsung*, *Google* and *Fairphone* make it fairly easy to unlock the bootloader and receive good support in the installer. - -Some devices with require manual steps to unlock the bootloader. In general you will need to create an account at a vendor website and receive some code from there. OpenAndroidInstaller will try to guide you as far as possible. These vendors include *Sony, Motorola, Xiaomi* and *OnePlus* among others. +More details on how to contribute can be found [here](https://github.com/openandroidinstaller-dev/openandroidinstaller/blob/main/CONTRIBUTING.md). +Please have a look before opening an issue or starting to contribute. -Other phone vendors stops allowing to unlock the bootloader all together. There is nothing to be done if you didn't unlock your device in time. These vendors include *Huawei and LG* among others. Support for these vendors will always be very limited. +A detailed list can be found [here](https://openandroidinstaller.org/#contribute). ## Tools @@ -257,13 +224,14 @@ Other phone vendors stops allowing to unlock the bootloader all together. There - [libusb-1.0](https://github.com/libusb/libusb) is a [LGPL-2.1](https://github.com/libusb/libusb/blob/master/COPYING)-licensed library for USB device access from Linux, macOS, Windows and others. - [copy-partitions-20220613-signed.zip](https://mirrorbits.lineageos.org/tools/copy-partitions-20220613-signed.zip) The copy-partitions script was created by LineageOS developer erfanoabdi and filipepferraz and released under LGPL. It is used when the partitions need to be copied before flashing. - ## Acknowledgements -* Funded from September 2022 until February 2023 by ![logos of the "Bundesministerium für Bildung und Forschung", Prodotype Fund and OKFN-Deutschland](resources/pf_funding_logos.svg) +* Funded from September 2022 until February 2023 by: +![logos of the "Bundesministerium für Bildung und Forschung", Prodotype Fund and OKFN-Deutschland](resources/pf_funding_logos.svg) ## License + Original development by [Tobias Sterbak](https://tobiassterbak.com). Copyright (C) 2022-2023. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. diff --git a/docs/building_the_application_for_your_platform.md b/docs/building_the_application_for_your_platform.md new file mode 100644 index 00000000..a905e84b --- /dev/null +++ b/docs/building_the_application_for_your_platform.md @@ -0,0 +1,14 @@ +## How to build the application for your platform + +The executables for the OpenAndroidInstaller are build with [pyinstaller](https://pyinstaller.org/en/stable/index.html). You can create builds for MacOS or Linux with `make build-app`. For Windows the paths need to be modified. For now, you can have a look [here](https://github.com/openandroidinstaller-dev/openandroidinstaller/blob/v0.1.2-alpha/.github/workflows/manual-build-windows.yml#L22) on how it's done. + +If you build the application for your platform and want to contribute the build, please reach out to me. + +## Run OpenAndroidInstaller for development + +Currently development is only supported on Ubuntu Linux. MacOS and Windows should also work fine. You might need to install additional USB-drivers on Windows. + +1. Clone the main branch of this repository +2. Run `make poetry` and `make install` to install poetry to manage python and install the required dependencies like adb, fastboot and heimdall. +3. Run `make app` to start the desktop app from the source. + diff --git a/docs/how_to_contribute_your_own_installation_configurations.md b/docs/how_to_contribute_your_own_installation_configurations.md new file mode 100644 index 00000000..d9063776 --- /dev/null +++ b/docs/how_to_contribute_your_own_installation_configurations.md @@ -0,0 +1,43 @@ +### How to contribute your own installation configurations + +If you want to use the tool for a non-supported smartphone, the fastest way is to adapt an [existing config file](https://github.com/openandroidinstaller-dev/openandroidinstaller/tree/main/openandroidinstaller/assets/configs). The file should be named after the official `device code` of the device. Add the code output by `adb shell getprop | grep ro.product.device` (when the devices is connected to the computer) as well as the official device code to the `supported_device_codes` list in the config. You can also get the device code by connecting the device to the computer and run OpenAndroidInstaller to detect the device. + +**To test your config file with the executable** without using the developer setup, place it in the same directory as the executable. There it will be detected by name. After you created a config file and it works fine, you can open a pull request to make the file available to other users. Please also add the device to the supported devices table above. + +#### Content of a config file + +A config file consists of two parts. The first part are some metadata about the device and the second parts are the steps to unlock the bootloader, boot a recovery and install the ROMs. + +##### How to write Metadata +Every config file should have `metadata` with the following fields: +- `maintainer`: str; Maintainer and author of the config file. +- `device_name`: str; Name of the device. +- `brand`: [OPTIONAL] str; Name of the brand. Can be used to make brand specific actions. +- `is_ab_device`: bool; A boolean to determine if the device is a/b-partitioned or not. +- `device_code`: str; The official device code. +- `supported_device_codes`: List[str]; A list of supported device codes for the config. The config will be loaded based on this field. +- `twrp-link`: [OPTIONAL] str; name of the corresponding twrp page. +- `additional_steps` : [OPTIONAL] List[str]; A list of additional steps. Can be `dtbo`, `vbmeta`, `vendor_boot` or `super_empty`. +- `notes`: [OPTIONAL] List[str]; specific phone information, showed before choosing ROM / recovery +- `untested`: [OPTIONAL] bool; If `true`, a warning message is showed during installation process. + +In addition to these metadata, every config can have optional `requirements`. If these are set, the user is asked to check if they are meet. +- `android`: [OPTIONAL] int|str; Android version to install prior to installing a custom ROM. +- `firmware`: [OPTIONAL] str; specific firmware version to install before installing a custom ROM. + +##### How to write steps: +Every step in the config file corresponds to one view in the application. These steps should contain the following fields: +- `type`: str; Corresponds to the type of view to generate. There are the following options: + - `text`: Just display the text given in content. + - `confirm_button`: Display the content, as well as a button to allow the user to go to the next step. + - `call_button`: Display the content text and a button that runs a given command. After the command is run, a confirm button is displayed to allow the user to move to the next step. + - `call_button_with_input`: Display the content text, an input field and a button that runs a given command. The inputtext, can be used in the command by using the `` placeholder in the command field. After the command is run, a confirm button is displayed to allow the user to move to the next step. + - `link_button_with_confirm`: Display a button that opens a browser with a given link, confirm afterwards. Link is given in `link`. +- `img`: [OPTIONAL] Display an image on the left pane of the step view. Images are loaded from `openandroidinstaller/assets/imgs/`. +- `content`: str; The content text displayed alongside the action of the step. Used to inform the user about what's going on. For consistency and better readability the text should be moved into the next line using `>`. +- `link`: [OPTIONAL] Link to use for the link button if type is `link_button_with_confirm`. +- `command`: [ONLY for call_button* steps] str; The command to run. One of `adb_reboot`, `adb_reboot_bootloader`, `adb_reboot_download`, `adb_sideload`, `adb_twrp_wipe_and_install`, `adb_twrp_copy_partitions`, `fastboot_boot_recovery`, `fastboot_flash_recovery`, `fastboot_reboot_recovery`, `fastboot_flash_additional_partitions`, `fastboot_unlock_with_code`, `fastboot_unlock`, `fastboot_unlock_critical`, `fastboot_oem_unlock`, `fastboot_get_unlock_data`, `fastboot_reboot`, `heimdall_flash_recovery`. +- `allow_skip`: [OPTIONAL] boolean; If a skip button should be displayed to allow skipping this step. Can be useful when the bootloader is already unlocked. + +**Please try to retain this order of these fields in your config to ensure consistency.** + diff --git a/docs/unlocking_the_bootloader.md b/docs/unlocking_the_bootloader.md new file mode 100644 index 00000000..e693a721 --- /dev/null +++ b/docs/unlocking_the_bootloader.md @@ -0,0 +1,30 @@ +# On unlocking the bootloader + +> [!IMPORTANT] +> First of all, this tool will not help you bypass any vender locked bootloaders in non-official ways. + +Devices by *Samsung, Google, OnePlus, Fairphone* and others make it relatively easy to unlock the bootloader and get good support in the installer. + +For some devices, it is necessary to unlock the bootloader manually. You usually need to create an account on the manufacturer's website, wait for a certain time and obtain a code from there. OpenAndroidInstaller will try to guide you as far as possible. These vendors include *Sony, Motorola and Xiaomi* amongst others. + +Other phone manufacturers no longer allow you to unlock the bootloader. Nothing can be done if you have not unlocked your device in time. These manufacturers include *Huawei, Honor, LG and ASUS*. Support for these manufacturers will always be very limited. + +## Here is a brief overview of the bootloader policies of some of the most popular brands (may be incomplete/inaccurate) + +| Brand | Flashing tool | Unlocking Method | Loss of guarantee\* | Supported models | +|---|---|---|---|---| +| Google | Fastboot | OEM/Flashing unlock | No | Pixel and Nexus | +| Samsung | ODIN or Heimdall | Download mode | **Yes** | Galaxy S and A series
(Increasing complexity **on and after S10**) | +| OnePlus | Fastboot | OEM/Flashing unlock | No | All | +| Fairphone | Fastboot | [Code from manufacturer](https://support.fairphone.com/hc/en-us/articles/10492476238865-Manage-the-Bootloader)
(**Already unlocked until FP2**) | No | All | +| Xiaomi | Fastboot | [Mi Unlock Tool](https://new.c.mi.com/global/post/101245) | **Yes** | Mi 4c, Redmi Note 3, Mi Note Pro, Redmi 3, Mi 4S, Mi 5 and all devices from 2016 onwards | +| Motorola | Fastboot | [Code from manufacturer](https://en-us.support.motorola.com/app/standalone/bootloader/unlock-your-device-a) | **Yes** | Almost all **except** carrier specific models (e.g. Verizon, AT&T, Tracfone) and certain other models | +| Sony | Fastboot | [Code from manufacturer](https://developer.sony.com/open-source/aosp-on-xperia-open-devices/get-started/unlock-bootloader) | **Yes** | All **except** XQ-CT62 (1Ⅳ US) & XQ-CQ62 (5Ⅳ US) | +| Huawei | Fastboot | No official codes since 2017/2018
(**Unofficial methods available**) | **Yes** | Mate 9/9Pro, P10/P10Plus | +| Honor | Fastboot | No official codes since 2017/2018
(**Unofficial methods available**) | **Yes** | Honor 8 | +| LG | Fastboot | Impossible since December 2021 | **Yes** | | +| ASUS | Fastboot | Impossible since May 2023 (ASUS unlocking App) | **Yes** | | + +**\*** In the EU you won't loose your standard 2 years of the warranty when you unlock your bootloader, flash your device or root it. ([source](https://forum.xda-developers.com/t/info-eu-rooting-and-flashing-dont-void-the-warranty.1998801/)) + +You can find more information about the brands and their bootloader policies [here](https://wikilibriste.fr/fr/tutoriels-android/bootloader-unlock) (in French). diff --git a/openandroidinstaller/app_state.py b/openandroidinstaller/app_state.py index eee468a9..30f68b08 100644 --- a/openandroidinstaller/app_state.py +++ b/openandroidinstaller/app_state.py @@ -16,8 +16,9 @@ import copy from pathlib import Path from typing import List, Optional +from loguru import logger -from installer_config import _load_config +from installer_config import _load_config, Step class AppState: @@ -37,6 +38,10 @@ def __init__( self.test = test self.test_config = test_config + # store state + self.unlock_bootloader = True + self.flash_recovery = True + # placeholders self.advanced = False self.install_addons = False @@ -44,6 +49,9 @@ def __init__( self.config = None self.image_path = None self.recovery_path = None + self.dtbo_path = None + self.vbmeta_path = None + self.super_empty_path = None # store views self.default_views: List = [] @@ -69,3 +77,48 @@ def load_config(self, device_code: str): self.steps = copy.deepcopy(self.config.unlock_bootloader) + copy.deepcopy( self.config.boot_recovery ) + + def toggle_flash_unlock_bootloader(self): + """Toggle flashing of unlock bootloader.""" + self.unlock_bootloader = not self.unlock_bootloader + if self.unlock_bootloader: + logger.info("Enabled unlocking the bootloader again.") + self.steps = copy.deepcopy(self.config.unlock_bootloader) + else: + logger.info("Skipping bootloader unlocking.") + self.steps = [] + # if the recovery is already flashed, skip flashing it again + if self.flash_recovery: + self.steps += copy.deepcopy(self.config.boot_recovery) + else: + self.steps = [ + Step( + title="Boot custom recovery", + type="confirm_button", + content="If you already flashed TWRP, boot into it by pressing 'Confirm and run'. Otherwise restart the process. Once your phone screen looks like the picture on the left, continue.", + command="adb_reboot_recovery", + img="twrp-start.jpeg", + ) + ] + + def toggle_flash_recovery(self): + """Toggle flashing of recovery.""" + self.flash_recovery = not self.flash_recovery + if self.unlock_bootloader: + self.steps = copy.deepcopy(self.config.unlock_bootloader) + else: + self.steps = [] + if self.flash_recovery: + logger.info("Enabled flashing recovery again.") + self.steps += copy.deepcopy(self.config.boot_recovery) + else: + logger.info("Skipping flashing recovery.") + self.steps = [ + Step( + title="Boot custom recovery", + type="call_button", + content="If you already flashed TWRP, boot into it by pressing 'Confirm and run'. Otherwise restart the process. Once your phone screen looks like the picture on the left, continue.", + command="adb_reboot_recovery", + img="twrp-start.jpeg", + ) + ] diff --git a/openandroidinstaller/assets/configs/Mi439.yaml b/openandroidinstaller/assets/configs/Mi439.yaml new file mode 100644 index 00000000..a5362a32 --- /dev/null +++ b/openandroidinstaller/assets/configs/Mi439.yaml @@ -0,0 +1,68 @@ +metadata: + maintainer: A non (anon) + brand: xiaomi + device_name: Xiaomi Redmi 7A / 8 / 8A / 8A Dual + is_ab_device: false + device_code: Mi439 + additional_steps: + - dtbo + - vbmeta + - super_empty + supported_device_codes: + - Mi439 + - mi439 + - pine + - olive + - olivelite + - olivewood + notes: + - Be careful when choosing OrangeFox version, Android 12 & 13 ROM needs OrangeFox version code with `A12`, for example `R11.1_5_A12`. Android 10 & 11 ROM needs OrangeFox version code without `A12` (bellow on the page) +requirements: + firmware: MiUI 12.5 (Q) +steps: + unlock_bootloader: + - type: confirm_button + content: > + As a first step, you need to unlock the bootloader. A bootloader is the piece of software, that tells your phone + how to start and run an operating system (like Android). Your device should be turned on. This will reset your phone. + - type: link_button_with_confirm + content: > + - Create a Mi account on Xiaomi’s website. Beware that one account is only allowed to unlock one unique device every 30 days. + + - Add a phone number to your Mi account, insert a SIM into your phone. + + - Enable developer options in `Settings` > `About Phone` by repeatedly tapping MIUI Version. + + - Link the device to your Mi account in `Settings` > `Additional settings` > `Developer options` > `Mi Unlock status`. + + - Download the Mi Unlock app with the link bellow (Windows is required to run the app), and follow the instructions provided by the app. It may tell you that you have to wait, usually 7 days. If it does so, please wait the quoted amount of time before continuing to the next step! + + - After device and Mi account are successfully verified, the bootloader should be unlocked. + + - Since the device resets completely, you will need to re-enable USB debugging to continue : `Settings` > `Additional settings` > `Developer options` > `USB debugging` + link: https://en.miui.com/unlock/download_en.html + boot_recovery: + - type: call_button + content: > + Now you need to install a custom recovery system on the phone. A recovery is a small subsystem on your phone, + that manages updating, adapting and repairing of the operating system. + + Once the device is fully booted, you need to reboot into the bootloader again by pressing 'Confirm and run' here. Then continue. + command: adb_reboot_bootloader + - type: call_button + content: > + Install additional partitions selected before by pressing 'Confirm and run'. Once it's done continue. + + Note : If you have not selected this partition, it will do nothing. + command: fastboot_flash_additional_partitions + - type: call_button + content: > + Install the recovery you chosen before by pressing 'Confirm and run'. Once it's done continue. + command: fastboot_flash_recovery + - type: call_button + img: ofox.png + content: > + Reboot to recovery by pressing 'Confirm and run', and hold the Vol+ button of your phone UNTIL you see the recovery. + If MiUI starts, you have to start the process again, since MiUI delete the recovery you just flashed. + Once it's done continue. + command: fastboot_reboot_recovery \ No newline at end of file diff --git a/openandroidinstaller/assets/configs/a5y17lte.yaml b/openandroidinstaller/assets/configs/a5y17lte.yaml index 47df4dbf..e0ea6925 100644 --- a/openandroidinstaller/assets/configs/a5y17lte.yaml +++ b/openandroidinstaller/assets/configs/a5y17lte.yaml @@ -5,6 +5,7 @@ metadata: device_code: a5y17lte supported_device_codes: - a5y17lte + - a5y17ltecan steps: unlock_bootloader: boot_recovery: diff --git a/openandroidinstaller/assets/configs/begonia.yaml b/openandroidinstaller/assets/configs/begonia.yaml new file mode 100644 index 00000000..f99ef571 --- /dev/null +++ b/openandroidinstaller/assets/configs/begonia.yaml @@ -0,0 +1,56 @@ +metadata: + maintainer: A non (anon) + brand: xiaomi + device_name: Xiaomi Redmi Note 8 Pro + is_ab_device: false + device_code: begonia + supported_device_codes: + - begonia + - begoniain + untested: true + notes: + - You should install Android 10 or newer ROM. +requirements: + android: 11 (MiUI 12.5) +steps: + unlock_bootloader: + - type: confirm_button + content: > + As a first step, you need to unlock the bootloader. A bootloader is the piece of software, that tells your phone + how to start and run an operating system (like Android). Your device should be turned on. This will reset your phone. + - type: link_button_with_confirm + content: > + - Create a Mi account on Xiaomi’s website. Beware that one account is only allowed to unlock one unique device every 30 days. + + - Add a phone number to your Mi account, insert a SIM into your phone. + + - Enable developer options in `Settings` > `About Phone` by repeatedly tapping MIUI Version. + + - Link the device to your Mi account in `Settings` > `Additional settings` > `Developer options` > `Mi Unlock status`. + + - Download the Mi Unlock app with the link bellow (Windows is required to run the app), and follow the instructions provided by the app. It may tell you that you have to wait, usually 7 days. If it does so, please wait the quoted amount of time before continuing to the next step! + + - After device and Mi account are successfully verified, the bootloader should be unlocked. + + - Since the device resets completely, you will need to re-enable USB debugging to continue : `Settings` > `Additional settings` > `Developer options` > `USB debugging` + link: https://en.miui.com/unlock/download_en.html + boot_recovery: + - type: confirm_button + content: > + Now you need to boot a custom recovery system on the phone. A recovery is a small subsystem on your phone, that manages updating, + adapting and repairing of the operating system. + - type: call_button + content: > + Once the device is fully booted, you need to reboot into the bootloader again by pressing 'Confirm and run' here. Then continue. + command: adb_reboot_bootloader + - type: call_button + content: > + Install the recovery you chosen before by pressing 'Confirm and run'. Once it's done continue. + command: fastboot_flash_recovery + - type: call_button + img: ofox.png + content: > + Reboot to recovery by pressing 'Confirm and run', and hold the Vol+ button of your phone UNTIL you see the recovery. + If MiUI starts, you have to start the process again, since MiUI delete the recovery you just flashed. + Once it's done continue. + command: fastboot_reboot_recovery \ No newline at end of file diff --git a/openandroidinstaller/assets/configs/beyond0lte.yaml b/openandroidinstaller/assets/configs/beyond0lte.yaml index 21f89f18..ffbcd414 100644 --- a/openandroidinstaller/assets/configs/beyond0lte.yaml +++ b/openandroidinstaller/assets/configs/beyond0lte.yaml @@ -4,7 +4,8 @@ metadata: is_ab_device: false device_code: beyond0lte supported_device_codes: - - beyond0lte + - beyond0lte + - beyond0 requirements: android: 12 steps: diff --git a/openandroidinstaller/assets/configs/beyond1lte.yaml b/openandroidinstaller/assets/configs/beyond1lte.yaml index fa5c8161..f83f9740 100644 --- a/openandroidinstaller/assets/configs/beyond1lte.yaml +++ b/openandroidinstaller/assets/configs/beyond1lte.yaml @@ -4,7 +4,8 @@ metadata: is_ab_device: false device_code: beyond1lte supported_device_codes: - - beyond1lte + - beyond1lte + - beyond1 requirements: android: 12 steps: diff --git a/openandroidinstaller/assets/configs/cupid.yaml b/openandroidinstaller/assets/configs/cupid.yaml new file mode 100644 index 00000000..117a50e1 --- /dev/null +++ b/openandroidinstaller/assets/configs/cupid.yaml @@ -0,0 +1,62 @@ +metadata: + maintainer: A non (anon) + brand: xiaomi + device_name: Xiaomi 12 + is_ab_device: false + additional_steps: + - dtbo + - vbmeta + - super_empty + device_code: cupid + supported_device_codes: + - cupid + untested: true +requirements: + android: 13 +steps: + unlock_bootloader: + - type: confirm_button + content: > + As a first step, you need to unlock the bootloader. A bootloader is the piece of software, that tells your phone + how to start and run an operating system (like Android). Your device should be turned on. This will reset your phone. + - type: link_button_with_confirm + content: > + - Create a Mi account on Xiaomi’s website. Beware that one account is only allowed to unlock one unique device every 30 days. + + - Add a phone number to your Mi account, insert a SIM into your phone. + + - Enable developer options in `Settings` > `About Phone` by repeatedly tapping MIUI Version. + + - Link the device to your Mi account in `Settings` > `Additional settings` > `Developer options` > `Mi Unlock status`. + + - Download the Mi Unlock app with the link bellow (Windows is required to run the app), and follow the instructions provided by the app. It may tell you that you have to wait, usually 7 days. If it does so, please wait the quoted amount of time before continuing to the next step! + + - After device and Mi account are successfully verified, the bootloader should be unlocked. + + - Since the device resets completely, you will need to re-enable USB debugging to continue : `Settings` > `Additional settings` > `Developer options` > `USB debugging` + link: https://en.miui.com/unlock/download_en.html + boot_recovery: + - type: call_button + content: > + Now you need to install a custom recovery system on the phone. A recovery is a small subsystem on your phone, + that manages updating, adapting and repairing of the operating system. + + Once the device is fully booted, you need to reboot into the bootloader again by pressing 'Confirm and run' here. Then continue. + command: adb_reboot_bootloader + - type: call_button + content: > + Install additional partitions selected before by pressing 'Confirm and run'. Once it's done continue. + + Note : If you have not selected this partition, it will do nothing. + command: fastboot_flash_additional_partitions + - type: call_button + content: > + Install the recovery you chosen before by pressing 'Confirm and run'. Once it's done continue. + command: fastboot_flash_recovery + - type: call_button + img: ofox.png + content: > + Reboot to recovery by pressing 'Confirm and run', and hold the Vol+ button of your phone UNTIL you see the recovery. + If MiUI starts, you have to start the process again, since MiUI delete the recovery you just flashed. + Once it's done continue. + command: fastboot_reboot_recovery diff --git a/openandroidinstaller/assets/configs/davinci.yaml b/openandroidinstaller/assets/configs/davinci.yaml new file mode 100644 index 00000000..73b4554a --- /dev/null +++ b/openandroidinstaller/assets/configs/davinci.yaml @@ -0,0 +1,52 @@ +metadata: + maintainer: A non (anon) + brand: xiaomi + device_name: Xiaomi Mi 9T / Redmi K20 + is_ab_device: false + device_code: davinci + supported_device_codes: + - davinci + - davinciin + untested: true +steps: + unlock_bootloader: + - type: confirm_button + content: > + As a first step, you need to unlock the bootloader. A bootloader is the piece of software, that tells your phone + how to start and run an operating system (like Android). Your device should be turned on. This will reset your phone. + - type: link_button_with_confirm + content: > + - Create a Mi account on Xiaomi’s website. Beware that one account is only allowed to unlock one unique device every 30 days. + + - Add a phone number to your Mi account, insert a SIM into your phone. + + - Enable developer options in `Settings` > `About Phone` by repeatedly tapping MIUI Version. + + - Link the device to your Mi account in `Settings` > `Additional settings` > `Developer options` > `Mi Unlock status`. + + - Download the Mi Unlock app with the link bellow (Windows is required to run the app), and follow the instructions provided by the app. It may tell you that you have to wait, usually 7 days. If it does so, please wait the quoted amount of time before continuing to the next step! + + - After device and Mi account are successfully verified, the bootloader should be unlocked. + + - Since the device resets completely, you will need to re-enable USB debugging to continue : `Settings` > `Additional settings` > `Developer options` > `USB debugging` + link: https://en.miui.com/unlock/download_en.html + boot_recovery: + - type: confirm_button + content: > + Now you need to boot a custom recovery system on the phone. A recovery is a small subsystem on your phone, that manages updating, + adapting and repairing of the operating system. + - type: call_button + content: > + Once the device is fully booted, you need to reboot into the bootloader again by pressing 'Confirm and run' here. Then continue. + command: adb_reboot_bootloader + - type: call_button + content: > + Install the recovery you chosen before by pressing 'Confirm and run'. Once it's done continue. + command: fastboot_flash_recovery + - type: call_button + img: ofox.png + content: > + Reboot to recovery by pressing 'Confirm and run', and hold the Vol+ button of your phone UNTIL you see the recovery. + If MiUI starts, you have to start the process again, since MiUI delete the recovery you just flashed. + Once it's done continue. + command: fastboot_reboot_recovery diff --git a/openandroidinstaller/assets/configs/dreamlte.yaml b/openandroidinstaller/assets/configs/dreamlte.yaml index 694b17b6..88de8897 100644 --- a/openandroidinstaller/assets/configs/dreamlte.yaml +++ b/openandroidinstaller/assets/configs/dreamlte.yaml @@ -7,18 +7,20 @@ metadata: - dreamlte twrp-link: dreamlte requirements: - android: "9.0" + android: 9 steps: unlock_bootloader: boot_recovery: - type: call_button content: > As a first step, you need to boot into the bootloader. A bootloader is the piece of software, - that tells your phone who to start and run an operating system (like Android). Your device should be turned on. + that tells your phone how to start and run an operating system (like Android). Your device should be turned on. Then press 'Confirm and run' to reboot into the bootloader. Continue once it's done. command: adb_reboot_download - type: call_button - content: In this step, you need to boot a custom recovery on your device. Press 'Confirm and run' to start the process. Confirm afterwards to continue. + content: > + In this step, you need to flash a custom recovery on your device. + Press 'Confirm and run' to start the process. Confirm afterwards to continue. command: heimdall_flash_recovery - type: confirm_button img: samsung-buttons-bixby.png diff --git a/openandroidinstaller/assets/configs/garden.yaml b/openandroidinstaller/assets/configs/garden.yaml new file mode 100644 index 00000000..512a9913 --- /dev/null +++ b/openandroidinstaller/assets/configs/garden.yaml @@ -0,0 +1,57 @@ +metadata: + maintainer: A non (anon) + brand: xiaomi + device_name: Xiaomi Redmi 9A / 9C / 9AT / 9i / 9A Sport / 10A / 10A Sport + is_ab_device: false + device_code: garden + supported_device_codes: + - dandelion + - garden + - blossom + - angelican + notes: + - OAI don't support ROM that requires permissiver. +requirements: + firmware: MiUI 12.5 (Q) +steps: + unlock_bootloader: + - type: confirm_button + content: > + As a first step, you need to unlock the bootloader. A bootloader is the piece of software, that tells your phone + how to start and run an operating system (like Android). Your device should be turned on. This will reset your phone. + - type: link_button_with_confirm + content: > + - Create a Mi account on Xiaomi’s website. Beware that one account is only allowed to unlock one unique device every 30 days. + + - Add a phone number to your Mi account, insert a SIM into your phone. + + - Enable developer options in `Settings` > `About Phone` by repeatedly tapping MIUI Version. + + - Link the device to your Mi account in `Settings` > `Additional settings` > `Developer options` > `Mi Unlock status`. + + - Download the Mi Unlock app with the link bellow (Windows is required to run the app), and follow the instructions provided by the app. It may tell you that you have to wait, usually 7 days. If it does so, please wait the quoted amount of time before continuing to the next step! + + - After device and Mi account are successfully verified, the bootloader should be unlocked. + + - Since the device resets completely, you will need to re-enable USB debugging to continue : `Settings` > `Additional settings` > `Developer options` > `USB debugging` + link: https://en.miui.com/unlock/download_en.html + boot_recovery: + - type: confirm_button + content: > + Now you need to boot a custom recovery system on the phone. A recovery is a small subsystem on your phone, that manages updating, + adapting and repairing of the operating system. + - type: call_button + content: > + Once the device is fully booted, you need to reboot into the bootloader again by pressing 'Confirm and run' here. Then continue. + command: adb_reboot_bootloader + - type: call_button + content: > + Install the recovery you chosen before by pressing 'Confirm and run'. Once it's done continue. + command: fastboot_flash_recovery + - type: call_button + img: ofox.png + content: > + Reboot to recovery by pressing 'Confirm and run', and hold the Vol+ button of your phone UNTIL you see the recovery. + If MiUI starts, you have to start the process again, since MiUI delete the recovery you just flashed. + Once it's done continue. + command: fastboot_reboot_recovery \ No newline at end of file diff --git a/openandroidinstaller/assets/configs/ginkgo.yaml b/openandroidinstaller/assets/configs/ginkgo.yaml new file mode 100644 index 00000000..b2bd6c3f --- /dev/null +++ b/openandroidinstaller/assets/configs/ginkgo.yaml @@ -0,0 +1,56 @@ +metadata: + maintainer: A non (anon) + brand: xiaomi + device_name: Xiaomi Redmi Note 8 / 8T + is_ab_device: false + device_code: ginkgo + supported_device_codes: + - ginkgo + - willow + untested: true + notes: + - You should install Android 10 or newer ROM. +requirements: + android: 10 (Q) +steps: + unlock_bootloader: + - type: confirm_button + content: > + As a first step, you need to unlock the bootloader. A bootloader is the piece of software, that tells your phone + how to start and run an operating system (like Android). Your device should be turned on. This will reset your phone. + - type: link_button_with_confirm + content: > + - Create a Mi account on Xiaomi’s website. Beware that one account is only allowed to unlock one unique device every 30 days. + + - Add a phone number to your Mi account, insert a SIM into your phone. + + - Enable developer options in `Settings` > `About Phone` by repeatedly tapping MIUI Version. + + - Link the device to your Mi account in `Settings` > `Additional settings` > `Developer options` > `Mi Unlock status`. + + - Download the Mi Unlock app with the link bellow (Windows is required to run the app), and follow the instructions provided by the app. It may tell you that you have to wait, usually 7 days. If it does so, please wait the quoted amount of time before continuing to the next step! + + - After device and Mi account are successfully verified, the bootloader should be unlocked. + + - Since the device resets completely, you will need to re-enable USB debugging to continue : `Settings` > `Additional settings` > `Developer options` > `USB debugging` + link: https://en.miui.com/unlock/download_en.html + boot_recovery: + - type: confirm_button + content: > + Now you need to boot a custom recovery system on the phone. A recovery is a small subsystem on your phone, that manages updating, + adapting and repairing of the operating system. + - type: call_button + content: > + Once the device is fully booted, you need to reboot into the bootloader again by pressing 'Confirm and run' here. Then continue. + command: adb_reboot_bootloader + - type: call_button + content: > + Install the recovery you chosen before by pressing 'Confirm and run'. Once it's done continue. + command: fastboot_flash_recovery + - type: call_button + img: ofox.png + content: > + Reboot to recovery by pressing 'Confirm and run', and hold the Vol+ button of your phone UNTIL you see the recovery. + If MiUI starts, you have to start the process again, since MiUI delete the recovery you just flashed. + Once it's done continue. + command: fastboot_reboot_recovery \ No newline at end of file diff --git a/openandroidinstaller/assets/configs/grandprimevelte.yaml b/openandroidinstaller/assets/configs/grandprimevelte.yaml index 3b913f17..2ac226c0 100644 --- a/openandroidinstaller/assets/configs/grandprimevelte.yaml +++ b/openandroidinstaller/assets/configs/grandprimevelte.yaml @@ -14,11 +14,13 @@ steps: - type: call_button content: > As a first step, you need to boot into the bootloader. A bootloader is the piece of software, - that tells your phone who to start and run an operating system (like Android). Your device should be turned on. + that tells your phone how to start and run an operating system (like Android). Your device should be turned on. Then press 'Confirm and run' to reboot into the bootloader. Continue once it's done. command: adb_reboot_download - type: call_button - content: In this step, you need to boot a custom recovery on your device. Press 'Confirm and run' to start the process. Confirm afterwards to continue. + content: > + In this step, you need to flash a custom recovery on your device. + Press 'Confirm and run' to start the process. Confirm afterwards to continue. command: heimdall_flash_recovery - type: confirm_button img: samsung-buttons.png diff --git a/openandroidinstaller/assets/configs/j7elte.yaml b/openandroidinstaller/assets/configs/j7elte.yaml index a34c5e98..ca66f630 100644 --- a/openandroidinstaller/assets/configs/j7elte.yaml +++ b/openandroidinstaller/assets/configs/j7elte.yaml @@ -4,7 +4,9 @@ metadata: is_ab_device: false device_code: j7elte supported_device_codes: - - j7elte + - j7elte + - j7eltetmo + twrp-link: j7elte steps: unlock_bootloader: boot_recovery: diff --git a/openandroidinstaller/assets/configs/klte.yaml b/openandroidinstaller/assets/configs/klte.yaml new file mode 100644 index 00000000..c9dfcc47 --- /dev/null +++ b/openandroidinstaller/assets/configs/klte.yaml @@ -0,0 +1,27 @@ +metadata: + maintainer: Tobias Sterbak (tsterbak) + device_name: Samsung Galaxy S5 LTE + is_ab_device: false + device_code: klte + supported_device_codes: + - klte +steps: + unlock_bootloader: + boot_recovery: + - type: call_button + content: > + As a first step, you need to boot into the bootloader. A bootloader is the piece of software, + that tells your phone how to start and run an operating system (like Android). Your device should be turned on. + Then press 'Confirm and run' to reboot into the bootloader. Continue once it's done. + command: adb_reboot_download + - type: call_button + content: > + In this step, you need to flash a custom recovery on your device. + Press 'Confirm and run' to start the process. Confirm afterwards to continue. + command: heimdall_flash_recovery + - type: confirm_button + img: samsung-buttons.png + content: > + Unplug the USB cable from your device. Then manually reboot into recovery by pressing the *Volume Down* + *Power buttons* for 8~10 seconds + until the screen turns black & release the buttons immediately when it does, then boot to recovery with the device powered off, + hold *Volume Up* + *Home* + *Power button*. \ No newline at end of file diff --git a/openandroidinstaller/assets/configs/lavender.yaml b/openandroidinstaller/assets/configs/lavender.yaml new file mode 100644 index 00000000..754269f1 --- /dev/null +++ b/openandroidinstaller/assets/configs/lavender.yaml @@ -0,0 +1,54 @@ +metadata: + maintainer: A non (anon) + brand: xiaomi + device_name: Xiaomi Redmi Note 7 + is_ab_device: false + device_code: lavender + supported_device_codes: + - lavender + notes: + - You should install Android 10 or newer ROM. +requirements: + android: 10 (Q) +steps: + unlock_bootloader: + - type: confirm_button + content: > + As a first step, you need to unlock the bootloader. A bootloader is the piece of software, that tells your phone + how to start and run an operating system (like Android). Your device should be turned on. This will reset your phone. + - type: link_button_with_confirm + content: > + - Create a Mi account on Xiaomi’s website. Beware that one account is only allowed to unlock one unique device every 30 days. + + - Add a phone number to your Mi account, insert a SIM into your phone. + + - Enable developer options in `Settings` > `About Phone` by repeatedly tapping MIUI Version. + + - Link the device to your Mi account in `Settings` > `Additional settings` > `Developer options` > `Mi Unlock status`. + + - Download the Mi Unlock app with the link bellow (Windows is required to run the app), and follow the instructions provided by the app. It may tell you that you have to wait, usually 7 days. If it does so, please wait the quoted amount of time before continuing to the next step! + + - After device and Mi account are successfully verified, the bootloader should be unlocked. + + - Since the device resets completely, you will need to re-enable USB debugging to continue : `Settings` > `Additional settings` > `Developer options` > `USB debugging` + link: https://en.miui.com/unlock/download_en.html + boot_recovery: + - type: confirm_button + content: > + Now you need to boot a custom recovery system on the phone. A recovery is a small subsystem on your phone, that manages updating, + adapting and repairing of the operating system. + - type: call_button + content: > + Once the device is fully booted, you need to reboot into the bootloader again by pressing 'Confirm and run' here. Then continue. + command: adb_reboot_bootloader + - type: call_button + content: > + Install the recovery you chosen before by pressing 'Confirm and run'. Once it's done continue. + command: fastboot_flash_recovery + - type: call_button + img: ofox.png + content: > + Reboot to recovery by pressing 'Confirm and run', and hold the Vol+ button of your phone UNTIL you see the recovery. + If MiUI starts, you have to start the process again, since MiUI delete the recovery you just flashed. + Once it's done continue. + command: fastboot_reboot_recovery \ No newline at end of file diff --git a/openandroidinstaller/assets/configs/miatoll.yaml b/openandroidinstaller/assets/configs/miatoll.yaml new file mode 100644 index 00000000..82c15a88 --- /dev/null +++ b/openandroidinstaller/assets/configs/miatoll.yaml @@ -0,0 +1,57 @@ +metadata: + maintainer: A non (anon) + brand: xiaomi + device_name: Xiaomi Redmi Note 9S / 9 Pro / 9 Pro Max / 10 Lite / Poco M2 pro + is_ab_device: false + device_code: miatoll + supported_device_codes: + - miatoll + - gram + - curtana + - excalibur + - joyeuse + untested: true +requirements: + android: 12 +steps: + unlock_bootloader: + - type: confirm_button + content: > + As a first step, you need to unlock the bootloader. A bootloader is the piece of software, that tells your phone + how to start and run an operating system (like Android). Your device should be turned on. This will reset your phone. + - type: link_button_with_confirm + content: > + - Create a Mi account on Xiaomi’s website. Beware that one account is only allowed to unlock one unique device every 30 days. + + - Add a phone number to your Mi account, insert a SIM into your phone. + + - Enable developer options in `Settings` > `About Phone` by repeatedly tapping MIUI Version. + + - Link the device to your Mi account in `Settings` > `Additional settings` > `Developer options` > `Mi Unlock status`. + + - Download the Mi Unlock app with the link bellow (Windows is required to run the app), and follow the instructions provided by the app. It may tell you that you have to wait, usually 7 days. If it does so, please wait the quoted amount of time before continuing to the next step! + + - After device and Mi account are successfully verified, the bootloader should be unlocked. + + - Since the device resets completely, you will need to re-enable USB debugging to continue : `Settings` > `Additional settings` > `Developer options` > `USB debugging` + link: https://en.miui.com/unlock/download_en.html + boot_recovery: + - type: confirm_button + content: > + Now you need to boot a custom recovery system on the phone. A recovery is a small subsystem on your phone, that manages updating, + adapting and repairing of the operating system. + - type: call_button + content: > + Once the device is fully booted, you need to reboot into the bootloader again by pressing 'Confirm and run' here. Then continue. + command: adb_reboot_bootloader + - type: call_button + content: > + Install the recovery you chosen before by pressing 'Confirm and run'. Once it's done continue. + command: fastboot_flash_recovery + - type: call_button + img: ofox.png + content: > + Reboot to recovery by pressing 'Confirm and run', and hold the Vol+ button of your phone UNTIL you see the recovery. + If MiUI starts, you have to start the process again, since MiUI delete the recovery you just flashed. + Once it's done continue. + command: fastboot_reboot_recovery \ No newline at end of file diff --git a/openandroidinstaller/assets/configs/raphael.yaml b/openandroidinstaller/assets/configs/raphael.yaml new file mode 100644 index 00000000..db518866 --- /dev/null +++ b/openandroidinstaller/assets/configs/raphael.yaml @@ -0,0 +1,59 @@ +metadata: + maintainer: A non (anon) + brand: xiaomi + device_name: Xiaomi Mi 9T Pro / Redmi K20 Pro + is_ab_device: false + device_code: raphael + additional_steps: + - super_empty + supported_device_codes: + - raphael + - raphaelin + untested: true +steps: + unlock_bootloader: + - type: confirm_button + content: > + As a first step, you need to unlock the bootloader. A bootloader is the piece of software, that tells your phone + how to start and run an operating system (like Android). Your device should be turned on. This will reset your phone. + - type: link_button_with_confirm + content: > + - Create a Mi account on Xiaomi’s website. Beware that one account is only allowed to unlock one unique device every 30 days. + + - Add a phone number to your Mi account, insert a SIM into your phone. + + - Enable developer options in `Settings` > `About Phone` by repeatedly tapping MIUI Version. + + - Link the device to your Mi account in `Settings` > `Additional settings` > `Developer options` > `Mi Unlock status`. + + - Download the Mi Unlock app with the link bellow (Windows is required to run the app), and follow the instructions provided by the app. It may tell you that you have to wait, usually 7 days. If it does so, please wait the quoted amount of time before continuing to the next step! + + - After device and Mi account are successfully verified, the bootloader should be unlocked. + + - Since the device resets completely, you will need to re-enable USB debugging to continue : `Settings` > `Additional settings` > `Developer options` > `USB debugging` + link: https://en.miui.com/unlock/download_en.html + boot_recovery: + - type: call_button + content: > + Now you need to install a custom recovery system on the phone. A recovery is a small subsystem on your phone, + that manages updating, adapting and repairing of the operating system. + + Once the device is fully booted, you need to reboot into the bootloader again by pressing 'Confirm and run' here. Then continue. + command: adb_reboot_bootloader + - type: call_button + content: > + Install additional partitions selected before by pressing 'Confirm and run'. Once it's done continue. + + Note : If you have not selected this partition, it will do nothing. + command: fastboot_flash_additional_partitions + - type: call_button + content: > + Install the recovery you chosen before by pressing 'Confirm and run'. Once it's done continue. + command: fastboot_flash_recovery + - type: call_button + img: ofox.png + content: > + Reboot to recovery by pressing 'Confirm and run', and hold the Vol+ button of your phone UNTIL you see the recovery. + If MiUI starts, you have to start the process again, since MiUI delete the recovery you just flashed. + Once it's done continue. + command: fastboot_reboot_recovery diff --git a/openandroidinstaller/assets/configs/rosemary.yaml b/openandroidinstaller/assets/configs/rosemary.yaml new file mode 100644 index 00000000..9bf589ed --- /dev/null +++ b/openandroidinstaller/assets/configs/rosemary.yaml @@ -0,0 +1,50 @@ +metadata: + maintainer: A non (anon) + brand: xiaomi + device_name: Xiaomi Redmi Note 10S / 11SE / Poco M5S + is_ab_device: false + device_code: rosemary + supported_device_codes: + - rosemary + - secret + - maltose + - rosemary_p + untested: true + notes: + - Please respect the requested by the ROM developers version for MIUI and Android. +steps: + unlock_bootloader: + - type: confirm_button + content: > + As a first step, you need to unlock the bootloader. A bootloader is the piece of software, that tells your phone + how to start and run an operating system (like Android). Your device should be turned on. This will reset your phone. + - type: link_button_with_confirm + content: > + - Create a Mi account on Xiaomi’s website. Beware that one account is only allowed to unlock one unique device every 30 days. + + - Add a phone number to your Mi account, insert a SIM into your phone. + + - Enable developer options in `Settings` > `About Phone` by repeatedly tapping MIUI Version. + + - Link the device to your Mi account in `Settings` > `Additional settings` > `Developer options` > `Mi Unlock status`. + + - Download the Mi Unlock app with the link bellow (Windows is required to run the app), and follow the instructions provided by the app. It may tell you that you have to wait, usually 7 days. If it does so, please wait the quoted amount of time before continuing to the next step! + + - After device and Mi account are successfully verified, the bootloader should be unlocked. + + - Since the device resets completely, you will need to re-enable USB debugging to continue : `Settings` > `Additional settings` > `Developer options` > `USB debugging` + link: https://en.miui.com/unlock/download_en.html + boot_recovery: + - type: confirm_button + content: > + Now you need to boot a custom recovery system on the phone. A recovery is a small subsystem on your phone, that manages updating, + adapting and repairing of the operating system. + - type: call_button + content: > + Once the device is fully booted, you need to reboot into the bootloader again by pressing 'Confirm and run' here. Then continue. + command: adb_reboot_bootloader + - type: call_button + content: > + Install the recovery you chosen before by pressing 'Confirm and run'. Once it's done continue. + UNTESTED : Need to hold Vol+ or no ? + command: fastboot_flash_boot \ No newline at end of file diff --git a/openandroidinstaller/assets/configs/serranoltexx.yaml b/openandroidinstaller/assets/configs/serranoltexx.yaml index 1d18ebef..f0431ae6 100644 --- a/openandroidinstaller/assets/configs/serranoltexx.yaml +++ b/openandroidinstaller/assets/configs/serranoltexx.yaml @@ -12,7 +12,7 @@ steps: - type: call_button content: > As a first step, you need to boot into the bootloader. A bootloader is the piece of software, - that tells your phone who to start and run an operating system (like Android). Your device should be turned on. + that tells your phone how to start and run an operating system (like Android). Your device should be turned on. Then press 'Confirm and run' to reboot into the bootloader. Continue once it's done. command: adb_reboot_download - type: call_button diff --git a/openandroidinstaller/assets/configs/vayu.yaml b/openandroidinstaller/assets/configs/vayu.yaml new file mode 100644 index 00000000..16223090 --- /dev/null +++ b/openandroidinstaller/assets/configs/vayu.yaml @@ -0,0 +1,54 @@ +metadata: + maintainer: A non (anon) + brand: poco + device_name: Poco X3 Pro + is_ab_device: false + device_code: vayu + supported_device_codes: + - vayu + - bhima + untested: true +requirements: + android: 12 (S) +steps: + unlock_bootloader: + - type: confirm_button + content: > + As a first step, you need to unlock the bootloader. A bootloader is the piece of software, that tells your phone + how to start and run an operating system (like Android). Your device should be turned on. This will reset your phone. + - type: link_button_with_confirm + content: > + - Create a Mi account on Xiaomi’s website. Beware that one account is only allowed to unlock one unique device every 30 days. + + - Add a phone number to your Mi account, insert a SIM into your phone. + + - Enable developer options in `Settings` > `About Phone` by repeatedly tapping MIUI Version. + + - Link the device to your Mi account in `Settings` > `Additional settings` > `Developer options` > `Mi Unlock status`. + + - Download the Mi Unlock app with the link bellow (Windows is required to run the app), and follow the instructions provided by the app. It may tell you that you have to wait, usually 7 days. If it does so, please wait the quoted amount of time before continuing to the next step! + + - After device and Mi account are successfully verified, the bootloader should be unlocked. + + - Since the device resets completely, you will need to re-enable USB debugging to continue : `Settings` > `Additional settings` > `Developer options` > `USB debugging` + link: https://en.miui.com/unlock/download_en.html + boot_recovery: + - type: confirm_button + content: > + Now you need to boot a custom recovery system on the phone. A recovery is a small subsystem on your phone, that manages updating, + adapting and repairing of the operating system. + - type: call_button + content: > + Once the device is fully booted, you need to reboot into the bootloader again by pressing 'Confirm and run' here. Then continue. + command: adb_reboot_bootloader + - type: call_button + content: > + Install the recovery you chosen before by pressing 'Confirm and run'. Once it's done continue. + command: fastboot_flash_recovery + - type: call_button + img: ofox.png + content: > + Reboot to recovery by pressing 'Confirm and run', and hold the Vol+ button of your phone UNTIL you see the recovery. + If MiUI starts, you have to start the process again, since MiUI delete the recovery you just flashed. + Once it's done continue. + command: fastboot_reboot_recovery \ No newline at end of file diff --git a/openandroidinstaller/installer_config.py b/openandroidinstaller/installer_config.py index 2a857d83..7eafe47e 100644 --- a/openandroidinstaller/installer_config.py +++ b/openandroidinstaller/installer_config.py @@ -15,6 +15,7 @@ from pathlib import Path from typing import List, Optional +from typing_extensions import Self import schema import yaml @@ -62,11 +63,13 @@ def __init__( self.requirements = requirements self.device_code = metadata.get("device_code") self.is_ab = metadata.get("is_ab_device", False) + self.additional_steps = metadata.get("additional_steps", []) self.supported_device_codes = metadata.get("supported_device_codes") self.twrp_link = metadata.get("twrp-link") + self.untested = metadata.get("untested", False) @classmethod - def from_file(cls, path): + def from_file(cls, path) -> Self: with open(path, "r", encoding="utf-8") as stream: try: raw_config = yaml.safe_load(stream) @@ -150,7 +153,8 @@ def validate_config(config: str) -> bool: ), "content": str, schema.Optional("command"): Regex( - r"adb_reboot|adb_reboot_bootloader|adb_reboot_download|adb_sideload|adb_twrp_wipe_and_install|adb_twrp_copy_partitions|fastboot_boot_recovery|fastboot_flash_boot|fastboot_unlock_with_code|fastboot_get_unlock_data|fastboot_unlock|fastboot_oem_unlock|fastboot_reboot|heimdall_flash_recovery" + r"""adb_reboot|adb_reboot_bootloader|adb_reboot_download|adb_sideload|adb_twrp_wipe_and_install|adb_twrp_copy_partitions|fastboot_boot_recovery|fastboot_flash_boot|fastboot_flash_recovery| + fastboot_unlock_critical|fastboot_unlock_with_code|fastboot_get_unlock_data|fastboot_unlock|fastboot_oem_unlock|fastboot_reboot|fastboot_reboot_recovery|heimdall_flash_recovery|fastboot_flash_additional_partitions""" ), schema.Optional("allow_skip"): bool, schema.Optional("img"): str, @@ -163,9 +167,15 @@ def validate_config(config: str) -> bool: "maintainer": str, "device_name": str, "is_ab_device": bool, + schema.Optional("untested"): bool, "device_code": str, "supported_device_codes": [str], schema.Optional("twrp-link"): str, + schema.Optional("additional_steps"): [ + Regex(r"dtbo|vbmeta|vendor_boot|super_empty") + ], + schema.Optional("notes"): [str], + schema.Optional("brand"): str, }, schema.Optional("requirements"): { schema.Optional("android"): schema.Or(str, int), diff --git a/openandroidinstaller/openandroidinstaller.py b/openandroidinstaller/openandroidinstaller.py index 2e175dc9..34cfccd5 100644 --- a/openandroidinstaller/openandroidinstaller.py +++ b/openandroidinstaller/openandroidinstaller.py @@ -56,7 +56,7 @@ from tooling import run_command # VERSION number -VERSION = "0.4.5-beta" +VERSION = "0.5.0-beta" # detect platform PLATFORM = sys.platform diff --git a/openandroidinstaller/tooling.py b/openandroidinstaller/tooling.py index d3a551be..03dcff5a 100644 --- a/openandroidinstaller/tooling.py +++ b/openandroidinstaller/tooling.py @@ -161,6 +161,15 @@ def adb_wait_for_sideload(bin_path: Path) -> TerminalResponse: yield line +@add_logging("Reboot to recovery with adb") +def adb_reboot_recovery(bin_path: Path) -> TerminalResponse: + """Reboot to recovery with adb.""" + for line in run_command("adb reboot recovery", bin_path): + yield line + for line in adb_wait_for_recovery(bin_path=bin_path): + yield line + + def adb_twrp_copy_partitions(bin_path: Path, config_path: Path) -> TerminalResponse: # some devices like one plus 6t or motorola moto g7 power need the partitions copied to prevent a hard brick logger.info("Sideload copy_partitions script with adb.") @@ -416,7 +425,7 @@ def fastboot_boot_recovery( def fastboot_flash_boot(bin_path: Path, recovery: str) -> TerminalResponse: - """Temporarily, flash custom recovery with fastboot to boot partition.""" + """Flash custom recovery with fastboot to boot partition.""" logger.info("Flash custom recovery with fastboot.") for line in run_command( "fastboot flash boot", target=f"{recovery}", bin_path=bin_path @@ -440,6 +449,85 @@ def fastboot_flash_boot(bin_path: Path, recovery: str) -> TerminalResponse: yield True +@add_logging("Flash custom recovery with fastboot.") +def fastboot_flash_recovery( + bin_path: Path, recovery: str, is_ab: bool = True +) -> TerminalResponse: + """Flash custom recovery with fastboot.""" + for line in run_command( + "fastboot flash recovery ", target=f"{recovery}", bin_path=bin_path + ): + yield line + if not is_ab: + if (type(line) == bool) and not line: + logger.error("Flashing recovery failed.") + yield False + else: + yield True + + +@add_logging("Rebooting device to recovery.") +def fastboot_reboot_recovery(bin_path: Path) -> TerminalResponse: + """Reboot to recovery with fastboot. + + WARNING: On some devices, users need to press a specific key combo to make it work. + """ + for line in run_command("fastboot reboot recovery", bin_path): + yield line + + +@add_logging("Flash additional partitions with fastboot") +def fastboot_flash_additional_partitions( + bin_path: Path, + dtbo: Optional[str], + vbmeta: Optional[str], + super_empty: Optional[str], + is_ab: bool = True, +) -> TerminalResponse: + """Flash additional partitions (dtbo, vbmeta, super_empty) with fastboot.""" + logger.info("Flash additional partitions with fastboot.") + if dtbo: + logger.info("dtbo selected. Flashing dtbo partition.") + for line in run_command( + "fastboot flash dtbo ", target=f"{dtbo}", bin_path=bin_path + ): + yield line + if not is_ab: + if (type(line) == bool) and not line: + logger.error("Flashing dtbo failed.") + yield False + else: + yield True + else: + yield True + + if vbmeta: + logger.info("vbmeta selected. Flashing vbmeta partition.") + for line in run_command( + "fastboot flash vbmeta ", target=f"{vbmeta}", bin_path=bin_path + ): + yield line + if not is_ab: + if (type(line) == bool) and not line: + logger.error("Flashing vbmeta failed.") + yield False + else: + yield True + + if super_empty: + logger.info("super_empty selected. Wiping super partition.") + for line in run_command( + "fastboot wipe-super ", target=f"{super_empty}", bin_path=bin_path + ): + yield line + if not is_ab: + if (type(line) == bool) and not line: + logger.error("Wiping super failed.") + yield False + else: + yield True + + def heimdall_wait_for_download_available(bin_path: Path) -> bool: """Use heimdall detect to wait for download mode to become available on the device.""" logger.info("Wait for download mode to become available.") diff --git a/openandroidinstaller/utils.py b/openandroidinstaller/utils.py index 0c17baf5..a8511611 100644 --- a/openandroidinstaller/utils.py +++ b/openandroidinstaller/utils.py @@ -41,7 +41,15 @@ def get_download_link(devicecode: str) -> Optional[str]: def image_works_with_device(supported_device_codes: List[str], image_path: str) -> bool: - """Determine if an image works for the given device.""" + """Determine if an image works for the given device. + + Args: + supported_device_codes: List of supported device codes from the config file. + image_path: Path to the image file. + + Returns: + True if the image works with the device, False otherwise. + """ with zipfile.ZipFile(image_path) as image_zip: with image_zip.open( "META-INF/com/android/metadata", mode="r" @@ -60,13 +68,41 @@ def image_works_with_device(supported_device_codes: List[str], image_path: str) return False -def recovery_works_with_device(device_code: str, recovery_path: str) -> bool: +def image_sdk_level(image_path: str) -> int: + """Determine Android version of the selected image. + + Example: + Android 13: 33 + """ + with zipfile.ZipFile(image_path) as image_zip: + with image_zip.open( + "META-INF/com/android/metadata", mode="r" + ) as image_metadata: + metadata = image_metadata.readlines() + for line in metadata: + if b"sdk-level" in line: + return int(line[line.find(b"=") + 1 : -1].decode("utf-8")) + return 0 + + +def recovery_works_with_device( + supported_device_codes: List[str], recovery_path: str +) -> bool: """Determine if a recovery works for the given device. BEWARE: THE RECOVERY PART IS STILL VERY BASIC! + + Args: + supported_device_codes: List of supported device codes from the config file. + recovery_path: Path to the recovery file. + + Returns: + True if the recovery works with the device, False otherwise. """ recovery_file_name = recovery_path.split("/")[-1] - if (device_code in recovery_file_name) and ("twrp" in recovery_file_name): + if any(code in recovery_file_name for code in supported_device_codes) and ( + "twrp" in recovery_file_name + ): logger.success("Device supported by the selected recovery.") return True else: diff --git a/openandroidinstaller/views/base.py b/openandroidinstaller/views/base.py index f32b9d31..e40dd31b 100644 --- a/openandroidinstaller/views/base.py +++ b/openandroidinstaller/views/base.py @@ -34,7 +34,7 @@ def __init__(self, state: AppState, image: str = "placeholder.png"): # right part of the display, add content here. self.right_view_header = Column(width=self.column_width, height=120, spacing=30) self.right_view = Column( - alignment="center", width=self.column_width, height=650, scroll="auto" + alignment="center", width=self.column_width, height=650, scroll="adaptive" ) # left part of the display: used for displaying the images self.left_view = Column( diff --git a/openandroidinstaller/views/install_addons_view.py b/openandroidinstaller/views/install_addons_view.py index ab8068f9..bdc54840 100644 --- a/openandroidinstaller/views/install_addons_view.py +++ b/openandroidinstaller/views/install_addons_view.py @@ -203,6 +203,8 @@ def run_install_addons(self, e): self.error_text.value = "Installation failed! Try again or make sure everything is setup correctly." else: sleep(4) # wait to make sure everything is fine + self.progress_indicator.set_progress_bar(100) + self.progress_indicator.update() logger.success("Installation process was successful. Allow to continue.") # enable the confirm button and disable the call button self.confirm_button.disabled = False diff --git a/openandroidinstaller/views/install_view.py b/openandroidinstaller/views/install_view.py index de6c3858..6e8c7b4d 100644 --- a/openandroidinstaller/views/install_view.py +++ b/openandroidinstaller/views/install_view.py @@ -54,7 +54,7 @@ def __init__( def build(self): """Create the content of the view.""" # error text - self.error_text = Text("", color=colors.RED) + self.error_text = Text("", color=colors.GREEN) # switch to enable advanced output - here it means show terminal input/output in tool def check_advanced_switch(e): @@ -178,7 +178,8 @@ def run_install(self, e): # disable the call button while the command is running self.install_button.disabled = True self.install_addons_switch.disabled = True - self.error_text.value = "" + self.error_text.value = "Please be patient, it may take a few minutes." + self.error_text.color = colors.GREEN # reset the progress indicators self.progress_indicator.clear() # reset terminal output @@ -208,8 +209,11 @@ def run_install(self, e): self.install_button.disabled = False # also remove the last error text if it happened self.error_text.value = "Installation failed! Try again or make sure everything is setup correctly." + self.error_text.color = colors.RED else: sleep(5) # wait to make sure everything is fine + self.progress_indicator.set_progress_bar(100) + self.progress_indicator.update() logger.success("Installation process was successful. Allow to continue.") # enable the confirm button and disable the call button self.confirm_button.disabled = False diff --git a/openandroidinstaller/views/select_view.py b/openandroidinstaller/views/select_view.py index 442fa98b..5c9c116d 100644 --- a/openandroidinstaller/views/select_view.py +++ b/openandroidinstaller/views/select_view.py @@ -30,6 +30,7 @@ AlertDialog, FilePicker, FilePickerResultEvent, + Checkbox, ) from flet_core.buttons import CountinuosRectangleBorder @@ -40,7 +41,12 @@ from views import BaseView from app_state import AppState from widgets import get_title, confirm_button -from utils import get_download_link, image_works_with_device, recovery_works_with_device +from utils import ( + get_download_link, + image_works_with_device, + recovery_works_with_device, + image_sdk_level, +) class SelectFilesView(BaseView): @@ -95,14 +101,36 @@ def init_visuals( # initialize file pickers self.pick_image_dialog = FilePicker(on_result=self.pick_image_result) self.pick_recovery_dialog = FilePicker(on_result=self.pick_recovery_result) + self.pick_dtbo_dialog = FilePicker(on_result=self.pick_dtbo_result) + self.pick_vbmeta_dialog = FilePicker(on_result=self.pick_vbmeta_result) + self.pick_super_empty_dialog = FilePicker( + on_result=self.pick_super_empty_result + ) + self.selected_image = Text("Selected image: ") self.selected_recovery = Text("Selected recovery: ") + self.selected_dtbo = Checkbox( + fill_color=colors.RED, value=None, disabled=True, tristate=True + ) + self.selected_vbmeta = Checkbox( + fill_color=colors.RED, value=None, disabled=True, tristate=True + ) + self.selected_super_empty = Checkbox( + fill_color=colors.RED, value=None, disabled=True, tristate=True + ) # initialize and manage button state. self.confirm_button = confirm_button(self.on_confirm) self.confirm_button.disabled = True + self.continue_eitherway_button = confirm_button( + self.on_confirm, "Continue without additional images" + ) + self.continue_eitherway_button.disabled = True self.pick_recovery_dialog.on_result = self.enable_button_if_ready self.pick_image_dialog.on_result = self.enable_button_if_ready + self.pick_dtbo_dialog.on_result = self.enable_button_if_ready + self.pick_vbmeta_dialog.on_result = self.enable_button_if_ready + self.pick_super_empty_dialog.on_result = self.enable_button_if_ready # back button self.back_button = ElevatedButton( "Back", @@ -120,11 +148,18 @@ def build(self): ) # attach hidden dialogues - self.right_view.controls.append(self.pick_image_dialog) - self.right_view.controls.append(self.pick_recovery_dialog) + self.right_view.controls.extend( + [ + self.pick_image_dialog, + self.pick_recovery_dialog, + self.pick_dtbo_dialog, + self.pick_vbmeta_dialog, + self.pick_super_empty_dialog, + ] + ) - # create help/info button to show the help dialog - info_button = OutlinedButton( + # create help/info button to show the help dialog for the image and recovery selection + explain_images_button = OutlinedButton( "What is this?", on_click=self.open_explain_images_dlg, expand=True, @@ -137,13 +172,31 @@ def build(self): self.right_view_header.controls.append( get_title( "Now pick an OS image and a recovery file:", - info_button=info_button, + info_button=explain_images_button, step_indicator_img="steps-header-select.png", ) ) # text row to show infos during the process self.info_field = Row() + # column to insert the additional image selection controls if needed + self.additional_image_selection = Column() + + # Device specific notes + notes = self.get_notes() + if notes: + self.right_view.controls.extend( + [ + Text( + "Important notes for your device", + style="titleSmall", + color=colors.RED, + weight="bold", + ), + Markdown(notes), + ] + ) + # if there is an available download, show the button to the page if self.download_link: twrp_download_link = f"https://dl.twrp.me/{self.state.config.twrp_link if self.state.config.twrp_link else self.state.config.device_code}" @@ -202,36 +255,219 @@ def build(self): ), self.selected_image, Divider(), - Text("Select a TWRP recovery image:", style="titleSmall"), - Markdown( - f""" + ] + ) + if self.state.flash_recovery: + self.right_view.controls.extend( + [ + Text("Select a TWRP recovery image:", style="titleSmall"), + Markdown( + f""" The recovery image should look something like `twrp-3.7.0_12-0-{self.state.config.device_code}.img`. **Note:** This tool **only supports TWRP recoveries**.""", - extension_set="gitHubFlavored", - ), - Row( - [ - FilledButton( - "Pick TWRP recovery file", - icon=icons.UPLOAD_FILE, - on_click=lambda _: self.pick_recovery_dialog.pick_files( - allow_multiple=False, - file_type="custom", - allowed_extensions=["img"], + extension_set="gitHubFlavored", + ), + Row( + [ + FilledButton( + "Pick TWRP recovery file", + icon=icons.UPLOAD_FILE, + on_click=lambda _: self.pick_recovery_dialog.pick_files( + allow_multiple=False, + file_type="custom", + allowed_extensions=["img"], + ), + expand=True, ), - expand=True, - ), - ] - ), - self.selected_recovery, - Divider(), + ] + ), + self.selected_recovery, + Divider(), + self.additional_image_selection, + ] + ) + + # attach the bottom buttons + if self.state.config.additional_steps: + bottom_buttons = [ + self.back_button, + self.continue_eitherway_button, + self.confirm_button, + ] + + else: + bottom_buttons = [self.back_button, self.confirm_button] + self.right_view.controls.extend( + [ self.info_field, - Row([self.back_button, self.confirm_button]), + Row(bottom_buttons), ] ) return self.view + def get_notes(self) -> str: + """Prepare and get notes for the specific device from config. + + These notes should be displayed to the user. + """ + notes = [] + + brand = self.state.config.metadata.get("brand", "") + if brand in ["xiaomi", "poco"]: + notes.append( + "- If something goes wrong, you can reinstall MiUI here:\n\n" + ) + + # this should be used as little as possible! + if self.state.config.metadata.get("untested", False): + notes.append( + "- **This device has not been tested with OpenAndroidInstaller yet.** The installation can go wrong. You may have to finish the installation process with command line. If you test, please report the result on GitHub." + ) + + notes.extend( + f"- {note}" for note in self.state.config.metadata.get("notes", []) + ) + return "\n\n".join(notes) + + def toggle_additional_image_selection(self): + """Toggle the visibility of the additional image selection controls.""" + # dialogue box to explain additional required images + self.dlg_explain_additional_images = AlertDialog( + modal=True, + title=Text("Why do I need additional images and where do I get them?"), + content=Markdown( + f"""## About additional images +Some devices require additional images to be flashed before the recovery and OS image can be flashed. +Not all images explained below are required for all devices. The installer will tell you which images are required for your device. + +### dtbo.img +The `dtbo.img` is a partition image that contains the device tree overlay. + +### vbmeta.img +The `vbmeta.img` is a partition image that contains the verified boot metadata. +This is required to prevent issues with the verified boot process. + +### super_empty.img +The `super_empty.img` is used to wipe the super partition. This is required to +prevent issues with the super partition when flashing a new ROM. + +### vendor_boot.img +The `vendor_boot.img` is a partition image that contains the vendor boot image. + +## Where do I get these images? +You can download the required images for your device from the [LineageOS downloads page](https://download.lineageos.org/devices/{self.state.config.device_code}/builds). +If this download page does not contain the required images, you can try to find them on the [XDA developers forum](https://forum.xda-developers.com/). + """, + auto_follow_links=True, + ), + actions=[ + TextButton( + "Close", on_click=self.close_close_explain_additional_images_dlg + ), + ], + actions_alignment="end", + shape=CountinuosRectangleBorder(radius=0), + ) + + # create help/info button to show the help dialog for the image and recovery selection + explain_additional_images_button = OutlinedButton( + "Why do I need this and where do I get it?", + on_click=self.open_explain_additional_images_dlg, + expand=True, + icon=icons.HELP_OUTLINE_OUTLINED, + icon_color=colors.DEEP_ORANGE_500, + tooltip="Get more details on additional images and download links.", + ) + + # attach the controls for uploading others partitions, like dtbo, vbmeta & super_empty + additional_image_selection = [] + if self.state.config.additional_steps: + additional_image_selection.extend( + [ + Row( + [ + Text( + "Select required additional images:", style="titleSmall" + ), + explain_additional_images_button, + ] + ), + Markdown( + """ +Your selected device and ROM requires flashing of additional partitions. Please select the required images below. + +Make sure the file is for **your exact phone model!**""", + ), + ] + ) + if "dtbo" in self.state.config.additional_steps: + self.selected_dtbo.value = False + additional_image_selection.extend( + [ + Row( + [ + FilledButton( + "Pick `dtbo.img` image", + icon=icons.UPLOAD_FILE, + on_click=lambda _: self.pick_dtbo_dialog.pick_files( + allow_multiple=False, + file_type="custom", + allowed_extensions=["img"], + ), + expand=True, + ), + self.selected_dtbo, + ] + ), + ] + ) + if "vbmeta" in self.state.config.additional_steps: + self.selected_vbmeta.value = False + additional_image_selection.extend( + [ + Row( + [ + FilledButton( + "Pick `vbmeta.img` image", + icon=icons.UPLOAD_FILE, + on_click=lambda _: self.pick_vbmeta_dialog.pick_files( + allow_multiple=False, + file_type="custom", + allowed_extensions=["img"], + ), + expand=True, + ), + self.selected_vbmeta, + ] + ), + ] + ) + if "super_empty" in self.state.config.additional_steps: + self.selected_super_empty.value = False + additional_image_selection.extend( + [ + Row( + [ + FilledButton( + "Pick `super_empty.img` image", + icon=icons.UPLOAD_FILE, + on_click=lambda _: self.pick_super_empty_dialog.pick_files( + allow_multiple=False, + file_type="custom", + allowed_extensions=["img"], + ), + expand=True, + ), + self.selected_super_empty, + ] + ), + Divider(), + ] + ) + self.additional_image_selection.controls = additional_image_selection + self.additional_image_selection.update() + def open_explain_images_dlg(self, e): """Open the dialog to explain OS and recovery image.""" self.page.dialog = self.dlg_explain_images @@ -243,6 +479,17 @@ def close_close_explain_images_dlg(self, e): self.dlg_explain_images.open = False self.page.update() + def open_explain_additional_images_dlg(self, e): + """Open the dialog to explain additional images.""" + self.page.dialog = self.dlg_explain_additional_images + self.dlg_explain_additional_images.open = True + self.page.update() + + def close_close_explain_additional_images_dlg(self, e): + """Close the dialog to explain additional images.""" + self.dlg_explain_additional_images.open = False + self.page.update() + def pick_image_result(self, e: FilePickerResultEvent): path = ", ".join(map(lambda f: f.name, e.files)) if e.files else "Cancelled!" # update the textfield with the name of the file @@ -264,6 +511,16 @@ def pick_image_result(self, e: FilePickerResultEvent): self.selected_image.color = colors.GREEN else: self.selected_image.color = colors.RED + # if the image works and the sdk level is 33 or higher, show the additional image selection + if self.state.flash_recovery: + if ( + self.selected_image.color == colors.GREEN + and image_sdk_level(self.state.image_path) >= 33 + ): + self.toggle_additional_image_selection() + else: + self.additional_image_selection.controls = [] + self.additional_image_selection.update() # update self.selected_image.update() @@ -281,9 +538,9 @@ def pick_recovery_result(self, e: FilePickerResultEvent): logger.info("No image selected.") # check if the recovery works with the device and show the filename in different colors accordingly if e.files: - device_code = self.state.config.device_code if recovery_works_with_device( - device_code=device_code, recovery_path=self.state.recovery_path + supported_device_codes=self.state.config.supported_device_codes, + recovery_path=self.state.recovery_path, ): self.selected_recovery.color = colors.GREEN else: @@ -291,19 +548,71 @@ def pick_recovery_result(self, e: FilePickerResultEvent): # update self.selected_recovery.update() + def pick_dtbo_result(self, e: FilePickerResultEvent): + path = ", ".join(map(lambda f: f.name, e.files)) if e.files else "Cancelled!" + if e.files: + # check if the dtbo works with the device and show the filename in different colors accordingly + if path == "dtbo.img": + self.selected_dtbo.fill_color = colors.GREEN + self.selected_dtbo.value = True + self.state.dtbo_path = e.files[0].path + logger.info(f"Selected dtbo from {self.state.dtbo_path}") + else: + self.selected_dtbo.fill_color = colors.RED + self.selected_dtbo.value = False + else: + logger.info("No image selected.") + # update + self.selected_dtbo.update() + + def pick_vbmeta_result(self, e: FilePickerResultEvent): + path = ", ".join(map(lambda f: f.name, e.files)) if e.files else "Cancelled!" + if e.files: + # check if the vbmeta works with the device and show the filename in different colors accordingly + if path == "vbmeta.img": + self.selected_vbmeta.fill_color = colors.GREEN + self.selected_vbmeta.value = True + self.state.vbmeta_path = e.files[0].path + logger.info(f"Selected vbmeta from {self.state.vbmeta_path}") + else: + self.selected_vbmeta.fill_color = colors.RED + self.selected_vbmeta.value = False + else: + logger.info("No image selected.") + # update + self.selected_vbmeta.update() + + def pick_super_empty_result(self, e: FilePickerResultEvent): + path = ", ".join(map(lambda f: f.name, e.files)) if e.files else "Cancelled!" + # update the textfield with the name of the file + if e.files: + # check if the super_empty works with the device and show the filename in different colors accordingly + if path == "super_empty.img": + self.selected_super_empty.fill_color = colors.GREEN + self.selected_super_empty.value = True + self.state.super_empty_path = e.files[0].path + logger.info(f"Selected super_empty from {self.state.super_empty_path}") + else: + self.selected_super_empty.fill_color = colors.RED + self.selected_super_empty.value = False + else: + logger.info("No image selected.") + # update + self.selected_super_empty.update() + def enable_button_if_ready(self, e): """Enable the confirm button if both files have been selected.""" if (".zip" in self.selected_image.value) and ( ".img" in self.selected_recovery.value ): - device_code = self.state.config.device_code if not ( image_works_with_device( supported_device_codes=self.state.config.supported_device_codes, image_path=self.state.image_path, ) and recovery_works_with_device( - device_code=device_code, recovery_path=self.state.recovery_path + supported_device_codes=self.state.config.supported_device_codes, + recovery_path=self.state.recovery_path, ) ): # if image and recovery work for device allow to move on, otherwise display message @@ -318,11 +627,70 @@ def enable_button_if_ready(self, e): ) ] self.confirm_button.disabled = True + self.continue_eitherway_button.disabled = True self.right_view.update() return + + self.continue_eitherway_button.disabled = False + + # check if the additional images are there + if self.state.config.additional_steps and not all( + [ + self.selected_dtbo.value + or "dtbo" not in self.state.config.additional_steps, + self.selected_vbmeta.value + or "vbmeta" not in self.state.config.additional_steps, + self.selected_super_empty.value + or "super_empty" not in self.state.config.additional_steps, + ] + ): + logger.error( + "Some additional images don't match or are missing. Please select different ones." + ) + self.info_field.controls = [ + Text( + "Some additional images don't match or are missing. Please select the right ones.", + color=colors.RED, + weight="bold", + ) + ] + self.confirm_button.disabled = True + self.right_view.update() + return + logger.info("Image and recovery work with the device. You can continue.") self.info_field.controls = [] self.confirm_button.disabled = False + self.continue_eitherway_button.disabled = True + self.right_view.update() + elif (".zip" in self.selected_image.value) and (not self.state.flash_recovery): + if not ( + image_works_with_device( + supported_device_codes=self.state.config.supported_device_codes, + image_path=self.state.image_path, + ) + ): + # if image works for device allow to move on, otherwise display message + logger.error( + "Image doesn't work with the device. Please select a different one." + ) + self.info_field.controls = [ + Text( + "Image doesn't work with the device.", + color=colors.RED, + weight="bold", + ) + ] + self.confirm_button.disabled = True + self.continue_eitherway_button.disabled = True + self.right_view.update() + return + + logger.info("Image works with the device. You can continue.") + self.info_field.controls = [] + self.confirm_button.disabled = False + self.continue_eitherway_button.disabled = True self.right_view.update() else: self.confirm_button.disabled = True + # self.continue_eitherway_button.disabled = True diff --git a/openandroidinstaller/views/start_view.py b/openandroidinstaller/views/start_view.py index ccac31f9..f7333429 100644 --- a/openandroidinstaller/views/start_view.py +++ b/openandroidinstaller/views/start_view.py @@ -13,7 +13,6 @@ # If not, see .""" # Author: Tobias Sterbak -import copy import webbrowser from loguru import logger from typing import Callable @@ -99,16 +98,7 @@ def init_visuals( # toggleswitch to allow skipping unlocking the bootloader def check_bootloader_unlocked(e): """Enable skipping unlocking the bootloader if selected.""" - if self.bootloader_switch.value: - logger.info("Skipping bootloader unlocking.") - self.state.steps = copy.deepcopy(self.state.config.boot_recovery) - self.state.num_total_steps = len(self.state.steps) - else: - logger.info("Enabled unlocking the bootloader again.") - self.state.steps = copy.deepcopy( - self.state.config.unlock_bootloader - ) + copy.deepcopy(self.state.config.boot_recovery) - self.state.num_total_steps = len(self.state.steps) + self.state.toggle_flash_unlock_bootloader() self.bootloader_switch = Switch( label="Bootloader is already unlocked.", @@ -118,6 +108,19 @@ def check_bootloader_unlocked(e): active_color=colors.GREEN, ) + # toggleswitch to allow skipping flashing recovery + def check_recovery_already_flashed(e): + """Enable skipping flashing recovery if selected.""" + self.state.toggle_flash_recovery() + + self.recovery_switch = Switch( + label="Custom recovery is already flashed.", + on_change=check_recovery_already_flashed, + disabled=True, + inactive_thumb_color=colors.YELLOW, + active_color=colors.GREEN, + ) + # inform the user about the device detection self.device_name = Text("", weight="bold") self.device_detection_infobox = Row( @@ -179,12 +182,10 @@ def build(self): Divider(), Markdown( """ -If you **already unlocked the bootloader** of your device, please toggle the switch below, to skip the procedure. +If you **already unlocked the bootloader** of your device or already **flashed a custom recovery**, please toggle the respective switch below, to skip the procedure. If you don't know what this means, you most likely don't need to do anything and you can just continue. """ ), - Row([self.bootloader_switch]), - Divider(), self.device_infobox, Row( [ @@ -200,6 +201,8 @@ def build(self): ], alignment="center", ), + Divider(), + Row([self.bootloader_switch, self.recovery_switch]), ] ) return self.view @@ -255,6 +258,7 @@ def search_devices_clicked(self, e): if device_name: self.continue_button.disabled = False self.bootloader_switch.disabled = False + self.recovery_switch.disabled = False # overwrite the text field with the real name from the config self.device_name.value = ( f"{device_name} (code: {self.state.config.device_code})" @@ -272,7 +276,7 @@ def search_devices_clicked(self, e): f"Device with code '{device_code}' is not supported yet." ) # add request support for device button - request_url = f"https://github.com/openandroidinstaller-dev/openandroidinstaller/issues/new?assignees=&labels=device&projects=&template=device-support-request.md&title=Add support for {device_code}" + request_url = f"https://github.com/openandroidinstaller-dev/openandroidinstaller/issues/new?labels=device&template=device-support-request.yaml&title=Add support for `{device_code}`" self.device_request_row.controls.append( ElevatedButton( "Request support for this device", diff --git a/openandroidinstaller/views/step_view.py b/openandroidinstaller/views/step_view.py index 1e4dffbf..3fbe2af3 100644 --- a/openandroidinstaller/views/step_view.py +++ b/openandroidinstaller/views/step_view.py @@ -41,13 +41,18 @@ adb_reboot, adb_reboot_bootloader, adb_reboot_download, + adb_reboot_recovery, adb_sideload, adb_twrp_copy_partitions, fastboot_boot_recovery, fastboot_flash_boot, + fastboot_flash_recovery, + fastboot_reboot_recovery, + fastboot_flash_additional_partitions, fastboot_oem_unlock, fastboot_reboot, fastboot_unlock, + fastboot_unlock_critical, fastboot_unlock_with_code, fastboot_get_unlock_data, heimdall_flash_recovery, @@ -212,11 +217,13 @@ def call_to_phone(self, e, command: str): "adb_reboot": adb_reboot, "adb_reboot_bootloader": adb_reboot_bootloader, "adb_reboot_download": adb_reboot_download, + "adb_reboot_recovery": adb_reboot_recovery, "adb_sideload": partial(adb_sideload, target=self.state.image_path), "adb_twrp_copy_partitions": partial( adb_twrp_copy_partitions, config_path=self.state.config_path ), "fastboot_unlock": fastboot_unlock, + "fastboot_unlock_critical": fastboot_unlock_critical, "fastboot_unlock_with_code": partial( fastboot_unlock_with_code, unlock_code=self.inputtext.value ), @@ -231,6 +238,19 @@ def call_to_phone(self, e, command: str): fastboot_flash_boot, recovery=self.state.recovery_path, ), + "fastboot_flash_recovery": partial( + fastboot_flash_recovery, + recovery=self.state.recovery_path, + is_ab=self.state.config.is_ab, + ), + "fastboot_reboot_recovery": fastboot_reboot_recovery, + "fastboot_flash_additional_partitions": partial( + fastboot_flash_additional_partitions, + dtbo=self.state.dtbo_path, + vbmeta=self.state.vbmeta_path, + super_empty=self.state.super_empty_path, + is_ab=self.state.config.is_ab, + ), "fastboot_reboot": fastboot_reboot, "heimdall_flash_recovery": partial( heimdall_flash_recovery, recovery=self.state.recovery_path diff --git a/openandroidinstaller/widgets.py b/openandroidinstaller/widgets.py index 98b8b147..e4400c5a 100644 --- a/openandroidinstaller/widgets.py +++ b/openandroidinstaller/widgets.py @@ -114,6 +114,20 @@ def display_progress_bar(self, line: str): """Display and update the progress bar for the given line.""" percentage_done = None result = None + # create the progress bar + if self.progress_bar == None: + self.progress_bar = ProgressBar( + value=1 / 100, + width=500, + bar_height=32, + color="#00d886", + bgcolor="#eeeeee", + ) + # text to display the percentage + self.percentage_text = Text("1%") + self._container.content.controls.append( + Row([self.percentage_text, self.progress_bar]) + ) # get the progress numbers from the output lines if (type(line) == str) and line.strip(): result = re.search( @@ -122,23 +136,29 @@ def display_progress_bar(self, line: str): ) if result: if result.group(2): - percentage_done = 100 + percentage_done = 99 elif result.group(1): percentage_done = int(result.group(1)) + if percentage_done == 0: + percentage_done = 1 + elif percentage_done == 100: + percentage_done = 99 - # create the progress bar on first occurrence - if percentage_done == 0: - self.progress_bar = ProgressBar( - width=500, bar_height=32, color="#00d886", bgcolor="#eeeeee" - ) - self.percentage_text = Text(f"{percentage_done}%") - self._container.content.controls.append( - Row([self.percentage_text, self.progress_bar]) - ) # update the progress bar - if self.progress_bar: - self.progress_bar.value = percentage_done / 100 - self.percentage_text.value = f"{percentage_done}%" + self.set_progress_bar(percentage_done) + + def set_progress_bar(self, percentage_done: int): + """Set the progress bar to the given percentage. + + Args: + percentage_done (int): Percentage of the progress bar to be filled. + """ + assert ( + percentage_done >= 0 and percentage_done <= 100 + ), "Percentage must be between 0 and 100" + if self.progress_bar: + self.progress_bar.value = percentage_done / 100 + self.percentage_text.value = f"{percentage_done}%" def display_progress_ring( self, diff --git a/poetry.lock b/poetry.lock index 63bc8e14..143175c4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -903,7 +903,7 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] lock-version = "1.1" python-versions = "<3.11,>=3.9" -content-hash = "f5462dcfd8695f093ffdc7e70d7a90909ab0982f96c3de1564b831223221faeb" +content-hash = "5eb8a128bbc3eb03bb8dd70b45c9e546d7ef88c16b9b562e9c769d1ccc7c0f52" [metadata.files] altgraph = [ diff --git a/pyproject.toml b/pyproject.toml index 61b0fd15..9e20594a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,7 @@ pytest-mock = "^3.10.0" bandit = "^1.7.4" pytest-subprocess = "^1.5.0" mypy = "^1.0.0" +typing-extensions = "^4.7.1" [tool.poetry.dev-dependencies] diff --git a/tests/test_progress_bar.py b/tests/test_progress_bar.py index 5b1b1fc8..31700450 100644 --- a/tests/test_progress_bar.py +++ b/tests/test_progress_bar.py @@ -30,20 +30,24 @@ def test_init(): def test_update_progress_bar(): """Test if the progress bar is updated properly based on lines.""" progress_indicator = ProgressIndicator(expand=True) - build_indicator = progress_indicator.build() + progress_indicator.build() # test if other line is fine progress_indicator.display_progress_bar( line="Failed to mount '/data' (Device or resource busy)" ) - assert not progress_indicator.progress_bar + assert progress_indicator.progress_bar # test if percentages are parsed correctly and update is performed - for percentage in range(0, 47): + for percentage in range(1, 47): line = f"serving: '/home/tobias/Repositories/openandroidinstaller/images/google-pixel3a/lineage-19.1-20221004-nightly-sargo-signed.zip' (~{percentage}%)\n" progress_indicator.display_progress_bar(line) assert progress_indicator.progress_bar.value == percentage / 100 # test if the finishing print is detected and updated correctly. progress_indicator.display_progress_bar(line="Total xfer: 1.00x\n") + assert progress_indicator.progress_bar.value == 0.99 + + # test if the final set_progress_bar is working correctly + progress_indicator.set_progress_bar(100) assert progress_indicator.progress_bar.value == 1.0