diff --git a/Main.py b/Main.py index e4480ef..66cdbf5 100644 --- a/Main.py +++ b/Main.py @@ -318,6 +318,11 @@ def download_completed(destination_path): download_thread = threading.Thread(target=download_file, args=(url, destination_path), kwargs={"callback": lambda: download_completed(destination_path)}) download_thread.start() + def on_refresh_google_images(self, event): + self.parent.config.google_images_last_checked = False + # Refresh the Google Images menu + self.parent.update_google_images_menu() + # ============================================================================ # Class GoogleImagesMenu # ============================================================================ @@ -402,6 +407,9 @@ def __init__(self, parent): phone_menu_item.SetBitmap(phone_icon) watches_menu_item = self.AppendSubMenu(self.watches_menu, "Watches") watches_menu_item.SetBitmap(watch_icon) + # self.AppendSeparator() + # refresh_images_menu_item = self.Append(wx.ID_ANY, "Refresh images list") + # self.Bind(wx.EVT_MENU, self.on_refresh_google_images, refresh_images_menu_item) if download_available: self.parent.toast("Updates are available", f"There are updates available for your device.\nCheck Google Images menu.") @@ -686,6 +694,8 @@ def initialize(self): self.temporary_root_checkBox.SetValue(self.config.temporary_root) self.no_reboot_checkBox.SetValue(self.config.no_reboot) self.wipe_checkBox.SetValue(self.wipe) + self.no_wipe_downgrade_checkbox.SetValue(False) + self.no_wipe_downgrade_checkbox.Enable(False) # get the image choice and update UI set_image_mode(self.image_choice.Items[self.image_choice.GetSelection()]) @@ -1172,10 +1182,11 @@ def _build_menu_bar(self): # seperator file_menu.AppendSeparator() # Exit Menu - wx.App.SetMacExitMenuItemId(wx.ID_EXIT) exit_item = file_menu.Append(wx.ID_ANY, "E&xit\tCtrl-Q", "Exit PixelFlasher") exit_item.SetBitmap(images.exit_24.GetBitmap()) self.Bind(wx.EVT_MENU, self._on_exit_app, exit_item) + # Set the ID of the "Exit" menu item on macOS + wx.App.SetMacExitMenuItemId(exit_item.GetId()) # Device Menu Items # ---------------- @@ -1996,6 +2007,7 @@ def _advanced_options_hide(self, value): self.fastboot_verbose_checkBox.Hide() self.temporary_root_checkBox.Hide() self.wipe_checkBox.Hide() + self.no_wipe_downgrade_checkbox.Hide() # ROM options self.custom_rom_checkbox.Hide() self.custom_rom.Hide() @@ -2028,6 +2040,7 @@ def _advanced_options_hide(self, value): self.fastboot_verbose_checkBox.Show() self.temporary_root_checkBox.Show() self.wipe_checkBox.Show() + self.no_wipe_downgrade_checkbox.Show() # ROM options self.custom_rom_checkbox.Show() self.custom_rom.Show() @@ -2516,9 +2529,20 @@ def evaluate_condition(self, condition): return True return False + elif condition == 'is_gki': + device = get_phone() + if device and device.is_gki: + return True + return False + + else: + print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Unknown condition: {condition}") + return False + except Exception as e: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while evaluating a rule") traceback.print_exc() + return False #----------------------------------------------------------------------------- # update_widget_states @@ -2579,11 +2603,12 @@ def update_widget_states(self): self.flash_to_inactive_slot_checkBox: ['device_attached', 'mode_is_not_ota', 'dual_slot'], self.fastboot_force_checkBox: ['device_attached', 'mode_is_not_ota', 'dual_slot'], self.wipe_checkBox: ['device_attached', 'custom_flash'], + # self.no_wipe_downgrade_checkbox: ['device_attached'], self.temporary_root_checkBox: ['not_custom_flash', 'boot_is_patched', 'boot_is_selected'], self.patch_button: ['device_attached', 'device_mode_adb'], self.patch_magisk_button: ['device_attached', 'device_mode_adb', 'boot_is_selected', 'boot_is_not_patched'], - self.patch_kernelsu_button: ['device_attached', 'device_mode_adb', 'boot_is_selected', 'boot_is_not_patched'], - self.patch_kernelsu_lkm_button: ['device_attached', 'device_mode_adb', 'boot_is_selected', 'boot_is_not_patched', 'boot_is_init_boot'], + self.patch_kernelsu_button: ['device_attached', 'device_mode_adb', 'boot_is_selected', 'boot_is_not_patched', 'is_gki'], + self.patch_kernelsu_lkm_button: ['device_attached', 'device_mode_adb', 'boot_is_selected', 'boot_is_not_patched', 'is_gki'], self.patch_apatch_button: ['device_attached', 'device_mode_adb', 'boot_is_selected', 'boot_is_not_patched'], # Special handling of non-singular widgets 'mode_radio_button.OTA': ['firmware_selected', 'firmware_is_ota'], @@ -2864,6 +2889,7 @@ def _on_mode_changed(self, event): self.mode_radio_button = event.GetEventObject() self.wipe = False self.wipe_checkBox.SetValue(False) + self.no_wipe_downgrade_checkbox.SetValue(False) if self.mode_radio_button.GetValue(): self.config.flash_mode = self.mode_radio_button.mode print(f"Flash mode changed to: {self.config.flash_mode}") @@ -3005,6 +3031,17 @@ def _on_wipe(self, event): puml(f"note right:Wipe {status}\n") self.wipe = status + # ----------------------------------------------- + # _on_no_wipe_downgrade + # ----------------------------------------------- + def _on_no_wipe_downgrade(self, event): + self._on_no_wipe_downgrade_checkbox = event.GetEventObject() + status = self._on_no_wipe_downgrade_checkbox.GetValue() + print(f"Flash Option: No Wipe Downgrade {status}") + puml(":Flash Option change;\n", True) + puml(f"note right:No Wipe Downgrade{status}\n") + self.wipe = status + # ----------------------------------------------- # _on_verbose # ----------------------------------------------- @@ -3177,6 +3214,7 @@ def _on_reboot_bootloader(self, event): res = device.reboot_bootloader(fastboot_included = True) if res == -1: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while rebooting to bootloader") + bootloader_issue_message() except Exception as e: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while rebooting to bootloader") traceback.print_exc() @@ -3968,6 +4006,7 @@ def _on_live_boot(self, event): print("==============================================================================") self._on_spin('start') live_flash_boot_phone(self, 'Live') + self.update_widget_states() except Exception as e: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while live booting") traceback.print_exc() @@ -3983,6 +4022,7 @@ def _on_flash_boot(self, event): print("==============================================================================") self._on_spin('start') live_flash_boot_phone(self, 'Flash') + self.update_widget_states() except Exception as e: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while flashing boot") traceback.print_exc() @@ -4044,6 +4084,7 @@ def _on_magisk_patch_boot(self, event): print("==============================================================================") self._on_spin('start') patch_boot_img(self, 'Magisk') + self.update_widget_states() except Exception as e: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered while patching with Magisk") traceback.print_exc() @@ -4059,6 +4100,7 @@ def _on_kernelsu_patch_boot(self, event): print("==============================================================================") self._on_spin('start') patch_boot_img(self, 'KernelSU') + self.update_widget_states() except Exception as e: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while patching with KernelSU") traceback.print_exc() @@ -4074,13 +4116,14 @@ def _on_kernelsu_lkm_patch_boot(self, event): print("==============================================================================") self._on_spin('start') patch_boot_img(self, 'KernelSU_LKM') + self.update_widget_states() except Exception as e: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while patching KernselSU LKM") traceback.print_exc() self._on_spin('stop') # ----------------------------------------------- - # _on_kernelsu_lkm_patch_boot + # _on_apatch_patch_boot # ----------------------------------------------- def _on_apatch_patch_boot(self, event): try: @@ -4089,6 +4132,7 @@ def _on_apatch_patch_boot(self, event): print("==============================================================================") self._on_spin('start') patch_boot_img(self, 'APatch') + self.update_widget_states() except Exception as e: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while patching with APatch") traceback.print_exc() @@ -4104,6 +4148,7 @@ def _on_patch_custom_boot(self, event): print("==============================================================================") self._on_spin('start') patch_boot_img(self, 'Custom') + self.update_widget_states() except Exception as e: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while patching custom boot") traceback.print_exc() @@ -4464,6 +4509,8 @@ def _add_mode_radio_button(sizer, index, flash_mode, label, tooltip): self.no_reboot_checkBox.SetToolTip(u"Do not reboot after flashing\nThis is useful if you want to perform other actions before reboot.") self.wipe_checkBox = wx.CheckBox(parent=panel, id=wx.ID_ANY, label=u"Wipe", pos=wx.DefaultPosition, size=wx.DefaultSize, style=0) self.wipe_checkBox.SetToolTip(u"This will invoke data wipe operation at the end of custom flashing.\nOne use case would be when disabling verification for the first time.") + self.no_wipe_downgrade_checkbox = wx.CheckBox(parent=panel, id=wx.ID_ANY, label=u"No Wipe Downgrade", pos=wx.DefaultPosition, size=wx.DefaultSize, style=0) + self.no_wipe_downgrade_checkbox.SetToolTip(u"WARNING!!! This is a highly experimental feature.\nThis will attempt to downgrade the device without needing a data wipe.\n") self.advanced_options_sizer = wx.BoxSizer(orient=wx.HORIZONTAL) self.advanced_options_sizer.Add(window=self.flash_to_inactive_slot_checkBox, flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL, border=0) self.advanced_options_sizer.Add(window=self.flash_both_slots_checkBox, proportion=0, flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL, border=5) @@ -4474,6 +4521,7 @@ def _add_mode_radio_button(sizer, index, flash_mode, label, tooltip): self.advanced_options_sizer.Add(window=self.temporary_root_checkBox, proportion=0, flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL, border=5) self.advanced_options_sizer.Add(window=self.no_reboot_checkBox, proportion=0, flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL, border=5) self.advanced_options_sizer.Add(window=self.wipe_checkBox, proportion=0, flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL, border=5) + self.advanced_options_sizer.Add(window=self.no_wipe_downgrade_checkbox, proportion=0, flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL, border=5) # 11th row widgets, Flash button self.flash_button = wx.Button(parent=panel, id=-1, label="Flash Pixel Phone", pos=wx.DefaultPosition, size=wx.Size(-1, 50)) @@ -4564,6 +4612,7 @@ def _add_mode_radio_button(sizer, index, flash_mode, label, tooltip): self.flash_to_inactive_slot_checkBox.Bind(wx.EVT_CHECKBOX, self._on_flash_to_inactive_slot) self.no_reboot_checkBox.Bind(wx.EVT_CHECKBOX, self._on_no_reboot) self.wipe_checkBox.Bind(wx.EVT_CHECKBOX, self._on_wipe) + self.no_wipe_downgrade_checkbox.Bind(wx.EVT_CHECKBOX, self._on_no_wipe_downgrade) self.disable_verity_checkBox.Bind(wx.EVT_CHECKBOX, self._on_disable_verity) self.fastboot_force_checkBox.Bind(wx.EVT_CHECKBOX, self._on_fastboot_force) self.fastboot_verbose_checkBox.Bind(wx.EVT_CHECKBOX, self._on_fastboot_verbose) diff --git a/build-on-mac.spec b/build-on-mac.spec index 7aa83ea..2d4c354 100644 --- a/build-on-mac.spec +++ b/build-on-mac.spec @@ -28,6 +28,6 @@ exe = EXE(pyz, icon='images/icon-dark-256.icns') app = BUNDLE(exe, name='PixelFlasher.app', - version='6.9.0.2', + version='6.9.1.0', icon='./images/icon-dark-256.icns', bundle_identifier='com.badabing.pixelflasher') diff --git a/build.sh b/build.sh index d4fd25b..7bb48f9 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash rm -rf build dist -VERSION=6.9.0.2 +VERSION=6.9.1.0 NAME="PixelFlasher" DIST_NAME="PixelFlasher" diff --git a/constants.py b/constants.py index d02b80e..24bb9ca 100644 --- a/constants.py +++ b/constants.py @@ -2,7 +2,7 @@ APPNAME = 'PixelFlasher' CONFIG_FILE_NAME = 'PixelFlasher.json' -VERSION = '6.9.0.2' +VERSION = '6.9.1.0' SDKVERSION = '33.0.3' MAIN_WIDTH = 1400 MAIN_HEIGHT = 1040 @@ -31,6 +31,7 @@ '-AICP', '-arter97', '-blu_spark', + '-CAF', '-cm-', '-crDroid', '-crdroid', diff --git a/magisk_downloads.py b/magisk_downloads.py index d6d9d68..6cdd575 100644 --- a/magisk_downloads.py +++ b/magisk_downloads.py @@ -71,7 +71,7 @@ def __init__(self, *args, **kwargs): else: self.il = wx.ImageList(16, 16) self.idx1 = self.il.Add(images.official_16.GetBitmap()) - self.list = ListCtrl(self, -1, size=(-1, self.CharHeight * 16), style = wx.LC_REPORT) + self.list = ListCtrl(self, -1, size=(-1, self.CharHeight * 17), style = wx.LC_REPORT) self.list.SetImageList(self.il, wx.IMAGE_LIST_SMALL) device = get_phone() @@ -164,8 +164,8 @@ def __init__(self, *args, **kwargs): a = self.list.GetViewRect() self.SetSize(vSizer.MinSize.Width + 80, vSizer.MinSize.Height + 420) - print("\nOpening Magisk Downloader/Installer ...") - puml(f":Open Magisk Downloader/Installer;\n", True) + print("\nOpening Root App Installer / Downloader ...") + puml(f":Open Root App Installer / Downloader;\n", True) # ----------------------------------------------- diff --git a/modules.py b/modules.py index 1ddddfb..ac5fd2a 100644 --- a/modules.py +++ b/modules.py @@ -481,12 +481,12 @@ def select_firmware(self): if firmware_hash and firmware_hash[:8] in firmware: print(f"Expected to match {firmware_hash[:8]} in the filename and did. This is good!") puml(f"#CDFFC8:Checksum matches portion of the filename {firmware};\n") - self.toast("Firmware SHA256 Match", f"SHA256 of {filename}.{extension} matches the segment in the filename.") + self.toast("Firmware SHA256 Match", f"SHA256 of {filename}{extension} matches the segment in the filename.") set_firmware_hash_validity(True) else: - print(f"WARNING: Expected to match {firmware_hash[:8]} in the {filename}.{extension} but didn't, please double check to make sure the checksum is good.") + print(f"WARNING: Expected to match {firmware_hash[:8]} in the {filename}{extension} but didn't, please double check to make sure the checksum is good.") puml("#orange:Unable to match the checksum in the filename;\n") - self.toast("Firmware SHA256 Mismatch", f"WARNING! SHA256 of {filename}.{extension} does not match segments in the filename.\nPlease double check to make sure the checksum is good.") + self.toast("Firmware SHA256 Mismatch", f"WARNING! SHA256 of {filename}{extension} does not match segments in the filename.\nPlease double check to make sure the checksum is good.") set_firmware_hash_validity(False) firmware = filename.split("-") @@ -1076,6 +1076,40 @@ def process_flash_all_file(filepath): puml("#red:Encountered an error while processing flash_all file;\n") traceback.print_exc() +# ============================================================================ +# Function setup_for_downgrade (TODO) +# ============================================================================ +def setup_for_downgrade(self, target_boot_file_path): + # TODO + # + # Show warnings and disclaimer + # Check if the device is rooted + # current_stock_boot_path = '' + # if the device is rooted extract the boot.img from device + # If stock boot is present, extract it (probably from Magisk backup or from PixelFlasher) + # current_stock_boot_path = + # if current_stock_boot_path = '' + # prompt the user to provide the stock boot.img of the current firmware (with enough warnings) + # + # current_boot_info = avbtool_get_info(current_stock_boot_path) # returns an object with all the details + # target_boot_info = avbtool_get_info(target_boot_file_path) # returns an object with all the details + # Compare the two boot image info objects and do validations to make sure the target is a downgrade and the current matches current OS version + # if all validations pass, proceed + # else show errors and abort + # + # copy the current boot.img to a temp folder + # patch the current boot.img with the target boot.img patch_level + # if successful, proceed to flash the patched boot.img + # if not successful, show errors and abort + return + +# ============================================================================ +# Function avbtool_get_info (TODO) +# ============================================================================ +def avbtool_get_info(self, boot_file_path): + # perform avbtool info on the boot_file_path + # convert to object and return object + return # ============================================================================ # Function drive_magisk (TODO) @@ -1879,7 +1913,7 @@ def patch_kernelsu_lkm_script(): data += "echo \"PATCH_SHA1: $PATCH_SHA1\"\n" data += f"PATCH_FILENAME={patch_name}_${{KSU_VERSION}}_${{STOCK_SHA1}}_${{PATCH_SHA1}}.img\n" data += "echo \"PATCH_FILENAME: $PATCH_FILENAME\"\n" - data += f"cp kernelsu_boot_* {self.config.phone_path}/${{PATCH_FILENAME}}\n" + data += f"if [ -f kernelsu_boot_* ]; then cp kernelsu_boot_* {self.config.phone_path}/${{PATCH_FILENAME}}; elif [ -f kernelsu_patched_* ]; then cp kernelsu_patched_* {self.config.phone_path}/${{PATCH_FILENAME}}; fi\n" data += f"if [[ -s {self.config.phone_path}/${{PATCH_FILENAME}} ]]; then\n" data += " echo $PATCH_FILENAME > /data/local/tmp/pf_patch.log\n" @@ -2152,7 +2186,7 @@ def patch_apatch_script(patch_method="app"): kmi = device.kmi anykernel = False pixel_devices = get_android_devices() - if kmi == '': + if not device.is_kmi: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Incompatible Kernel KMI") print("Aborting ...\n") puml("#red:Incompatible Kernel KMI;\n}\n") @@ -2359,7 +2393,7 @@ def patch_apatch_script(patch_method="app"): if not magiskboot_created: # Find latest Magisk to download - apk = device.get_magisk_apk_details('stable') + apk = device.get_magisk_apk_details('Magisk Stable') filename = f"magisk_{apk.version}_{apk.versionCode}.apk" download_file(apk.link, filename) magisk_apk = os.path.join(tmp_path, filename) @@ -3045,6 +3079,7 @@ def live_flash_boot_phone(self, option): # sourcery skip: de-morgan mode = "fastboot" else: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while rebooting to bootloader") + bootloader_issue_message() done_flashing = False if mode == 'fastboot' and get_fastboot(): @@ -3839,6 +3874,7 @@ def flash_phone(self): print("Aborting ...\n") puml("#red:Encountered an error while rebooting to bootloader;\n}\n") self.toast("Flash action", "Encountered an error while rebooting to bootloader.") + bootloader_issue_message() return -1 # Check for bootloader unlocked if self.config.check_for_bootloader_unlocked and not check_for_unlocked(device_id): @@ -4028,6 +4064,7 @@ def reboot_device_to_bootloader(): print("Aborting ...\n") puml("#red:Encountered an error while rebooting to bootloader;\n}\n") self.toast("Flash action", "Encountered an error while rebooting to bootloader.") + bootloader_issue_message() refresh_and_done() return -1 image_mode = get_image_mode() diff --git a/phone.py b/phone.py index 6ff034c..5a25b7e 100644 --- a/phone.py +++ b/phone.py @@ -7,6 +7,7 @@ import traceback from datetime import datetime from urllib.parse import urlparse +from packaging.version import parse from constants import * from runtime import * @@ -542,6 +543,20 @@ def kmi(self): except Exception: return '' + # ---------------------------------------------------------------------------- + # property is_gki + # ---------------------------------------------------------------------------- + @property + def is_gki(self): + try: + ro_kernel_version = self.get_prop('ro.kernel.version') + if parse(ro_kernel_version) >= parse('5.4'): + return True + else: + return False + except Exception: + return False + # ---------------------------------------------------------------------------- # property magisk_path # ---------------------------------------------------------------------------- @@ -2246,7 +2261,7 @@ def magisk_apks(self): if self._magisk_apks is None: try: apks = [] - mlist = ['Magisk Stable', 'Magisk Beta', 'Magisk Canary', 'Magisk Debug', 'Magisk Alpha', 'Magisk Delta Canary', 'Magisk Delta Debug', "KernelSU", 'APatch', "Magisk special 27001", "Magisk special 26401", 'Magisk special 25203'] + mlist = ['Magisk Stable', 'Magisk Beta', 'Magisk Canary', 'Magisk Debug', 'Magisk Alpha', 'Magisk Delta Canary', 'Magisk Delta Debug', "KernelSU", 'APatch', "Magisk zygote64_32 canary", "Magisk special 27001", "Magisk special 26401", 'Magisk special 25203'] for i in mlist: apk = self.get_magisk_apk_details(i) if apk: @@ -2372,7 +2387,8 @@ def get_magisk_apk_details(self, channel): url = "https://raw.githubusercontent.com/Namelesswonder/magisk-files/main/beta.json" elif channel == 'Magisk zygote64_32 canary': - url = "https://raw.githubusercontent.com/Namelesswonder/magisk-files/main/canary.json" + # url = "https://raw.githubusercontent.com/Namelesswonder/magisk-files/main/canary.json" + url = "https://raw.githubusercontent.com/ActiveIce/Magisk_zygote64_32/master/canary.json" elif channel == 'Magisk zygote64_32 debug': url = "https://raw.githubusercontent.com/Namelesswonder/magisk-files/main/debug.json" @@ -2513,6 +2529,7 @@ def rooted(self): else: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: adb command is not found!") puml("#red:ERROR: adb command is not found;\n", True) + return False return self._rooted # ---------------------------------------------------------------------------- @@ -3094,6 +3111,7 @@ def set_active_slot(self, slot): res = self.reboot_bootloader() if res == -1: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while rebooting to bootloader") + bootloader_issue_message() self.refresh_phone_mode() if self.mode == 'f.b' and get_fastboot(): print(f"Setting active slot to slot [{slot}] for device: {self.id} ...") @@ -3117,6 +3135,7 @@ def switch_slot(self, timeout=60): res = self.reboot_bootloader() if res == -1: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while rebooting to bootloader") + bootloader_issue_message() # self.refresh_phone_mode() update_phones(self.id) if mode == 'fastboot' and get_fastboot(): @@ -3152,6 +3171,7 @@ def erase_partition(self, partition): res = self.reboot_bootloader() if res == -1: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while rebooting to bootloader") + bootloader_issue_message() self.refresh_phone_mode() if self.mode == 'f.b' and get_fastboot(): print(f"Erasing Partition [{partition}] for device: {self.id} ...") @@ -3175,6 +3195,7 @@ def lock_bootloader(self): res = self.reboot_bootloader() if res == -1: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while rebooting to bootloader") + bootloader_issue_message() self.refresh_phone_mode() if self.mode == 'f.b' and get_fastboot(): # add a popup warning before continuing. @@ -3197,6 +3218,7 @@ def unlock_bootloader(self): res = self.reboot_bootloader() if res == -1: print(f"\n❌ {datetime.now():%Y-%m-%d %H:%M:%S} ERROR: Encountered an error while rebooting to bootloader") + bootloader_issue_message() self.refresh_phone_mode() if self.mode == 'f.b' and get_fastboot(): print(f"Unlocking bootloader for device: {self.id} ...") diff --git a/runtime.py b/runtime.py index 90316d3..4214a9f 100644 --- a/runtime.py +++ b/runtime.py @@ -12,6 +12,7 @@ import math import ntpath import os +import platform import re import shutil import signal @@ -2313,7 +2314,7 @@ def process_dict(the_dict, add_missing_keys=False, pif_flavor='', set_first_api= with contextlib.suppress(Exception): module_flavor = pif_flavor.split('_')[0] module_versionCode = int(pif_flavor.split('_')[1]) - if module_flavor == '': + if module_flavor is None or module_flavor == '': module_flavor = 'playintegrityfork' if module_versionCode == 0: module_versionCode = 9999999 @@ -3170,6 +3171,16 @@ def patch_binary_file(file_path, hex_offset, text, output_file_path=None): traceback.print_exc() +# ============================================================================ +# Function bootloader_issue_message +# ============================================================================ +def bootloader_issue_message(): + print("ℹ️ This issue is most likely related to communication between your device and your computer.") + print("Please ensure that you have installed the latest Google USB Drivers in both adb and bootloader (fastboot) modes.") + print("If the problem persists, try using a different USB cable or port.") + print("USB 2.0 ports are reportedly more stable than USB 3.0 ports.\n") + + # ============================================================================ # Function download_ksu_latest_release_asset # ============================================================================ diff --git a/windows-metadata.yaml b/windows-metadata.yaml index beea945..a0f2f1b 100644 --- a/windows-metadata.yaml +++ b/windows-metadata.yaml @@ -1,6 +1,6 @@ # https://github.com/DudeNr33/pyinstaller-versionfile # create-version-file windows-metadata.yaml --outfile windows-version-info.txt -Version: 6.9.0.2 +Version: 6.9.1.0 FileDescription: PixelFlasher InternalName: PixelFlasher OriginalFilename: PixelFlasher.exe diff --git a/windows-version-info.txt b/windows-version-info.txt index 604fd1b..e470a81 100644 --- a/windows-version-info.txt +++ b/windows-version-info.txt @@ -7,8 +7,8 @@ VSVersionInfo( ffi=FixedFileInfo( # filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4) # Set not needed items to zero 0. Must always contain 4 elements. - filevers=(6,9,0,2), - prodvers=(6,9,0,2), + filevers=(6,9,1,0), + prodvers=(6,9,1,0), # Contains a bitmask that specifies the valid bits 'flags'r mask=0x3f, # Contains a bitmask that specifies the Boolean attributes of the file. @@ -32,12 +32,12 @@ VSVersionInfo( u'040904B0', [StringStruct(u'CompanyName', u''), StringStruct(u'FileDescription', u'PixelFlasher'), - StringStruct(u'FileVersion', u'6.9.0.2'), + StringStruct(u'FileVersion', u'6.9.1.0'), StringStruct(u'InternalName', u'PixelFlasher'), StringStruct(u'LegalCopyright', u''), StringStruct(u'OriginalFilename', u'PixelFlasher.exe'), StringStruct(u'ProductName', u'PixelFlasher'), - StringStruct(u'ProductVersion', u'6.9.0.2')]) + StringStruct(u'ProductVersion', u'6.9.1.0')]) ]), VarFileInfo([VarStruct(u'Translation', [1033, 1200])]) ]