mtkclient/mtk_gui

545 lines
25 KiB
Text
Raw Normal View History

2021-12-25 17:01:25 -05:00
#!/usr/bin/env python3
2022-01-01 12:46:52 -05:00
# MTK Flash Client (c) B.Kerler, G.Kreileman 2021.
2021-12-25 17:01:25 -05:00
# Licensed under GPLv3 License
import sys
import time
import mock
2022-01-11 15:18:37 -05:00
import threading
2021-12-25 17:01:25 -05:00
import logging
import ctypes
2022-01-01 12:46:52 -05:00
from functools import partial
from PySide6.QtCore import Qt, QVariantAnimation, Signal, QObject, QSize, QTranslator, QLocale, QLibraryInfo, \
Slot, QCoreApplication
from PySide6.QtGui import QTextOption, QPixmap, QTransform, QIcon
2022-01-01 12:46:52 -05:00
from PySide6.QtWidgets import QMainWindow, QApplication, QWidget, QCheckBox, QVBoxLayout, QHBoxLayout, QLineEdit, \
2023-12-29 13:33:42 -05:00
QPushButton
2021-12-25 17:01:25 -05:00
from mtkclient.Library.mtk_class import Mtk
from mtkclient.Library.DA.mtk_da_handler import DA_handler
2021-12-25 17:01:25 -05:00
from mtkclient.Library.gpt import gpt_settings
from mtkclient.Library.mtk_main import Main, Mtk_Config
from mtkclient.gui.readFlashPartitions import ReadFlashWindow
2021-12-30 14:41:25 -05:00
from mtkclient.gui.writeFlashPartitions import WriteFlashWindow
from mtkclient.gui.eraseFlashPartitions import EraseFlashWindow
2022-01-01 13:25:59 -05:00
from mtkclient.gui.toolsMenu import generateKeysMenu, UnlockMenu
2022-01-01 12:46:52 -05:00
from mtkclient.gui.toolkit import asyncThread, trap_exc_during_debug, convert_size, CheckBox, FDialog, TimeEstim
2021-12-25 17:01:25 -05:00
from mtkclient.config.payloads import pathconfig
from mtkclient.gui.main_gui import Ui_MainWindow
import os
2022-01-01 12:46:52 -05:00
2022-01-11 15:18:37 -05:00
lock = threading.Lock()
2022-01-01 12:46:52 -05:00
os.environ['QT_MAC_WANTS_LAYER'] = '1' # This fixes a bug in pyside2 on MacOS Big Sur
2021-12-25 17:01:25 -05:00
# TO do Move all GUI modifications to signals!
# install exception hook: without this, uncaught exception would cause application to exit
sys.excepthook = trap_exc_during_debug
# Initiate MTK classes
variables = mock.Mock()
variables.cmd = "stage"
variables.debugmode = True
2022-01-01 12:46:52 -05:00
path = pathconfig()
2021-12-25 17:01:25 -05:00
# if sys.platform.startswith('darwin'):
# config.ptype = "kamakiri" #Temp for Mac testing
MtkTool = Main(variables)
guiState = "welcome"
phoneInfo = {"chipset": "", "bootMode": "", "daInit": False, "cdcInit": False}
2022-01-01 12:46:52 -05:00
class DeviceHandler(QObject):
sendToLogSignal = Signal(str)
2022-01-11 08:18:43 -05:00
update_status_text = Signal(str)
2021-12-30 14:41:25 -05:00
sendToProgressSignal = Signal(int)
da_handler = None
def __init__(self, parent, preloader: str = None, loglevel=logging.INFO, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
2022-01-11 08:18:43 -05:00
config = Mtk_Config(loglevel=logging.INFO, gui=self.sendToLogSignal, guiprogress=self.sendToProgressSignal,
update_status_text=self.update_status_text)
config.gpt_settings = gpt_settings(gpt_num_part_entries='0', gpt_part_entry_size='0',
gpt_part_entry_start_lba='0') # This actually sets the right GPT settings..
config.reconnect = True
config.uartloglevel = 2
self.loglevel = logging.DEBUG
2022-01-11 15:18:37 -05:00
self.da_handler = DA_handler(Mtk(config=config, loglevel=logging.INFO), loglevel)
2021-12-25 17:01:25 -05:00
2022-01-01 12:46:52 -05:00
2021-12-25 17:01:25 -05:00
def getDevInfo(self, parameters):
2023-12-29 13:33:42 -05:00
# loglevel = parameters[0]
phoneInfo = parameters[1]
devhandler = parameters[2]
2022-01-11 15:18:37 -05:00
mtkClass = devhandler.da_handler.mtk
da_handler = devhandler.da_handler
try:
2021-12-29 18:17:55 -05:00
if not mtkClass.port.cdc.connect():
mtkClass.preloader.init()
else:
phoneInfo['cdcInit'] = True
2023-12-29 13:33:42 -05:00
except Exception:
phoneInfo['cantConnect'] = True
2023-12-29 13:33:42 -05:00
phoneInfo['chipset'] = (str(mtkClass.config.chipconfig.name) + " (" + str(mtkClass.config.chipconfig.description) +
")")
self.sendUpdateSignal.emit()
2021-12-25 17:01:25 -05:00
mtkClass = da_handler.configure_da(mtkClass, preloader=None)
if mtkClass:
phoneInfo['daInit'] = True
2023-12-29 13:33:42 -05:00
phoneInfo['chipset'] = (str(mtkClass.config.chipconfig.name) + " (" +
str(mtkClass.config.chipconfig.description) + ")")
2021-12-25 17:01:25 -05:00
if mtkClass.config.is_brom:
phoneInfo['bootMode'] = "Bootrom mode"
elif mtkClass.config.chipconfig.damode:
phoneInfo['bootMode'] = "DA mode"
else:
phoneInfo['bootMode'] = "Preloader mode"
self.sendUpdateSignal.emit()
else:
phoneInfo['cantConnect'] = True
self.sendUpdateSignal.emit()
2021-12-25 17:01:25 -05:00
2023-12-29 13:33:42 -05:00
2021-12-29 09:31:56 -05:00
def load_translations(application):
2022-01-01 12:46:52 -05:00
# Load application translations and the QT base translations for the current locale
2021-12-29 09:31:56 -05:00
locale = QLocale.system()
translator = QTranslator(application)
directory = os.path.dirname(__file__)
2024-05-04 04:10:00 -04:00
lang = f'mtkclient/gui/i18n/{locale.name()}'
2022-01-07 05:51:38 -05:00
if locale.name() == "en_NL":
lang = lang.replace("en_NL", "nl_NL")
2022-01-01 12:46:52 -05:00
# lang = 'mtkclient/gui/i18n/fr_FR'
# lang = 'mtkclient/gui/i18n/de_DE'
# lang = 'mtkclient/gui/i18n/en_GB'
# lang = 'mtkclient/gui/i18n/es_ES'
2021-12-29 09:31:56 -05:00
if translator.load(lang, directory):
application.installTranslator(translator)
2023-07-12 06:28:27 -04:00
translations_path = QLibraryInfo.path(QLibraryInfo.TranslationsPath)
2021-12-29 09:31:56 -05:00
base_translator = QTranslator(application)
if base_translator.load(locale, "qtbase", "_", translations_path):
application.installTranslator(base_translator)
2021-12-29 10:08:38 -05:00
2021-12-29 18:17:55 -05:00
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
2022-01-01 12:46:52 -05:00
self.ui = Ui_MainWindow()
2021-12-29 18:17:55 -05:00
self.ui.setupUi(self)
2022-01-01 12:46:52 -05:00
self.fdialog = FDialog(self)
2021-12-29 18:17:55 -05:00
self.initpixmap()
2022-01-11 15:18:37 -05:00
self.Status = {}
2022-01-01 12:46:52 -05:00
self.timeEst = TimeEstim()
self.timeEstTotal = TimeEstim()
2021-12-29 18:17:55 -05:00
self.ui.logBox.setWordWrapMode(QTextOption.NoWrap)
self.ui.menubar.setEnabled(False)
self.ui.tabWidget.setHidden(True)
self.ui.partProgress.setHidden(True)
self.ui.fullProgress.setHidden(True)
2022-06-27 05:51:00 -04:00
self.ui.readDumpGPTCheckbox.setChecked(True)
2022-01-11 15:18:37 -05:00
self.ui.connectInfo.setMinimumSize(200, 500)
self.ui.connectInfo.setMaximumSize(9900, 500)
self.ui.showdebugbtn.clicked.connect(self.showDebugInfo)
2022-01-01 12:46:52 -05:00
self.devhandler = None
self.readflash = None
def showDebugInfo(self):
self.ui.connectInfo.setHidden(True)
self.ui.tabWidget.setCurrentWidget(self.ui.debugtab)
self.ui.tabWidget.setHidden(False)
2022-01-01 12:46:52 -05:00
@Slot()
def updateState(self):
2022-01-11 15:18:37 -05:00
global lock
lock.acquire()
2022-01-01 12:46:52 -05:00
doneBytes = 0
2024-05-04 10:57:49 -04:00
curpartBytes = self.Status[f"currentPartitionSize{'Done' if 'currentPartitionSizeDone' in self.Status else ''}"]
2022-01-11 15:18:37 -05:00
2022-01-01 12:46:52 -05:00
if "allPartitions" in self.Status:
for partition in self.Status["allPartitions"]:
2022-01-11 15:18:37 -05:00
if self.Status["allPartitions"][partition]['done'] and partition != self.Status["currentPartition"]:
2022-01-01 12:46:52 -05:00
doneBytes = doneBytes + self.Status["allPartitions"][partition]['size']
2022-01-11 15:18:37 -05:00
doneBytes = curpartBytes + doneBytes
totalBytes = self.Status["totalsize"]
fullPercentageDone = int((doneBytes / totalBytes) * 100)
self.ui.fullProgress.setValue(fullPercentageDone)
timeinfototal = self.timeEstTotal.update(fullPercentageDone, 100)
2024-05-04 10:59:41 -04:00
self.ui.fullProgressText.setText(f"<table width='100%'><tr><td><b>Total:</b> {convert_size(doneBytes)} / {convert_size(totalBytes)}</td><td align='right'>{timeinfototal}{QCoreApplication.translate('main', ' left')}</td></tr></table>")
2022-01-11 15:18:37 -05:00
else:
partBytes = self.Status["currentPartitionSize"]
doneBytes = self.Status["currentPartitionSizeDone"]
fullPercentageDone = int((doneBytes / partBytes) * 100)
self.ui.fullProgress.setValue(fullPercentageDone)
timeinfototal = self.timeEstTotal.update(fullPercentageDone, 100)
self.ui.fullProgressText.setText("<table width='100%'><tr><td><b>Total:</b> " +
2023-12-29 13:33:42 -05:00
convert_size(doneBytes) + " / " + convert_size(partBytes) +
"</td><td align='right'>" +
timeinfototal + QCoreApplication.translate("main",
" left") + "</td></tr></table>")
2022-01-01 13:25:59 -05:00
if "currentPartitionSize" in self.Status:
2022-01-11 15:18:37 -05:00
partBytes = self.Status["currentPartitionSize"]
partDone = (curpartBytes / partBytes) * 100
self.ui.partProgress.setValue(partDone)
timeinfo = self.timeEst.update(curpartBytes, partBytes)
txt = "<table width='100%'><tr><td><b>Current partition:</b> " + self.Status["currentPartition"] + \
2023-12-29 13:33:42 -05:00
" (" + convert_size(curpartBytes) + " / " + convert_size(partBytes) + ") </td><td align='right'>" + \
timeinfo + QCoreApplication.translate("main", " left") + "</td></tr></table>"
2022-01-01 13:25:59 -05:00
self.ui.partProgressText.setText(txt)
2022-01-11 15:18:37 -05:00
lock.release()
2022-01-01 12:46:52 -05:00
def updateStateAsync(self, toolkit, parameters):
while not self.Status["done"]:
# print(self.dumpStatus)
time.sleep(0.1)
print("DONE")
self.ui.readpreloaderbtn.setEnabled(True)
self.ui.readpartitionsbtn.setEnabled(True)
self.ui.readboot2btn.setEnabled(True)
self.ui.readrpmbbtn.setEnabled(True)
self.ui.readflashbtn.setEnabled(True)
self.ui.writepartbtn.setEnabled(True)
self.ui.writeflashbtn.setEnabled(True)
self.ui.writeboot2btn.setEnabled(True)
self.ui.writepreloaderbtn.setEnabled(True)
self.ui.writerpmbbtn.setEnabled(True)
self.ui.erasepartitionsbtn.setEnabled(True)
self.ui.eraseboot2btn.setEnabled(True)
self.ui.erasepreloaderbtn.setEnabled(True)
self.ui.eraserpmbbtn.setEnabled(True)
@Slot(int)
def updateProgress(self, progress):
try:
if self.Status["rpmb"]:
self.Status["currentPartitionSizeDone"] = progress
else:
2023-12-29 13:33:42 -05:00
self.Status[
"currentPartitionSizeDone"] = progress * self.devhandler.da_handler.mtk.daloader.progress.pagesize
self.updateState()
2023-12-29 13:33:42 -05:00
except Exception:
pass
2022-01-01 12:46:52 -05:00
def setdevhandler(self, devhandler):
self.devhandler = devhandler
devhandler.sendToProgressSignal.connect(self.updateProgress)
2022-01-11 08:18:43 -05:00
devhandler.update_status_text.connect(self.update_status_text)
2022-01-01 12:46:52 -05:00
def initread(self):
2023-12-29 13:33:42 -05:00
self.readflash = ReadFlashWindow(self.ui, self, self.devhandler.da_handler, self.sendToLog)
2022-01-04 15:02:49 -05:00
thread.sendUpdateSignal.connect(win.updateGui)
self.readflash.enableButtonsSignal.connect(self.enablebuttons)
self.readflash.disableButtonsSignal.connect(self.disablebuttons)
2022-01-01 12:46:52 -05:00
self.ui.readpartitionsbtn.clicked.connect(self.readflash.dumpPartition)
self.ui.readselectallcheckbox.clicked.connect(self.readflash.selectAll)
2024-05-04 04:10:00 -04:00
self.ui.readpreloaderbtn.clicked.connect(lambda: self.readflash.dumpFlash("boot1"))
self.ui.readflashbtn.clicked.connect(lambda: self.readflash.dumpFlash("user"))
self.ui.readrpmbbtn.clicked.connect(lambda: self.readflash.dumpFlash("rpmb"))
self.ui.readboot2btn.clicked.connect(lambda: self.readflash.dumpFlash("boot2"))
2022-01-01 12:46:52 -05:00
def initkeys(self):
2022-01-11 15:18:37 -05:00
self.genkeys = generateKeysMenu(self.ui, self, self.devhandler.da_handler, self.sendToLog)
2024-05-04 04:10:00 -04:00
self.ui.generatekeybtn.clicked.connect(self.genkeys.generateKeys)
2022-01-04 15:02:49 -05:00
self.genkeys.enableButtonsSignal.connect(self.enablebuttons)
self.genkeys.disableButtonsSignal.connect(self.disablebuttons)
2022-01-01 12:46:52 -05:00
2022-01-01 13:25:59 -05:00
def initunlock(self):
2022-01-11 15:18:37 -05:00
self.unlock = UnlockMenu(self.ui, self, self.devhandler.da_handler, self.sendToLog)
2024-05-04 04:10:00 -04:00
self.ui.unlockbutton.clicked.connect(lambda: self.unlock.unlock("unlock"))
self.ui.lockbutton.clicked.connect(lambda: self.unlock.unlock("lock"))
2022-01-04 15:02:49 -05:00
self.unlock.enableButtonsSignal.connect(self.enablebuttons)
self.unlock.disableButtonsSignal.connect(self.disablebuttons)
2022-01-01 13:25:59 -05:00
2022-01-01 12:46:52 -05:00
def initerase(self):
2022-01-11 15:18:37 -05:00
self.eraseflash = EraseFlashWindow(self.ui, self, self.devhandler.da_handler, self.sendToLog)
2022-01-04 15:02:49 -05:00
self.eraseflash.enableButtonsSignal.connect(self.enablebuttons)
self.eraseflash.disableButtonsSignal.connect(self.disablebuttons)
2022-01-01 12:46:52 -05:00
self.ui.eraseselectallpartitionscheckbox.clicked.connect(self.eraseflash.selectAll)
2024-05-04 04:10:00 -04:00
self.ui.erasepartitionsbtn.clicked.connect(self.eraseflash.erasePartition)
self.ui.eraserpmbbtn.clicked.connect(lambda: self.eraseflash.eraseFlash("rpmb"))
self.ui.erasepreloaderbtn.clicked.connect(lambda: self.eraseflash.eraseFlash("boot1"))
self.ui.eraseboot2btn.clicked.connect(lambda: self.eraseflash.eraseFlash("boot2"))
2022-01-01 12:46:52 -05:00
def initwrite(self):
2022-01-11 15:18:37 -05:00
self.writeflash = WriteFlashWindow(self.ui, self, self.devhandler.da_handler, self.sendToLog)
2022-01-04 15:02:49 -05:00
self.writeflash.enableButtonsSignal.connect(self.enablebuttons)
self.writeflash.disableButtonsSignal.connect(self.disablebuttons)
2022-01-01 12:46:52 -05:00
self.ui.writeselectfromdir.clicked.connect(self.writeflash.selectFiles)
2024-05-04 04:10:00 -04:00
self.ui.writeflashbtn.clicked.connect(lambda: self.writeflash.writeFlash("user"))
self.ui.writepartbtn.clicked.connect(self.writeflash.writePartition)
self.ui.writeboot2btn.clicked.connect(lambda: self.writeflash.writeFlash("boot2"))
self.ui.writepreloaderbtn.clicked.connect(lambda: self.writeflash.writeFlash("boot1"))
self.ui.writerpmbbtn.clicked.connect(lambda: self.writeflash.writeFlash("rpmb"))
2022-01-01 12:46:52 -05:00
2022-01-11 08:18:43 -05:00
@Slot(str)
def update_status_text(self, text):
self.ui.phoneDebugInfoTextbox.setText(text)
2022-01-11 08:18:43 -05:00
2022-01-04 15:02:49 -05:00
@Slot()
2022-01-01 12:46:52 -05:00
def disablebuttons(self):
self.ui.readpreloaderbtn.setEnabled(False)
self.ui.readpartitionsbtn.setEnabled(False)
self.ui.readboot2btn.setEnabled(False)
self.ui.readrpmbbtn.setEnabled(False)
self.ui.readflashbtn.setEnabled(False)
self.ui.writeflashbtn.setEnabled(False)
self.ui.writepartbtn.setEnabled(False)
self.ui.writepreloaderbtn.setEnabled(False)
self.ui.writeboot2btn.setEnabled(False)
self.ui.writerpmbbtn.setEnabled(False)
self.ui.eraseboot2btn.setEnabled(False)
self.ui.erasepreloaderbtn.setEnabled(False)
self.ui.eraserpmbbtn.setEnabled(False)
2022-01-01 13:25:59 -05:00
self.ui.generatekeybtn.setEnabled(False)
self.ui.unlockbutton.setEnabled(False)
self.ui.lockbutton.setEnabled(False)
2022-01-04 15:02:49 -05:00
@Slot()
2022-01-01 12:46:52 -05:00
def enablebuttons(self):
self.ui.readpreloaderbtn.setEnabled(True)
self.ui.readpartitionsbtn.setEnabled(True)
self.ui.readboot2btn.setEnabled(True)
self.ui.readrpmbbtn.setEnabled(True)
self.ui.readflashbtn.setEnabled(True)
self.ui.writeflashbtn.setEnabled(True)
self.ui.writepartbtn.setEnabled(True)
self.ui.writepreloaderbtn.setEnabled(True)
self.ui.writeboot2btn.setEnabled(True)
self.ui.writerpmbbtn.setEnabled(True)
self.ui.eraseboot2btn.setEnabled(True)
self.ui.erasepreloaderbtn.setEnabled(True)
self.ui.eraserpmbbtn.setEnabled(True)
2022-01-01 13:25:59 -05:00
self.ui.generatekeybtn.setEnabled(True)
self.ui.unlockbutton.setEnabled(True)
self.ui.lockbutton.setEnabled(True)
2022-01-11 15:18:37 -05:00
self.ui.partProgress.setValue(100)
self.ui.fullProgress.setValue(100)
self.ui.fullProgressText.setText("")
self.ui.partProgressText.setText(self.tr("Done."))
self.Status = {}
2022-01-01 13:25:59 -05:00
2022-01-01 12:46:52 -05:00
def getpartitions(self):
2022-01-11 15:18:37 -05:00
data, guid_gpt = self.devhandler.da_handler.mtk.daloader.get_gpt()
2024-05-04 04:10:00 -04:00
self.ui.readtitle.setText(QCoreApplication.translate("main", "Error reading gpt" if guid_gpt is None else "Select partitions to dump"))
2022-01-01 12:46:52 -05:00
readpartitionListWidgetVBox = QVBoxLayout()
readpartitionListWidget = QWidget(self)
readpartitionListWidget.setLayout(readpartitionListWidgetVBox)
self.ui.readpartitionList.setWidget(readpartitionListWidget)
self.ui.readpartitionList.setWidgetResizable(True)
2023-12-29 13:33:42 -05:00
# self.ui.readpartitionList.setGeometry(10,40,380,320)
2022-01-01 12:46:52 -05:00
self.ui.readpartitionList.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.ui.readpartitionList.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.readpartitionCheckboxes = {}
for partition in guid_gpt.partentries:
self.readpartitionCheckboxes[partition.name] = {}
self.readpartitionCheckboxes[partition.name]['size'] = (partition.sectors * guid_gpt.sectorsize)
self.readpartitionCheckboxes[partition.name]['box'] = QCheckBox()
self.readpartitionCheckboxes[partition.name]['box'].setText(partition.name + " (" +
2023-12-29 13:33:42 -05:00
convert_size(
partition.sectors * guid_gpt.sectorsize) + ")")
2022-01-01 12:46:52 -05:00
readpartitionListWidgetVBox.addWidget(self.readpartitionCheckboxes[partition.name]['box'])
writepartitionListWidgetVBox = QVBoxLayout()
writepartitionListWidget = QWidget(self)
writepartitionListWidget.setLayout(writepartitionListWidgetVBox)
self.ui.writepartitionList.setWidget(writepartitionListWidget)
self.ui.writepartitionList.setWidgetResizable(True)
2023-12-29 13:33:42 -05:00
# self.ui.writepartitionList.setGeometry(10,40,380,320)
2022-01-01 12:46:52 -05:00
self.ui.writepartitionList.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.ui.writepartitionList.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.writepartitionCheckboxes = {}
for partition in guid_gpt.partentries:
self.writepartitionCheckboxes[partition.name] = {}
self.writepartitionCheckboxes[partition.name]['size'] = (partition.sectors * guid_gpt.sectorsize)
vb = QVBoxLayout()
2023-12-29 13:33:42 -05:00
qc = CheckBox()
2022-01-01 12:46:52 -05:00
qc.setReadOnly(True)
qc.setText(partition.name + " (" + convert_size(partition.sectors * guid_gpt.sectorsize) + ")")
2023-12-29 13:33:42 -05:00
hc = QHBoxLayout()
ll = QLineEdit()
lb = QPushButton(QCoreApplication.translate("main", "Set"))
lb.clicked.connect(partial(self.selectWriteFile, partition.name, qc, ll))
2022-01-01 12:46:52 -05:00
hc.addWidget(ll)
hc.addWidget(lb)
vb.addWidget(qc)
vb.addLayout(hc)
ll.setDisabled(True)
2023-12-29 13:33:42 -05:00
self.writepartitionCheckboxes[partition.name]['box'] = [qc, ll, lb]
2022-01-01 12:46:52 -05:00
writepartitionListWidgetVBox.addLayout(vb)
erasepartitionListWidgetVBox = QVBoxLayout()
erasepartitionListWidget = QWidget(self)
erasepartitionListWidget.setLayout(erasepartitionListWidgetVBox)
self.ui.erasepartitionList.setWidget(erasepartitionListWidget)
self.ui.erasepartitionList.setWidgetResizable(True)
2023-12-29 13:33:42 -05:00
# self.ui.erasepartitionList.setGeometry(10,40,380,320)
2022-01-01 12:46:52 -05:00
self.ui.erasepartitionList.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.ui.erasepartitionList.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.erasepartitionCheckboxes = {}
for partition in guid_gpt.partentries:
self.erasepartitionCheckboxes[partition.name] = {}
self.erasepartitionCheckboxes[partition.name]['size'] = (partition.sectors * guid_gpt.sectorsize)
self.erasepartitionCheckboxes[partition.name]['box'] = QCheckBox()
self.erasepartitionCheckboxes[partition.name]['box'].setText(partition.name + " (" +
2023-12-29 13:33:42 -05:00
convert_size(
partition.sectors * guid_gpt.sectorsize) + ")")
2022-01-01 12:46:52 -05:00
erasepartitionListWidgetVBox.addWidget(self.erasepartitionCheckboxes[partition.name]['box'])
def selectWriteFile(self, partition, checkbox, lineedit):
2023-12-29 13:33:42 -05:00
fname = self.fdialog.open(partition + ".bin")
2022-01-01 12:46:52 -05:00
if fname is None:
checkbox.setChecked(False)
lineedit.setText("")
lineedit.setDisabled(True)
return ""
checkbox.setChecked(True)
lineedit.setText(fname)
lineedit.setDisabled(False)
return fname
2021-12-30 04:47:08 -05:00
2021-12-29 18:17:55 -05:00
def sendToLog(self, info):
2024-05-04 04:10:00 -04:00
self.ui.logBox.appendPlainText(time.strftime("[%H:%M:%S", time.localtime()) + "]: " + info)
2021-12-29 18:17:55 -05:00
self.ui.logBox.verticalScrollBar().setValue(self.ui.logBox.verticalScrollBar().maximum())
2021-12-30 14:41:25 -05:00
def sendToProgress(self, progress):
return
2021-12-29 18:17:55 -05:00
def updateGui(self):
global phoneInfo
phoneInfo['chipset'] = phoneInfo['chipset'].replace("()", "")
2021-12-29 18:17:55 -05:00
if phoneInfo['cdcInit'] and phoneInfo['bootMode'] == "":
2023-12-29 13:33:42 -05:00
self.ui.phoneInfoTextbox.setText(
QCoreApplication.translate("main", "Phone detected:\nReading model info..."))
2021-12-29 18:17:55 -05:00
else:
2022-01-01 12:46:52 -05:00
self.ui.phoneInfoTextbox.setText(QCoreApplication.translate("main",
2023-12-29 13:33:42 -05:00
"Phone detected:\n" + phoneInfo[
'chipset'] + "\n" + phoneInfo['bootMode']))
# Disabled due to graphical steps. Maybe this should come back somewhere else.
# self.ui.status.setText(QCoreApplication.translate("main","Device detected, please wait.\nThis can take a while..."))
2021-12-29 18:17:55 -05:00
if phoneInfo['daInit']:
2023-12-29 13:33:42 -05:00
# self.ui.status.setText(QCoreApplication.translate("main","Device connected :)"))
2021-12-29 18:17:55 -05:00
self.ui.menubar.setEnabled(True)
self.pixmap = QPixmap(path.get_images_path("phone_connected.png"))
self.ui.phoneDebugInfoTextbox.setText("")
2021-12-29 18:17:55 -05:00
self.ui.pic.setPixmap(self.pixmap)
self.spinnerAnim.stop()
self.ui.spinner_pic.setHidden(True)
self.ui.connectInfo.setHidden(True)
self.ui.partProgress.setHidden(False)
self.ui.fullProgress.setHidden(False)
2022-01-01 12:46:52 -05:00
self.initread()
self.initkeys()
2022-01-01 13:25:59 -05:00
self.initunlock()
2022-01-01 12:46:52 -05:00
self.initerase()
self.initwrite()
self.getpartitions()
2023-07-12 07:04:04 -04:00
self.ui.tabWidget.setCurrentIndex(0)
self.ui.tabWidget.update()
self.ui.tabWidget.setHidden(False)
2022-01-01 12:46:52 -05:00
2021-12-29 18:17:55 -05:00
else:
if 'cantConnect' in phoneInfo:
2023-12-29 13:33:42 -05:00
self.ui.status.setText(
QCoreApplication.translate("main", "Error initialising. Did you install the drivers?"))
2021-12-29 18:17:55 -05:00
self.spinnerAnim.start()
self.ui.spinner_pic.setHidden(False)
def spinnerAnimRot(self, angle):
2023-12-29 13:33:42 -05:00
# trans = QTransform()
# dimension = self.pixmap.width() / math.sqrt(2)
2021-12-29 18:17:55 -05:00
newPixmap = self.pixmap.transformed(QTransform().rotate(angle), Qt.SmoothTransformation)
2022-01-01 12:46:52 -05:00
xoffset = (newPixmap.width() - self.pixmap.width()) / 2
yoffset = (newPixmap.height() - self.pixmap.height()) / 2
2021-12-29 18:17:55 -05:00
rotated = newPixmap.copy(xoffset, yoffset, self.pixmap.width(), self.pixmap.height())
self.ui.spinner_pic.setPixmap(rotated)
def initpixmap(self):
# phone spinner
self.pixmap = QPixmap(path.get_images_path("phone_loading.png")).scaled(96, 96, Qt.KeepAspectRatio,
2022-01-01 12:46:52 -05:00
Qt.SmoothTransformation)
2021-12-29 18:17:55 -05:00
self.pixmap.setDevicePixelRatio(2)
self.ui.spinner_pic.setPixmap(self.pixmap)
self.ui.spinner_pic.show()
nfpixmap = QPixmap(path.get_images_path("phone_notfound.png"))
self.ui.pic.setPixmap(nfpixmap)
logo = QPixmap(path.get_images_path("logo_256.png"))
self.ui.logoPic.setPixmap(logo)
initSteps = QPixmap(path.get_images_path("initsteps.png"))
self.ui.initStepsImage.setPixmap(initSteps)
2021-12-29 18:17:55 -05:00
self.spinnerAnim = QVariantAnimation()
self.spinnerAnim.setDuration(3000)
self.spinnerAnim.setStartValue(0)
self.spinnerAnim.setEndValue(360)
self.spinnerAnim.setLoopCount(-1)
self.spinnerAnim.valueChanged.connect(self.spinnerAnimRot)
self.ui.spinner_pic.setHidden(True)
2021-12-25 17:01:25 -05:00
if __name__ == '__main__':
2021-12-29 09:31:56 -05:00
# Enable nice 4K Scaling
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
2021-12-25 17:01:25 -05:00
# Init the app window
app = QApplication(sys.argv)
2021-12-29 09:31:56 -05:00
load_translations(app)
2021-12-29 18:17:55 -05:00
win = MainWindow()
2021-12-25 17:01:25 -05:00
icon = QIcon()
icon.addFile(path.get_images_path('logo_32.png'), QSize(32, 32))
icon.addFile(path.get_images_path('logo_64.png'), QSize(64, 64))
icon.addFile(path.get_images_path('logo_256.png'), QSize(256, 256))
icon.addFile(path.get_images_path('logo_512.png'), QSize(512, 512))
app.setWindowIcon(icon)
win.setWindowIcon(icon)
if sys.platform.startswith('win'):
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('MTKTools.Gui')
dpiMultiplier = win.logicalDpiX()
if dpiMultiplier == 72:
dpiMultiplier = 2
else:
dpiMultiplier = 1
addTopMargin = 20
if sys.platform.startswith('darwin'): # MacOS has the toolbar in the top bar insted of in the app...
addTopMargin = 0
2023-07-12 06:28:27 -04:00
win.setWindowTitle("MTKClient - Version 2.0")
2021-12-25 17:01:25 -05:00
# lay = QVBoxLayout(self)
win.show()
2022-01-01 12:46:52 -05:00
# win.setFixedSize(746, 400 + addTopMargin)
2021-12-25 17:01:25 -05:00
# Device setup
loglevel = logging.INFO
2022-01-01 12:46:52 -05:00
devhandler = DeviceHandler(parent=app, preloader=None, loglevel=loglevel)
2021-12-29 18:17:55 -05:00
devhandler.sendToLogSignal.connect(win.sendToLog)
2021-12-25 17:01:25 -05:00
# Get the device info
2022-01-01 12:46:52 -05:00
thread = asyncThread(parent=app, n=0, function=getDevInfo, parameters=[loglevel, phoneInfo, devhandler])
2021-12-29 18:17:55 -05:00
thread.sendToLogSignal.connect(win.sendToLog)
thread.sendUpdateSignal.connect(win.updateGui)
2021-12-30 14:41:25 -05:00
thread.sendToProgressSignal.connect(win.sendToProgress)
2021-12-25 17:01:25 -05:00
thread.start()
2022-01-01 12:46:52 -05:00
win.setdevhandler(devhandler)
2021-12-25 17:01:25 -05:00
# Run loop the app
2022-01-01 12:46:52 -05:00
app.exec()
2021-12-25 17:01:25 -05:00
# Prevent thread from not being closed and call error end codes
thread.terminate()
thread.wait()