diff --git a/src/main/java/ecorp/easy/installer/controllers/LogController.java b/src/main/java/ecorp/easy/installer/controllers/LogController.java new file mode 100644 index 0000000000000000000000000000000000000000..bb7476ff5e2cbb157441e6e17d5a271cf7f74d80 --- /dev/null +++ b/src/main/java/ecorp/easy/installer/controllers/LogController.java @@ -0,0 +1,104 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package ecorp.easy.installer.controllers; + +import ecorp.easy.installer.AppConstants; +import ecorp.easy.installer.logger.GUIAppender; +import ecorp.easy.installer.logger.LogPathPropertyDefiner; +import ecorp.easy.installer.tasks.UploadToEcloudTask; +import ecorp.easy.installer.utils.UiUtils; +import java.net.URL; +import java.util.ResourceBundle; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.Button; +import javafx.scene.control.ScrollPane; +import javafx.scene.text.TextFlow; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This is the controller in charge of UI element to display log + * @author vincent Bourgmayer + */ +public class LogController implements Initializable{ + + private final static Logger logger = LoggerFactory.getLogger(LogController.class); + + //element relatives to log display + @FXML ScrollPane logScrollPane; + @FXML TextFlow logFlow; + @FXML Button showHideLogBtn; + @FXML Button sendLogBtn; + + @Override + public void initialize(URL arg0, ResourceBundle arg1) { + logFlow.heightProperty().addListener(observable -> logScrollPane.setVvalue(1.0)); + + logScrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + } + + + /** + * enable/disable log displaying + */ + public void showHideLog(){ + ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + GUIAppender appender = (GUIAppender) rootLogger.getAppender("GUI"); + + final String text = showHideLogBtn.getText(); + if(text.equals(">")){ + showHideLogBtn.setText("V"); + UiUtils.hideNode(logScrollPane); + logFlow.getChildren().clear(); + appender.setContainer(null); + logScrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + }else{ + showHideLogBtn.setText(">"); + UiUtils.showNode(logScrollPane); + logFlow.getChildren().addAll(appender.getLogsList()); + appender.setContainer(logFlow); + logScrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); + } + } + + /** + * Send log to support, in special ecloud.global folder + * @return + */ + public boolean sendLogToSupport(){ + //if (thread != null){ + String filePath = LogPathPropertyDefiner.getLogFilePath(); + if(filePath != null){ + + UploadToEcloudTask uploadTask = new UploadToEcloudTask(AppConstants.LOG_STORAGE_URL, filePath); + uploadTask.setOnSucceeded(eh -> { + if( (Boolean) eh.getSource().getValue() ){ //if success + sendLogBtn.setDisable(true); + //sendLogBtn.setText(i18n.getString("install_btn_sendLogSuccess")); + logger.info("sendLogToSupport(), sending log: success"); + } + else{ + //sendLogBtn.setText(i18n.getString("install_btn_sendLogAgain")); + logger.warn("sendLogToSupport(), sending log: failure"); + } + }); + + uploadTask.setOnFailed(eh->{ + //sendLogBtn.setText(i18n.getString("install_btn_sendLogAgain")); + logger.warn("sendLogToSupport(), sending log: failure, error = {}",eh.getSource().getException().toString() ); + }); + + Thread uploadTaskThread = new Thread(uploadTask); + uploadTaskThread.setDaemon(true); + uploadTaskThread.start(); + } + return false; + } + + public void showSendLogBtn(){ + UiUtils.showNode(sendLogBtn); + } +} \ No newline at end of file diff --git a/src/main/java/ecorp/easy/installer/controllers/MainWindowController.java b/src/main/java/ecorp/easy/installer/controllers/MainWindowController.java index 6259a3421ac5a7dc31f940b66c185f9ab53467f8..c54deab94f3aaf86c1edd55726f532c8fb073a8f 100644 --- a/src/main/java/ecorp/easy/installer/controllers/MainWindowController.java +++ b/src/main/java/ecorp/easy/installer/controllers/MainWindowController.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 - ECORP SAS + * Copyright 2019-2021 - ECORP SAS * 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 @@ -19,7 +19,13 @@ package ecorp.easy.installer.controllers; import ecorp.easy.installer.AppConstants; import ecorp.easy.installer.controllers.subcontrollers.AbstractSubController; import ecorp.easy.installer.EasyInstaller; +import ecorp.easy.installer.controllers.stepControllers.CustomExecutableController; +import ecorp.easy.installer.controllers.stepControllers.CustomStepController; +import ecorp.easy.installer.controllers.stepControllers.StepController; +import ecorp.easy.installer.controllers.stepControllers.Stoppable; import ecorp.easy.installer.models.Phone; +import ecorp.easy.installer.models.steps.IStep; +import ecorp.easy.installer.tasks.CommandRunnerService; import ecorp.easy.installer.threads.ThreadFactory; import ecorp.easy.installer.utils.UiUtils; @@ -61,7 +67,9 @@ public class MainWindowController implements Initializable { ThreadFactory factory = new ThreadFactory("/yaml/"); Phone device; //Object encapsulating data about the device to flash private boolean isFlashed = false; // True when /e/ OS installed on device - + private String currentStepKey = "f0"; + + private Object subController; /** * Initializes the controller class. @@ -81,6 +89,8 @@ public class MainWindowController implements Initializable { Bindings.concat("-fx-font-size: ", fontSize.asString("%.0f")).concat("px;") ); + StepController.setParentController(this); + } /** @@ -163,36 +173,79 @@ public class MainWindowController implements Initializable { if(currentSubRootId == null || currentSubRootId.isEmpty()){ - currentSubRootId =loadSubUI("1-beforeYouBegin.fxml", "before_mTitle").getId(); + currentSubRootId =loadSubUI("1-beforeYouBegin.fxml", "before_mTitle", null).getId(); }else{ switch(currentSubRootId){ case "beforeYouBeginRoot": - changeView(currentSubRootId, "2-connectDevice.fxml", "connect_mTitle"); + changeView("2-connectDevice.fxml", "connect_mTitle", null); break; case "connectDeviceRoot": - changeView(currentSubRootId, "3-enableADB.fxml", "devMode_mTitle"); + changeView("3-enableADB.fxml", "devMode_mTitle", null); break; case "enableDevMode": if(AppConstants.isWindowsOs()){ - changeView(currentSubRootId, "3-2-checkDriverInstallation.fxml", "checkDriverInstall_mTitle"); + changeView("3-2-checkDriverInstallation.fxml", "checkDriverInstall_mTitle", null); }else{ - changeView(currentSubRootId, "4-deviceDetected.fxml", "detect_mTitle"); + changeView("4-deviceDetected.fxml", "detect_mTitle", null); disableNextButton(true); } break; case "checkDriverInstallation": - changeView(currentSubRootId, "4-deviceDetected.fxml", "detect_mTitle"); + changeView("4-deviceDetected.fxml", "detect_mTitle", null); disableNextButton(true); break; case "deviceDetectedRoot": - changeView(currentSubRootId, "5-downloadSrc.fxml", "download_mTitle"); + changeView("5-downloadSrc.fxml", "download_mTitle", null); disableNextButton(true); break; + case "uiRoot": case "downloadSceneRoot": - changeView(currentSubRootId, "6-flashScene.fxml", "installationTitle"); - break; - case "flashSceneRoot": - changeView(currentSubRootId, "7-flashResult.fxml", "installationTitle"); + StepController controller = null; + String fxmlName = ""; + String title ="installationTitle"; + if(currentStepKey.equals(IStep.LAST_STEP_KEY)){ + if(isFlashed){ + fxmlName="7-flashResult.fxml"; + title="installationTitle"; + }else{ + fxmlName="9-feedback.fxml"; + title="feedback_mTitle"; + } + }else{ + final IStep step = factory.getFlashMould().getSteps().get(currentStepKey); + + switch(step.getType()){ + case "askAccount": + fxmlName = "6-2-eAccount.fxml"; + break; + case "enableOemUnlock": + fxmlName = "6-3-unlockOEM.fxml"; + break; + case "custom": + controller = new CustomStepController(); + fxmlName="customStep.fxml"; + break; + case "custom-executable": + controller = new CustomExecutableController(); + fxmlName="customStep.fxml"; + break; + case "executable": + //no interface there + break; + case "load": + fxmlName = "loadStep.fxml"; + break; + default: + //no interface there + break; + } + } + + if(!fxmlName.isBlank()) + changeView(fxmlName, title, controller); + else + logger.error("No interface to load!"); + break; case "flashResultRoot": final String fxmlFileName; @@ -205,10 +258,10 @@ public class MainWindowController implements Initializable { fxmlFileName = "9-feedback.fxml"; nextViewTitle ="feedback_mTitle"; } - changeView(currentSubRootId, fxmlFileName, nextViewTitle); + changeView(fxmlFileName, nextViewTitle, null); break; case "congratsRoot": - changeView(currentSubRootId, "9-feedback.fxml", "feedback_mTitle"); + changeView("9-feedback.fxml", "feedback_mTitle", null); break; case "feedbackRoot": Platform.exit(); @@ -220,8 +273,12 @@ public class MainWindowController implements Initializable { } } + /** + * Reset the flashing process to the begining + */ public void retryToFlash(){ - changeView(currentSubRootId, "6-flashScene.fxml", "installationTitle"); + currentStepKey = "f0"; + loadSubScene(); } /** @@ -231,6 +288,8 @@ public class MainWindowController implements Initializable { public void setDevice(Phone device){ this.factory.changeMould(device); this.device = device; + CommandRunnerService.updateCommonParam("DEVICE_ID", device.getSerialNo()); + CommandRunnerService.updateCommonParam("DEVICE_DEVICE", device.getAdbDevice()); } /** @@ -247,8 +306,12 @@ public class MainWindowController implements Initializable { * @param previousNodeId * @param fxmlName * @param viewTitle + * @param controller optionnal controller for the new UI. Should be null if already defined in FXML */ - public void changeView(final String previousNodeId, final String fxmlName, final String viewTitle){ + public void changeView(final String fxmlName, final String viewTitle, StepController controller){ + logger.debug("change view()"); + + final String previousNodeId = currentSubRootId; Node elementNode = null; //get current subroot for(Node node : root.getChildren() ){ @@ -257,17 +320,24 @@ public class MainWindowController implements Initializable { break; } } - if(elementNode == null) return ; + + if(elementNode == null){ + logger.debug("no subnode found"); + return ; + } //apply transition final FadeTransition fadeOutTransition = UiUtils.buildFadeTransition(elementNode, true); fadeOutTransition.setOnFinished(e -> { removeNodeFromRoot(previousNodeId); - final Node subRoot = loadSubUI(fxmlName, viewTitle); - currentSubRootId= subRoot.getId(); - - subRoot.setOpacity(0.0); - UiUtils.buildFadeTransition(subRoot,false).play(); + //logger.debug("Fade out for previous interface finished"); + final Node subRoot = loadSubUI(fxmlName, viewTitle, controller); + if (subRoot != null) + { + currentSubRootId= subRoot.getId(); + subRoot.setOpacity(0.0); + UiUtils.buildFadeTransition(subRoot,false).play(); + } }); fadeOutTransition.play(); } @@ -276,33 +346,53 @@ public class MainWindowController implements Initializable { /** * Load UI from FXML file * @param fxmlName + * @param controller an optionnal controller for the UI. Cann be null! * @return */ - public FXMLLoader loadFXML(String fxmlName){ + public FXMLLoader loadFXML(String fxmlName, StepController controller){ FXMLLoader loader; + loader = new FXMLLoader(getClass().getResource(EasyInstaller.FXML_PATH+fxmlName)); + loader.setResources(i18n); + + if(controller != null){ + loader.setController(controller); + subController = controller; + } + try{ - loader = new FXMLLoader(getClass().getResource(EasyInstaller.FXML_PATH+fxmlName)); - loader.setResources(i18n); loader.load(); - AbstractSubController ctrl = loader.getController(); - if(ctrl != null) ctrl.setParentController(this); }catch(IOException e){ logger.error("fxmlName = {}, error = {}", fxmlName, e.toString()); + e.printStackTrace(); return null; } + if(controller == null){ + final Object ctrl = loader.getController(); + + if(ctrl != null){ + subController = ctrl; + if( ctrl instanceof AbstractSubController ) + { + ((AbstractSubController)ctrl).setParentController(this); + } + } + } return loader; } /** * Load the subScene from FXML and return the controller * @param fxmlName fxml file name * @param viewTitle the title for the new View + * @param controller optionnal parameter. It's the controller for the UI if not defined in FXML * @return subRoot. */ - public Node loadSubUI(final String fxmlName, final String viewTitle){ - logger.debug("view title: "+viewTitle); + public Node loadSubUI(final String fxmlName, final String viewTitle, StepController controller){ if(viewTitle != null) titleLabel.setText(i18n.getString(viewTitle)); - FXMLLoader loader = loadFXML(fxmlName); + FXMLLoader loader = loadFXML(fxmlName, controller); + if(loader == null) return null; + Pane subRoot = (Pane) loader.getRoot(); + root.getChildren().add(0, subRoot); //adding this element as first subNode, let other element like button to still be clickable on small screen return subRoot; @@ -334,6 +424,9 @@ public class MainWindowController implements Initializable { */ public void onStop(){ logger.debug("onStop()"); + if(subController != null && subController instanceof Stoppable){ + ((Stoppable) subController).stop(); + } } /** @@ -370,5 +463,15 @@ public class MainWindowController implements Initializable { public Phone getDevice() { return device; } + + + public String getCurrentStepKey() { + return currentStepKey; + } + + + public void setCurrentStepKey(String currentStepKey) { + this.currentStepKey = currentStepKey; + } } diff --git a/src/main/java/ecorp/easy/installer/controllers/stepControllers/CustomExecutableController.java b/src/main/java/ecorp/easy/installer/controllers/stepControllers/CustomExecutableController.java new file mode 100644 index 0000000000000000000000000000000000000000..b8ecb9e281400be2431b6bab59b2fecda8ac9992 --- /dev/null +++ b/src/main/java/ecorp/easy/installer/controllers/stepControllers/CustomExecutableController.java @@ -0,0 +1,206 @@ +/* + * Copyright 2019-2021 - ECORP SAS + + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ecorp.easy.installer.controllers.stepControllers; + +import ecorp.easy.installer.controllers.LogController; +import static ecorp.easy.installer.controllers.stepControllers.StepController.parentController; +import ecorp.easy.installer.graphics.Instruction; +import ecorp.easy.installer.models.Command; +import ecorp.easy.installer.models.steps.CustomExecutableStep; +import ecorp.easy.installer.tasks.CommandRunnerService; +import ecorp.easy.installer.utils.UiUtils; +import ecorp.easy.installer.graphics.FlashGlobalProgressManager; +import ecorp.easy.installer.models.steps.IStep; +import java.net.URL; +import java.util.ArrayList; +import java.util.Locale; +import java.util.ResourceBundle; +import javafx.fxml.FXML; +import javafx.geometry.Pos; +import javafx.scene.control.Button; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; + +/** + * This is clearly a mix of CustomStepController & ExecutableStepController + * It means that it's code duplication. I don't like it but I didn't find a way to reuse + * both class because multiple extension isn't possible and any design pattern fit + * my need. But If you find a way please implement it! + * @author vincent Bourgmayer + */ +public class CustomExecutableController extends StepController implements Stoppable{ + + protected final ResourceBundle IMG_BUNDLE = ResourceBundle.getBundle("instructions.imageName", + new Locale.Builder() + .setRegion("en") + .setLanguage("EN") + .setVariant(parentController.getDevice().getInternalCode()) + .build()); + + private int currentEmphasizedInstruction = 0; + private int instructionsCount; + private CommandRunnerService backgroundService; + + @FXML private VBox instructionsContainer; + @FXML private Label titleLbl; + @FXML private ImageView imgView; + @FXML private LogController logRootController; + + // progress bar's node of global Flash's process : + @FXML HBox globalProgressIndicator; + private FlashGlobalProgressManager globalProgressMgr; + + @Override + public void initialize(URL url, ResourceBundle rb) { + super.initialize(url, rb); + + parentController.setNextButtonVisible(true); + + /** Initialization relatives to Custom **/ + titleLbl.setText(i18n.getString(step.getTitleKey() )); + if(step.getTitleIconName() != null){ + titleLbl.setGraphic(new ImageView(UiUtils.loadImage(step.getTitleIconName()))); + titleLbl.setGraphicTextGap(18); //set spacing between icon and text + titleLbl.setContentDisplay(ContentDisplay.LEFT); //set Icon to be displayed on left + } + + final ArrayList instructions = loadInstructions(); + instructions.get(currentEmphasizedInstruction).emphasize(); + instructionsContainer.getChildren().addAll(instructions); + displayInstructionImage(instructions.get(currentEmphasizedInstruction)); + instructionsCount = instructions.size(); + + globalProgressMgr = new FlashGlobalProgressManager(parentController.getThreadFactory().getStepsCount()); + for(int i = 0;i < step.getStepNumber(); i++){ + globalProgressMgr.updateProgression(); + } + globalProgressIndicator.getChildren().addAll(globalProgressMgr.getSegments()); + + + /** Initialization relatives to Executable **/ + final Command cmd = step.getCommand(); + backgroundService = new CommandRunnerService(cmd); + backgroundService.setOnSucceeded(eh->{ + boolean result = backgroundService.getValue(); + if(result) + onStepEnd(); + else{ + String errorMsgKey = cmd.getErrorMsg(); + if (errorMsgKey == null || errorMsgKey.isEmpty()){ + errorMsgKey = "script_error_unknown"; + } + displayError(errorMsgKey); + } + + }); + backgroundService.start(); + + } + + @Override + protected void onContinueClicked(){ + logger.debug("onContinueClicked"); + + final Instruction currentInstruction = (Instruction) instructionsContainer + .getChildren().get(1+currentEmphasizedInstruction++);//the +1 is to ignore the title + currentInstruction.trivialize(); + + + final Instruction nextInstruction = (Instruction) instructionsContainer + .getChildren().get(1+currentEmphasizedInstruction); //the +1 is to ignore the title + nextInstruction.emphasize(); + + displayInstructionImage(nextInstruction); + + if(currentEmphasizedInstruction+1 == instructionsCount){ + logger.debug("last instruction reached instruction"); + parentController.setNextButtonVisible(false); + } + } + + + /** + * Create Instruction nodes with text key from step + */ + private ArrayList loadInstructions(){ + final ArrayList result = new ArrayList<>(); + + for(String key : step.getTextContentKeys()){ + String contentKey = "all_lbl_notImplemented"; //set default key + System.out.println("translation key: "+key); + if(i18n.containsKey(key)){ + contentKey = key; + } + result.add(new Instruction(key, i18n.getString(contentKey))); + } + return result; + } + + + /** + * Display Image corresponding to the current Instruction + * if there is one. In other way, it remove current image + * @param instruction + */ + private void displayInstructionImage(Instruction instruction){ + if(IMG_BUNDLE.containsKey(instruction.getKey())){ + imgView.setImage( + UiUtils.loadImage( IMG_BUNDLE.getString( instruction.getKey() ) ) ); + }else{ + imgView.setImage(null); + } + } + + /** + * Display an error due to background task + * @param errorMsgKey + */ + protected void displayError(String errorMsgKey){ + + parentController.resetNextButtonEventHandler(); + //parentController.setNextButtonVisible(false); + parentController.setIsFlashed(false); + parentController.setCurrentStepKey(IStep.LAST_STEP_KEY); + + if(i18n.containsKey(errorMsgKey)){ + final Label errorLbl = new Label(i18n.getString(errorMsgKey)); + ((VBox) uiRoot).getChildren().add(2, errorLbl); + }else{ + logger.error("Missing translation for error key: {}", errorMsgKey); + } + UiUtils.hideNode(instructionsContainer.getParent()); + + logRootController.showSendLogBtn(); + + Button tryAgainBtn = new Button(i18n.getString("all_lbl_tryAgain")); + tryAgainBtn.setOnMouseClicked(( MouseEvent event) -> { + parentController.retryToFlash(); + }); + ((VBox)uiRoot).setAlignment(Pos.TOP_CENTER); + ((VBox)uiRoot).getChildren().add(3, tryAgainBtn); + } + + @Override + public void stop() { + logger.debug("CustomExecutableController.stop()"); + backgroundService.cancel(); + } +} \ No newline at end of file diff --git a/src/main/java/ecorp/easy/installer/controllers/stepControllers/CustomStepController.java b/src/main/java/ecorp/easy/installer/controllers/stepControllers/CustomStepController.java new file mode 100644 index 0000000000000000000000000000000000000000..fabe50a980c3458e1a547fc1b429de955dbfcdca --- /dev/null +++ b/src/main/java/ecorp/easy/installer/controllers/stepControllers/CustomStepController.java @@ -0,0 +1,139 @@ +/* + * Copyright 2019-2021 - ECORP SAS + + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ecorp.easy.installer.controllers.stepControllers; + + +import ecorp.easy.installer.graphics.FlashGlobalProgressManager; +import ecorp.easy.installer.graphics.Instruction; +import ecorp.easy.installer.models.steps.ICustomStep; +import ecorp.easy.installer.utils.UiUtils; +import java.net.URL; +import java.util.ArrayList; +import java.util.Locale; +import java.util.ResourceBundle; +import javafx.fxml.FXML; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; + +/** + * + * @author vincent Bourgmayer + */ +public class CustomStepController extends StepController{ + + protected final ResourceBundle IMG_BUNDLE = ResourceBundle.getBundle("instructions.imageName", + new Locale.Builder() + .setRegion("en") + .setLanguage("EN") + .setVariant(parentController.getDevice().getInternalCode()) + .build()); + + private int currentEmphasizedInstruction = 0; + private int instructionsCount; + + @FXML private VBox instructionsContainer; + @FXML private Label titleLbl; + @FXML private ImageView imgView; + // progress bar's node of global Flash's process : + @FXML HBox globalProgressIndicator; + private FlashGlobalProgressManager globalProgressMgr; + + + @Override + public void initialize(URL url, ResourceBundle rb) { + super.initialize(url, rb); + logger.debug("initialize customStep controller"); + + parentController.setNextButtonVisible(true); + titleLbl.setText(i18n.getString(step.getTitleKey() )); + if(step.getTitleIconName() != null){ + titleLbl.setGraphic(new ImageView(UiUtils.loadImage(step.getTitleIconName()))); + titleLbl.setGraphicTextGap(18); //set spacing between icon and text + titleLbl.setContentDisplay(ContentDisplay.LEFT); //set Icon to be displayed on left + } + + final ArrayList instructions = loadInstructions(); + instructions.get(currentEmphasizedInstruction).emphasize(); + instructionsContainer.getChildren().addAll(instructions); + displayInstructionImage(instructions.get(currentEmphasizedInstruction)); + + instructionsCount = instructions.size(); + + + globalProgressMgr = new FlashGlobalProgressManager(parentController.getThreadFactory().getStepsCount()); + for(int i = 0;i < step.getStepNumber(); i++){ + globalProgressMgr.updateProgression(); + } + globalProgressIndicator.getChildren().addAll(globalProgressMgr.getSegments()); + } + + + @Override + protected void onContinueClicked(){ + if(currentEmphasizedInstruction+1 == instructionsCount){ + UiUtils.buildFadeTransition(uiRoot, false); + super.onStepEnd(); + }else{ + final Instruction currentInstruction = (Instruction) instructionsContainer + .getChildren().get(1+currentEmphasizedInstruction++);//the +1 is to ignore the title + currentInstruction.trivialize(); + + final Instruction nextInstruction = (Instruction) instructionsContainer + .getChildren().get(1+currentEmphasizedInstruction); //the +1 is to ignore the title + nextInstruction.emphasize(); + + displayInstructionImage(nextInstruction); + } + } + + /** + * Create Instruction nodes with text key from step + */ + private ArrayList loadInstructions(){ + final ArrayList result = new ArrayList<>(); + + for(String key : step.getTextContentKeys()){ + String contentKey = "all_lbl_notImplemented"; //set default key + System.out.println("translation key: "+key); + if(i18n.containsKey(key)){ + contentKey = key; + } + result.add(new Instruction(key, i18n.getString(contentKey))); + } + return result; + } + + + /** + * Display Image corresponding to the current Instruction + * if there is one. In other way, it remove current image + * @param instruction + */ + private void displayInstructionImage(Instruction instruction){ + if(IMG_BUNDLE.containsKey(instruction.getKey())){ + imgView.setManaged(true); + imgView.setImage( + UiUtils.loadImage( IMG_BUNDLE.getString( instruction.getKey() ) ) ); + }else{ + imgView.setImage(null); + imgView.setManaged(false); + } + } +} \ No newline at end of file diff --git a/src/main/java/ecorp/easy/installer/controllers/subcontrollers/EAccountController.java b/src/main/java/ecorp/easy/installer/controllers/stepControllers/EAccountController.java similarity index 89% rename from src/main/java/ecorp/easy/installer/controllers/subcontrollers/EAccountController.java rename to src/main/java/ecorp/easy/installer/controllers/stepControllers/EAccountController.java index 8b5e9da73df8d1e8fc9ce781521cb1510931b819..87f3d81c3222e951b9a0933933483aa85939c34e 100644 --- a/src/main/java/ecorp/easy/installer/controllers/subcontrollers/EAccountController.java +++ b/src/main/java/ecorp/easy/installer/controllers/stepControllers/EAccountController.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 - ECORP SAS + * Copyright 2019-2021 - ECORP SAS * 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 @@ -14,15 +14,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package ecorp.easy.installer.controllers.subcontrollers; +package ecorp.easy.installer.controllers.stepControllers; -import ecorp.easy.installer.controllers.MainWindowController; import ecorp.easy.installer.tasks.AskAccountTask; import java.net.URL; import java.util.ResourceBundle; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; import java.util.regex.Pattern; import javafx.fxml.FXML; import javafx.scene.control.Button; @@ -33,20 +31,16 @@ import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * - * @author vincent + * @author vincent Bourgmayer * This is the controller for eAccount.fxml */ -public class EAccountController extends AbstractSubController{ - private static final Logger logger = LoggerFactory.getLogger(EAccountController.class); +public class EAccountController extends StepController{ private static final String MAIL_REGEX="[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"; private static final Pattern EMAIL_PATTERN = Pattern.compile(MAIL_REGEX); - @FXML VBox eAccountRoot; @FXML HBox alreadyAccountBox; @FXML HBox askAccountBox; @FXML Button checkMailBtn; @@ -59,11 +53,7 @@ public class EAccountController extends AbstractSubController{ @Override public void initialize(URL location, ResourceBundle resources){ super.initialize(location, resources); - } - - @Override - public void setParentController(MainWindowController parentController){ - super.setParentController(parentController); + parentController.disableNextButton(true); radioButton.setOnMouseClicked( (eh) -> { mailInput.requestFocus(); @@ -93,7 +83,6 @@ public class EAccountController extends AbstractSubController{ radioButton2.getLayoutX(), radioButton2.getLayoutY(), radioButton2.getLayoutX(), radioButton2.getLayoutY(), MouseButton.PRIMARY, 1, true, true, true, true, true, true, true, true, true, true, null)); }); - } @@ -109,12 +98,10 @@ public class EAccountController extends AbstractSubController{ mailInput.requestFocus(); break; case 0: - ExecutorService executorSrv = Executors.newSingleThreadExecutor( new ThreadFactory() { - public Thread newThread(Runnable r) { - Thread t = Executors.defaultThreadFactory().newThread(r); - t.setDaemon(true); - return t; - } + ExecutorService executorSrv = Executors.newSingleThreadExecutor((Runnable r) -> { + Thread t = Executors.defaultThreadFactory().newThread(r); + t.setDaemon(true); + return t; }); AskAccountTask askInvitationTask = new AskAccountTask(userInput, i18n.getString("askAccount_string")); askInvitationTask.setOnSucceeded(workerStateEvent -> { diff --git a/src/main/java/ecorp/easy/installer/controllers/stepControllers/ExecutableStepController.java b/src/main/java/ecorp/easy/installer/controllers/stepControllers/ExecutableStepController.java new file mode 100644 index 0000000000000000000000000000000000000000..a32e479e945bc0464a59c6dcfbaefec6d89e3fa0 --- /dev/null +++ b/src/main/java/ecorp/easy/installer/controllers/stepControllers/ExecutableStepController.java @@ -0,0 +1,68 @@ +/* + * Copyright 2019-2021 - ECORP SAS + + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ecorp.easy.installer.controllers.stepControllers; + +import ecorp.easy.installer.models.Command; +import ecorp.easy.installer.models.steps.IExecutableStep; +import ecorp.easy.installer.tasks.CommandRunnerService; +import java.net.URL; +import java.util.ResourceBundle; +import javafx.concurrent.Task; + +/** + * @TODO - add a error and cancellation listener on the Service + * @author vincent Bourgmayer + */ +public class ExecutableStepController extends StepController{ + + Task task; + CommandRunnerService backgroundService; + + @Override + public void initialize(URL arg0, ResourceBundle resources) { + super.initialize(arg0, resources); //To change body of generated methods, choose Tools | Templates. + + final Command cmd = step.getCommand(); + backgroundService = new CommandRunnerService(cmd); + + backgroundService.setOnSucceeded(eh->{ + boolean result = backgroundService.getValue(); + if(result) + onStepEnd(); + else{ + String errorMsgKey = cmd.getErrorMsg(); + if (errorMsgKey == null || errorMsgKey.isEmpty()){ + errorMsgKey = "script_error_unknown"; + } + displayError(errorMsgKey); + } + + }); + + backgroundService.start(); + } + + + protected void displayError(String errorMsgKey){ + //Show error UI and hide everything that should be hidden + //like restart btn, etc. + if(i18n.containsKey(errorMsgKey)){ + //Set text to a label + } + } + +} diff --git a/src/main/java/ecorp/easy/installer/controllers/stepControllers/LoadStepController.java b/src/main/java/ecorp/easy/installer/controllers/stepControllers/LoadStepController.java new file mode 100644 index 0000000000000000000000000000000000000000..256cc93229f2c08639b556ae44baac4724e5929f --- /dev/null +++ b/src/main/java/ecorp/easy/installer/controllers/stepControllers/LoadStepController.java @@ -0,0 +1,160 @@ +/* + * Copyright 2019-2021 - ECORP SAS + + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ecorp.easy.installer.controllers.stepControllers; + +import ecorp.easy.installer.controllers.LogController; +import static ecorp.easy.installer.controllers.stepControllers.StepController.parentController; +import ecorp.easy.installer.models.Command; +import ecorp.easy.installer.models.steps.LoadStep; +import ecorp.easy.installer.tasks.CommandRunnerService; +import ecorp.easy.installer.graphics.FlashGlobalProgressManager; +import ecorp.easy.installer.models.steps.IStep; +import java.net.URL; +import java.util.ResourceBundle; +import javafx.animation.KeyFrame; +import javafx.animation.KeyValue; +import javafx.animation.Timeline; +import javafx.fxml.FXML; +import javafx.geometry.Pos; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ProgressBar; +import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.util.Duration; + +/** + * + * @author vincent Bourgmayer + */ +public class LoadStepController extends StepController implements Stoppable{ + + @FXML private ProgressBar taskProgressBar; + @FXML private Label titleLbl; + @FXML private VBox instructionsContainer; + @FXML private ImageView imgView; + @FXML private LogController logRootController; //the field name must be "Controller" + + private Timeline pbTimeline; //progressBar Timeline + private CommandRunnerService service; + + // progress bar's node of global Flash's process : + @FXML HBox globalProgressIndicator; + private FlashGlobalProgressManager globalProgressMgr; + + @Override + public void initialize(URL url, ResourceBundle rb) { + super.initialize(url, rb); + + parentController.setNextButtonVisible(false); + + instructionsContainer.setManaged(false); + imgView.setManaged(false); + /*if(step.getTextContentKeys().isEmpty()){ + instructionsContainer.setVisible(false); + }*/ + + + if(i18n.containsKey(step.getTitleKey())){ + titleLbl.setText(i18n.getString(step.getTitleKey() ) ); + } + + + globalProgressMgr = new FlashGlobalProgressManager(parentController.getThreadFactory().getStepsCount()); + for(int i = 0;i < step.getStepNumber(); i++){ + globalProgressMgr.updateProgression(); + } + globalProgressIndicator.getChildren().addAll(globalProgressMgr.getSegments()); + + /** Prepare ProgressBar animation **/ + final int averageTime = step.getAverageTime(); + if(averageTime > 0){ + pbTimeline = new Timeline( + new KeyFrame(Duration.millis(0), new KeyValue(taskProgressBar.progressProperty(), 0.0) ), + new KeyFrame(Duration.millis(averageTime*1000.0), new KeyValue(taskProgressBar.progressProperty(), 1.0)) + ); + } + + /** Prepare Command execution **/ + final Command cmd = step.getCommand(); + service = new CommandRunnerService(cmd); + + service.setOnSucceeded(eh->{ + pbTimeline.stop(); + boolean result = service.getValue(); + + if(result){ + onStepEnd(); + }else{ + String errorMsgKey = cmd.getErrorMsg(); + if (errorMsgKey == null || errorMsgKey.isEmpty()){ + errorMsgKey = "script_error_unknown"; + } + displayError(errorMsgKey); + } + + }); + + service.setOnRunning(eh->{ + taskProgressBar.setProgress(0.0); //Reset to prevent showing last value + pbTimeline.playFromStart(); + }); + + + service.setOnCancelled(eh->{ + pbTimeline.stop(); + }); + + service.start(); + } + + + protected void displayError(String errorMsgKey){ + + parentController.setIsFlashed(false); + parentController.setCurrentStepKey(IStep.LAST_STEP_KEY); + parentController.resetNextButtonEventHandler(); + parentController.setNextButtonVisible(true); + + pbTimeline.stop(); + taskProgressBar.getStyleClass().add("errorBar"); + if(i18n.containsKey(errorMsgKey)){ + Label errorLbl = new Label(i18n.getString(errorMsgKey)); + ((VBox) uiRoot).getChildren().add(3, errorLbl); + }else{ + logger.error("Missing translation for error key: {}", errorMsgKey); + } + + logRootController.showSendLogBtn(); + + final Button tryAgainBtn = new Button(i18n.getString("all_lbl_tryAgain")); + tryAgainBtn.setOnMouseClicked(( MouseEvent event) -> { + parentController.retryToFlash(); + }); + ((VBox)uiRoot).setAlignment(Pos.TOP_CENTER); + ((VBox)uiRoot).getChildren().add(4,tryAgainBtn); + + } + + @Override + public void stop() { + logger.debug("LoadStepController.stop()"); + service.cancel(); + } +} diff --git a/src/main/java/ecorp/easy/installer/controllers/stepControllers/StepController.java b/src/main/java/ecorp/easy/installer/controllers/stepControllers/StepController.java new file mode 100644 index 0000000000000000000000000000000000000000..827d51b3db92dee51004fccc3e145cf3d385626b --- /dev/null +++ b/src/main/java/ecorp/easy/installer/controllers/stepControllers/StepController.java @@ -0,0 +1,98 @@ +/* + * Copyright 2019-2021 - ECORP SAS + + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ecorp.easy.installer.controllers.stepControllers; + +import ecorp.easy.installer.controllers.MainWindowController; +import ecorp.easy.installer.models.steps.IStep; +import java.net.URL; +import java.util.ResourceBundle; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.Node; +import javafx.scene.input.MouseEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * + * @author vincent Bourgmayer + * @param implementation of IStep interface + */ +public class StepController implements Initializable{ + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + protected static MainWindowController parentController; + + @FXML Node uiRoot; + protected ResourceBundle i18n; + protected S step; + + @Override + public void initialize(URL url, ResourceBundle rb) { + i18n = rb; + + final String stepKey = parentController.getCurrentStepKey(); + System.out.println("stepKey = "+stepKey); + + step = (S) parentController.getThreadFactory().getFlashMould().getSteps().get(stepKey); + + parentController.setNextButtonOnClickListener( ( MouseEvent event) -> { + if(event.getEventType().equals(MouseEvent.MOUSE_CLICKED)){ + onContinueClicked(); + } + }); + } + + /** + * /!\ it must be called Before the Initialize() method!! + * @param parentController + */ + public static void setParentController(MainWindowController parentController) { + StepController.parentController = parentController; + } + + /** + * Behaviour for when user click on "continue button" + * defined mostly for subclass overriding + */ + protected void onContinueClicked(){ + onStepEnd(); + } + + /** + * Code executed when the step is over + * Mainly load the next step + * apply UI effect like fade in/out + */ + protected void onStepEnd(){ + System.out.println("onStepEnd() load: "+step.getNextStepKey()); + parentController.setCurrentStepKey(step.getNextStepKey()); + if(step.getNextStepKey().equals(IStep.LAST_STEP_KEY)){ + parentController.setIsFlashed(true); + } + parentController.loadSubScene(); + + + //Question is: Should I call this only if we are at the last step + //Then How to check that from here ? + //Or should I always reset behaviour.. As It is always override by new step + //this looks like useless call each time except for the latest one... + //Answer: this can go like this for now, and be handled later in the refactoring process + //@Todo + parentController.resetNextButtonEventHandler(); + } +} diff --git a/src/main/java/ecorp/easy/installer/controllers/stepControllers/Stoppable.java b/src/main/java/ecorp/easy/installer/controllers/stepControllers/Stoppable.java new file mode 100644 index 0000000000000000000000000000000000000000..68ef4c0fbc7a27682347ecc1fe26db9d84002cd1 --- /dev/null +++ b/src/main/java/ecorp/easy/installer/controllers/stepControllers/Stoppable.java @@ -0,0 +1,13 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Interface.java to edit this template + */ +package ecorp.easy.installer.controllers.stepControllers; + +/** + * + * @author vincent + */ +public interface Stoppable { + public void stop(); +} diff --git a/src/main/java/ecorp/easy/installer/controllers/subcontrollers/UnlockOemController.java b/src/main/java/ecorp/easy/installer/controllers/stepControllers/UnlockOemController.java similarity index 80% rename from src/main/java/ecorp/easy/installer/controllers/subcontrollers/UnlockOemController.java rename to src/main/java/ecorp/easy/installer/controllers/stepControllers/UnlockOemController.java index 87a0a666b08256d0f6a6a2e93f611ae7a2c110ab..cda2c2fd4bfa40da305d6e11aa179e8c8efcae61 100644 --- a/src/main/java/ecorp/easy/installer/controllers/subcontrollers/UnlockOemController.java +++ b/src/main/java/ecorp/easy/installer/controllers/stepControllers/UnlockOemController.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 - ECORP SAS + * Copyright 2019-2021 - ECORP SAS * 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 @@ -14,9 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package ecorp.easy.installer.controllers.subcontrollers; +package ecorp.easy.installer.controllers.stepControllers; + -import ecorp.easy.installer.controllers.MainWindowController; import ecorp.easy.installer.graphics.FlashGlobalProgressManager; import java.net.URL; import java.util.ResourceBundle; @@ -30,9 +30,9 @@ import javafx.scene.layout.HBox; * This controller is for UI about unlocking OEM on the stock ROM * It's main goal is to allow to get extra code from website or API * - * @author vincent + * @author vincent Bourgmayer */ -public class UnlockOemController extends AbstractSubController{ +public class UnlockOemController extends StepController{ @FXML Label instruction; @FXML Hyperlink link; @@ -44,13 +44,8 @@ public class UnlockOemController extends AbstractSubController{ public void initialize(URL location, ResourceBundle resources){ super.initialize(location, resources); link.setBorder(Border.EMPTY); - } - - @Override - public void setParentController(MainWindowController parentController){ - super.setParentController(parentController); - parentController.setNextButtonVisible(true); + parentController.setNextButtonVisible(true); globalProgressMgr = new FlashGlobalProgressManager( parentController.getThreadFactory().getStepsCount() ); globalProgressIndicator.getChildren().addAll(globalProgressMgr.getSegments()); globalProgressMgr.updateProgression(); diff --git a/src/main/java/ecorp/easy/installer/controllers/subcontrollers/DeviceDetectedController.java b/src/main/java/ecorp/easy/installer/controllers/subcontrollers/DeviceDetectedController.java index 5b69d8769d41dbf86999a13ca3b17b08ddbebf8d..5ddb79fa18f1ea1afab76fa05938430ab1deacb5 100644 --- a/src/main/java/ecorp/easy/installer/controllers/subcontrollers/DeviceDetectedController.java +++ b/src/main/java/ecorp/easy/installer/controllers/subcontrollers/DeviceDetectedController.java @@ -18,12 +18,12 @@ package ecorp.easy.installer.controllers.subcontrollers; import ecorp.easy.installer.AppConstants; +import ecorp.easy.installer.helpers.DeviceHelper; import ecorp.easy.installer.exceptions.TooManyDevicesException; import ecorp.easy.installer.models.Phone; import ecorp.easy.installer.tasks.DeviceDetectionTask; import ecorp.easy.installer.utils.UiUtils; import java.net.URL; -import java.util.Arrays; import java.util.ResourceBundle; import javafx.concurrent.WorkerStateEvent; import javafx.fxml.FXML; @@ -128,8 +128,10 @@ public class DeviceDetectedController extends AbstractSubController{ }else{ detectionMsg.setText(String.format(i18n.getString("detect_lbl_compatibleDeviceFound"), model)); if(parentController != null){ + phone.setInternalCode(DeviceHelper.getDeviceInternalcode(phone.getAdbDevice())); + AppConstants.setDeviceModel(phone.getAdbDevice()); //this line must be before the "parentController.setDevice(phone). If it's not the case, + //the AppConstants.getSourceFolder() won't include the device model's name parentController.setDevice(phone); - AppConstants.setDeviceModel(phone.getAdbDevice()); //@TODO remove this line ? parentController.disableNextButton(false); } } diff --git a/src/main/java/ecorp/easy/installer/controllers/subcontrollers/FlashSceneController.java b/src/main/java/ecorp/easy/installer/controllers/subcontrollers/FlashSceneController.java deleted file mode 100644 index e92f5d6ee27dd7d0af3c4e6aefaf6fd5face6234..0000000000000000000000000000000000000000 --- a/src/main/java/ecorp/easy/installer/controllers/subcontrollers/FlashSceneController.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright 2019-2020 - ECORP SAS - - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package ecorp.easy.installer.controllers.subcontrollers; - -import ch.qos.logback.classic.LoggerContext; -import ecorp.easy.installer.AppConstants; -import ecorp.easy.installer.controllers.MainWindowController; -import ecorp.easy.installer.graphics.FlashGlobalProgressManager; -import ecorp.easy.installer.graphics.Instruction; -import ecorp.easy.installer.helpers.DeviceHelper; -import ecorp.easy.installer.logger.GUIAppender; -import ecorp.easy.installer.logger.LogPathPropertyDefiner; -import ecorp.easy.installer.models.DataBundle; -import ecorp.easy.installer.threads.FlashThread; -import ecorp.easy.installer.tasks.UploadToEcloudTask; -import ecorp.easy.installer.utils.IFlashHandler; -import ecorp.easy.installer.utils.UiUtils; - -import java.net.URL; -import java.util.List; -import java.util.Locale; -import java.util.ResourceBundle; -import javafx.animation.FadeTransition; -import javafx.animation.KeyFrame; -import javafx.animation.KeyValue; -import javafx.animation.Timeline; -import javafx.collections.ObservableList; -import javafx.fxml.FXML; -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.ContentDisplay; -import javafx.scene.control.Label; -import javafx.scene.control.ProgressBar; -import javafx.scene.control.ScrollPane; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.HBox; -import javafx.scene.layout.VBox; -import javafx.scene.text.TextFlow; -import javafx.util.Duration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * FXML Controller class - * - * @author Vincent Bourgmayer - * @author Ingo - */ -public class FlashSceneController extends AbstractSubSteppedController implements IFlashHandler { - //Current step UI element - @FXML VBox flashSceneRoot; - @FXML ProgressBar loadStepProgressIndicator; //'load' step type only - @FXML VBox instructionsFlow; - @FXML Label stepTitleLabel; - @FXML ImageView instructionImage; - @FXML HBox instructionsContainer; - - // progress bar's node of global Flash's process : - @FXML HBox globalProgressIndicator; - private FlashGlobalProgressManager globalProgressMgr; - - // node relative to Log - @FXML VBox instructionsVBox; - @FXML ScrollPane logScrollPane; - @FXML TextFlow logFlow; - @FXML Button showHideLogBtn; - @FXML Button sendLogBtn; - - private Timeline timeline; //this animate the progression in ProgressBar - private boolean stopped = false; //determine if the process has been stopped (due to error or normal ending) - private List instructionsKey; //Contains the different instruction that have to be currently displayed - ResourceBundle instructionsImagesBundle; //Give access to image to loads with instructionsKey - private FlashThread thread; - private Object pauseLock; //lock used for pausing the FlashThread - private final static Logger logger = LoggerFactory.getLogger(FlashSceneController.class); - - @Override - public void initialize(URL location, ResourceBundle resources) { - super.initialize(location, resources); - logger.debug("Initialize FlashSceneController.java"); - logFlow.heightProperty().addListener(observable -> logScrollPane.setVvalue(1.0)); - UiUtils.hideNode(logScrollPane); - UiUtils.hideNode(sendLogBtn); - stepTitleLabel.setGraphicTextGap(18); - stepTitleLabel.setContentDisplay(ContentDisplay.LEFT); - } - - /** - * @inheritDoc - * @param parentController - */ - @Override - public void setParentController(MainWindowController parentController) { - super.setParentController(parentController); //To change body of generated methods, choose Tools | Templates. - - //can use Properties instead of ResourceBundle but ResourceBundle use default file for missing value - //The only problem is that I can't specify any version without region and language... - instructionsImagesBundle = ResourceBundle.getBundle("instructions.imageName", - new Locale.Builder() - .setRegion("en") - .setLanguage("EN") - .setVariant(DeviceHelper.getDeviceInternalcode(parentController.getDevice().getAdbDevice())) - .build()); - pauseLock = new Object(); //This is object used to unpause a thread - - thread = parentController.getThreadFactory().buildFlashThread(this, pauseLock); - if(thread!= null){ - thread.setDaemon(true); - //@TODO find another way to get the step number as yaml file can contains step for issue. By example - //if script got issue, then load script 45 if success load script 2. - //Then the stepSize won't fit with the real step that the user must perform - globalProgressMgr = new FlashGlobalProgressManager(thread.getCommandsSize()); - globalProgressIndicator.getChildren().addAll(globalProgressMgr.getSegments()); - - thread.start(); - } - } - - /** - * Add a new instruction to display without clearing the precedent - * @param instruction the instruction to add - */ - public void addInstructionToDisplay(String instructionKey){ - String effectiveTxtKey = "all_lbl_missingTranslation"; - if(i18n.containsKey(instructionKey)){ - effectiveTxtKey = instructionKey; - } - Instruction instruction = new Instruction(effectiveTxtKey, i18n.getString(effectiveTxtKey)); - - //instruction.setWrapText(true); //make text resize if longer than width - instruction.maxWidthProperty().bind(instructionsFlow.widthProperty()); //Set max Width to its parent width - instructionsFlow.getChildren().add(instruction); - } - - /** - * UI changes at beginning of a new step - * @TODO: move part of code relative to 'action' step to 'setActionStepUI()', and 'load' type to 'setLoadStepUI()' - * @param db - */ - @Override - public void onStepStart(DataBundle db) { - logger.info("onStepStart()"); - if(db == null)return; - - //close the timer of a loadStepType - if(timeline != null){ - timeline.stop(); - timeline = null; - } - - //Update the progressBar of the global process - globalProgressMgr.updateProgression(); - - //Update instruction title - final String title = db.getString("stepTitle"); - logger.debug("--Title {}", title); - - //Get Type of step ("action" or "load") - final String stepType = db.getString("stepType"); - logger.debug("--Type: {}", stepType); - switch (stepType) { - case AppConstants.USER_ACTION_KEY: //@deprecated - case "custom": - case "custom-executable": - instructionsContainer.setOpacity(0.0); - updateInstructions(title, db.getList("stepInstructions", "String") ); - displayActionStepType(db); - UiUtils.buildFadeTransition(instructionsContainer, false).play(); - break; - case AppConstants.LOAD_KEY: - instructionsContainer.setOpacity(0.0); - updateInstructions(title, db.getList("stepInstructions", "String")); - displayLoadStepType(db); - UiUtils.buildFadeTransition(instructionsContainer, false).play(); - break; - case AppConstants.ASK_ACCOUNT_KEY: - displaySpecificView("6-2-eAccount.fxml"); - break; - case AppConstants.UNLOCK_OEM_KEY: - displaySpecificView("6-3-unlockOEM.fxml"); - break; - default: - logger.warn("Try to load invalid step's type"); - break; - } - } - - /** - * Update text and images instructions - * @param instructionsKey - */ - private void updateInstructions(final String title, final List instructionsKey){ - if(title != null){ - stepTitleLabel.setText(i18n.getString(title)); - } - - //update instructions - if(instructionsKey == null || instructionsKey.isEmpty()) return; - this.instructionsKey = instructionsKey; - - //Remove precedent instruction - instructionsFlow.getChildren().clear(); - - //Add new instructions - instructionsKey.forEach((instruction) -> { - addInstructionToDisplay(instruction); - }); - - //Update instruction image - String instructionImgName = instructionsKey.get(0); - if(instructionsImagesBundle.containsKey(instructionImgName)){ - try{ - this.instructionImage.setImage(new Image(getClass().getResourceAsStream("/images/"+instructionsImagesBundle.getString(instructionImgName)))); - }catch (Exception e) { - logger.warn("onStepStart(), image key = {}, error = {}", instructionImgName, e.toString()); - this.instructionImage.setImage(null); - } - }else{ - this.instructionImage.setImage(null); - } - } - - - - - /** - * Display the specific interface for - * Note: This could be replace by a call to parentController.loadSubUI("6-2-eAccount.fxml") - * but how to reset current ui to this one after ? - */ - private void displaySpecificView(final String fxmlName){ - //Masque previous UI - UiUtils.hideNode(flashSceneRoot); - //Affiche the new One - final Node tempRoot = parentController.loadSubUI(fxmlName, null); - - //play fade out animation - tempRoot.setOpacity(0.0); - UiUtils.buildFadeTransition(tempRoot,false).play(); - - //Define what happened when user click on continue on this specific view - final String tempRootId = tempRoot.getId(); - parentController.setNextButtonOnClickListener(( MouseEvent event) -> { - //this is where I have to put fade in transition - final FadeTransition fadeInAnimation = UiUtils.buildFadeTransition(tempRoot,true); - fadeInAnimation.setOnFinished(t->{ - parentController.resetNextButtonEventHandler(); - parentController.removeNodeFromRoot(tempRootId); - parentController.showCurrentSubRoot(); - parentController.setNextButtonVisible(false); - synchronized (pauseLock) { - pauseLock.notify(); - } - }); - - fadeInAnimation.play(); - }); - } - - /** - * Set UI for "load" steps - * @param db - */ - private void displayLoadStepType(DataBundle db){ - logger.info("onLoadStepType()"); - UiUtils.hideNode(instructionsFlow); //put it invisible instead ? - instructionsVBox.setAlignment(Pos.TOP_CENTER); - parentController.setNextButtonVisible(false); - int averageTime = db.getInt("averageTime"); - logger.debug("averageTime = {} ", averageTime); - if(averageTime > -1){ //Or > 0 ? - timeline = new Timeline( - new KeyFrame(Duration.millis(0), new KeyValue(loadStepProgressIndicator.progressProperty(), 0.0) ), - new KeyFrame(Duration.millis(averageTime*1000.0), new KeyValue(loadStepProgressIndicator.progressProperty(), 1.0)) - ); - timeline.playFromStart(); - loadStepProgressIndicator.setProgress(0.0); //Reset to prevent showing last value - UiUtils.showNode(loadStepProgressIndicator); - } - stepTitleLabel.setGraphic(null); - } - - /** - * Set UI for "action" steps. - * @param db - */ - private void displayActionStepType(DataBundle db){ - //emphasize first Label - instructionsVBox.setAlignment(Pos.TOP_LEFT); - currentSubStepId = 0; //reset the value - - ((Instruction)instructionsFlow.getChildren().get(0)).emphasize(); - - parentController.setNextButtonVisible((instructionsFlow.getChildren().size() >1)); - - parentController.setNextButtonOnClickListener((MouseEvent event)->{ - final int instructionsCount = instructionsFlow.getChildren().size(); - - if ( !db.getBoolean("hasScript") - && currentSubStepId == (instructionsCount-1) - && !stopped ) - { - synchronized (pauseLock) { pauseLock.notify(); } - }else{ - onNextButtonClicked(); - } - //If there is a script and this instruction before the last one - if( db.getBoolean("hasScript") - &¤tSubStepId == (instructionsCount-2) - && !stopped ) - { - //hide the button to prevent clicking before the end of the full process - parentController.setNextButtonVisible(false); - }// If there is no script and it's the last instruction: notify flashThread - - ++currentSubStepId; - }); - - //Hide progress Indicator - UiUtils.hideNode(loadStepProgressIndicator); - UiUtils.showNode(instructionsFlow); - - //Set Title Icon if defined - String titleIconName = db.getString("titleIconName"); - if(titleIconName != null){ - stepTitleLabel.setGraphic(new ImageView(UiUtils.loadImage(titleIconName))); - } - } - - - /** - * UI modification when an error is detected during the process - * @param db datas to update the UI. Currently not used - */ - @Override - public void onFlashError(DataBundle db) { - logger.warn("onFlashError()"); - String errorMsgKey = db.getString("errorMsgKey"); - - if(errorMsgKey == null || errorMsgKey.isEmpty() || !i18n.containsKey(errorMsgKey)) - errorMsgKey ="script_error_unknown"; - stepTitleLabel.setText(i18n.getString(errorMsgKey)); - - logger.debug("errorMsgKey = {}", errorMsgKey); - - UiUtils.hideNode(instructionsFlow); - UiUtils.showNode(sendLogBtn); - - Button tryAgainBtn = new Button(i18n.getString("all_lbl_tryAgain")); - tryAgainBtn.setOnMouseClicked(( MouseEvent event) -> { - parentController.retryToFlash(); - }); - instructionsVBox.setAlignment(Pos.TOP_CENTER); - instructionsVBox.getChildren().add(tryAgainBtn); - } - - /** - * Behaviour of the UI when the flash process is stop. It also cancel the TimerTask of 'load' type task. - * @param db bundle containing element to update the UI. - */ - @Override - public void onFlashStop(DataBundle db) { - logger.info("onFlashStop()"); - if(timeline != null){ - timeline.stop(); - timeline = null; - } - stopped = true; - parentController.resetNextButtonEventHandler(); - parentController.setNextButtonVisible(true); - final boolean isFlashed = db.getBoolean("isFlashed"); - parentController.setIsFlashed(isFlashed); - //if success, move automaticcaly to the next step - if(isFlashed){ - parentController.loadSubScene(); - } - } - - /** - * enable/disable log displaying - */ - public void showHideLog(){ - ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); - GUIAppender appender = (GUIAppender) rootLogger.getAppender("GUI"); - - final String text = showHideLogBtn.getText(); - if(text.equals(">")){ - showHideLogBtn.setText("V"); - UiUtils.hideNode(logScrollPane); - logFlow.getChildren().clear(); - appender.setContainer(null); - }else{ - showHideLogBtn.setText(">"); - UiUtils.showNode(logScrollPane); - logFlow.getChildren().addAll(appender.getLogsList()); - appender.setContainer(logFlow); - } - } - - /** - * Send log to support, in special ecloud.global folder - * @return - */ - public boolean sendLogToSupport(){ - if(thread != null){ - String filePath = LogPathPropertyDefiner.getLogFilePath(); - if(filePath != null){ - - UploadToEcloudTask uploadTask = new UploadToEcloudTask(AppConstants.LOG_STORAGE_URL, filePath); - uploadTask.setOnSucceeded(eh -> { - if( (Boolean) eh.getSource().getValue() ){ //if success - sendLogBtn.setDisable(true); - sendLogBtn.setText(i18n.getString("install_btn_sendLogSuccess")); - logger.info("sendLogToSupport(), sending log: success"); - } - else{ - sendLogBtn.setText(i18n.getString("install_btn_sendLogAgain")); - logger.warn("sendLogToSupport(), sending log: failure"); - } - }); - - uploadTask.setOnFailed(eh->{ - sendLogBtn.setText(i18n.getString("install_btn_sendLogAgain")); - logger.warn("sendLogToSupport(), sending log: failure, error = {}",eh.getSource().getException().toString() ); - }); - - Thread uploadTaskThread = new Thread(uploadTask); - uploadTaskThread.setDaemon(true); - uploadTaskThread.start(); - } - } - return false; - } - - /** - * The new behaviour of the parentController's nextButton - */ - @Override - protected void onNextButtonClicked() { - //Si currenttype est action - final ObservableList children = instructionsFlow.getChildren(); - final int instructionsNumber = children.size(); - - /* - check that there is more than 1 instruction. (children's size is > 1). - Then if it's not the case, just return. - This behaviour is only expected when there is more than 2 instructions. - */ - if(instructionsNumber <= 1) return; - - /* - No need to check that currentSubStepId isn't equal or over size - This won't happens because the next button should be hidden at the last instruction - */ - - //get CurrentLabel - Instruction currentInstruction = (Instruction) children.get(currentSubStepId); - //get previousLabel - Instruction nextInstruction = (Instruction) children.get(currentSubStepId+1); - - //Update the image using instruction key cod - final String nextTxtKey = nextInstruction.getKey(); - if(instructionsImagesBundle.containsKey(nextTxtKey) ){ - instructionImage.setImage(UiUtils.loadImage(instructionsImagesBundle.getString(nextTxtKey))); - }else{ - instructionImage.setImage(null); - } - //Deemphase previous instruction and emphasize new current one - if(currentSubStepId < instructionsNumber-1){ - currentInstruction.trivialize(); - nextInstruction.emphasize(); - } - } -} \ No newline at end of file diff --git a/src/main/java/ecorp/easy/installer/models/Command.java b/src/main/java/ecorp/easy/installer/models/Command.java index 6a24cbde10e6222f8f618b7315bd3f9094076c27..c9f32aaab09772e249a70f05fe5b15988a48aca9 100644 --- a/src/main/java/ecorp/easy/installer/models/Command.java +++ b/src/main/java/ecorp/easy/installer/models/Command.java @@ -17,10 +17,6 @@ package ecorp.easy.installer.models; import ecorp.easy.installer.AppConstants; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; @@ -30,229 +26,124 @@ import org.slf4j.LoggerFactory; * @author Vincent Bourgmayer */ public class Command { - String command; //String containing command to perform - volatile boolean cancelled = false; //boolean to tell if it is cancelled or not - Map parameters; //Parameters to add to the command - private int exitValue; //the exit value of the script. - private String shellOutput; //The shell text output of the execution of the script - Process pc; //Process which run the command - Step step; //Object which contain data about the command like next step, ... private final static Logger logger = LoggerFactory.getLogger(Command.class); - - /** - * Constructor for instance in context of FlashThread - * @param runScriptCmd - * @param step - */ - public Command(String runScriptCmd, Step step){ - this.step = step; - this.command = runScriptCmd+step.getScript(); - this.parameters = step.getParameters(); - } - - - /** - * Constructor for command object in context of PreparationThread - * @param command - */ - public Command(String command){ - this.command = command; - this.parameters = new HashMap<>(); - } + private final String commandBase; //String containing command to perform + private String outputKey; //The variable key to use to associate output value + private final static HashMap COMMON_PARAMS = new HashMap<>(); + private Map parameters; //Parameters to add to the command + private Map okCodes; + private Map koCodes; + /** - * Update a parameter only if already exist - * @param key the key of parameter to update - * @param value the new value of the param - * @return false if param isn't already in the map + * Instanciate a command object + * @param commandBase */ - public boolean updateParameter(String key, String value){ - if(parameters.containsKey(key)){ - this.parameters.put(key, value); - return true; - } - return false; + public Command(String commandBase){ + this.commandBase = commandBase; + this.outputKey = ""; + this.parameters = new HashMap<>(); + this.okCodes = new HashMap<>(); + this.koCodes = new HashMap<>(); } /** - * Get the currend command that will be run in a shell - * note: without it's parameters! - * @return + * Build a command instance with an already existing set of parameters + * @param commandBase + * @param parameters */ - public String getCommand() { - return command; - } - - public Map getParameters() { - return parameters; + public Command(String commandBase, Map parameters){ + this.commandBase = commandBase; + this.parameters = parameters; + this.outputKey = ""; + this.okCodes = new HashMap<>(); + this.koCodes = new HashMap<>(); } /** - * Add a new parameter for the current command + * Map.put(key, value) a new parameter for the current command * @param key the key to identify the parameter in the list * @param value the value of the parameter */ public void addParameter(String key, String value){ this.parameters.put(key, value); } - - /** - * @return the value returned by the execution of the current command - */ - public int getExitValue() { - return exitValue; - } - /** - * Get the output of the execution of the current command - * @return could return null - */ - public String getShellOutput() { - return shellOutput; - } - /** - * Build the string that contain full command with its parameters - * @return String command and its parameters - */ - public String[] getFinalCmd(){ - StringBuilder sb = new StringBuilder(command); - if(parameters != null){ - parameters.values().forEach((param) -> { - sb.append(" ").append(param); - }); - } - - logger.debug("getFinalCmd(), Splitted command = {}", sb.toString()); - return sb.toString().split(" "); + + + /* Getter & setters */ + public String getCommandBase() { + return commandBase; } /** - * This is the method which execute the current command - * @throws IOException - * @throws InterruptedException + * Return the key to store output + * @return */ - public void execAndReadOutput() throws IOException, InterruptedException{ - ProcessBuilder pb; - if(AppConstants.isWindowsOs()) - { - //@TODO REWRITE THIS PART AND MOVE IT TO getFinalCmd() - final int cmdArraySize = parameters.size()+3; - String[] commandArray= new String[cmdArraySize]; - - int cmdArrayIndex = 0; - commandArray[cmdArrayIndex++] = "cmd.exe"; - commandArray[cmdArrayIndex++] = "/c"; - - commandArray[cmdArrayIndex++] = "\"\""+command+(parameters.isEmpty() ? "\"\"":"\""); - //if empty param: commandArray[2] = ""scriptFolder/scriptname.bat"" - //else : commandArray[2] = ""scriptFolder/scriptname.bat" - - for(String param : parameters.values()){ - String quotedParam = "\""+param+"\""; - //If this is the last parameter in the list - if(cmdArrayIndex == cmdArraySize-1){ - quotedParam += "\""; //add a closing <<">> - } - //add the quoted param in the cmdArray - commandArray[cmdArrayIndex++] = quotedParam; - } - pb = new ProcessBuilder(commandArray); - logger.debug("command: {}", pb.command()); - }else{ - pb = new ProcessBuilder(getFinalCmd()); - } - - pb.redirectErrorStream(true); - pc= pb.start(); - logger.info("Command's Process started"); - InputStream stdout = pc.getInputStream(); - InputStreamReader isr = new InputStreamReader (stdout); - BufferedReader br = new BufferedReader(isr); - - StringBuilder sb = new StringBuilder(); - String line; - try{ - while(pc.isAlive() && !cancelled){ - line = br.readLine(); - if( line != null && !line.equals("null") ){ - sb.append("\n\n").append(line); - logger.debug("\n (debug)"+line); - } - } - this.exitValue = pc.exitValue(); - }catch(IOException e){ - logger.error("execAndReadOutput(), error = {}", e.toString() ); - this.exitValue = -1; - } - br.close(); - isr.close(); - - this.shellOutput = sb.toString(); - if(pc.isAlive()) - pc.destroy(); + public String getOutputKey() { + return outputKey; } - - public void cancel(){ - logger.info("cancel()"); - this.cancelled = true; - if(pc != null && pc.isAlive()) - pc.destroy(); - } - /** - * Return the new values for the UI but can be null if there is nothing to change in UI - * @return null or StepUI instance + * Define the key to store output + * @param outputKey */ - public StepUi getNewUIValues(){ - return step.getUI(); + public void setOutputKey(String outputKey) { + this.outputKey = outputKey; } - + /** - * Retourne the key define for output of script - * the value is stored in this class property: shellOutput. - * @return String can be null + * Get map of parameters < key, value > + * @return */ - public String getOutputKey(){ - return this.step.getOutput(); + public Map getParameters() { + return parameters; } /** - * Return the message associated with the exit Value - * @return String can be null if exitValue is not define for this step + * Set the map of parameters < key, value > + * @param parameters */ - public String getErrorMsg(){ - if(step.getKoCode() == null) return null; - return this.step.getKoCode().getOrDefault(this.exitValue, null); + public void setParameters(Map parameters) { + this.parameters = parameters; } /** - * Return true if the execution of the command succeeded + * get map of success code < int, string> + * where int is the result code + * and the string the text associated * @return */ - public boolean isSuccess(){ - if(step.getOkCode() == null ) return (exitValue == 0); + public Map getOkCodes() { + return okCodes; + } + + public void setOkCodes(Map okCodes) { + this.okCodes = okCodes; + } - return this.step.getOkCode().keySet().contains(this.exitValue); + public Map getKoCodes() { + return koCodes; + } + + public void setKoCodes(Map koCodes) { + this.koCodes = koCodes; } /** - * Return the key of the next step + * Get list of parameters available for every command * @return */ - public String getNextCommandKey(){ - if(isSuccess() && !cancelled){ - return step.getAfterSuccess(); - } - return step.getAfterFail(); + public static HashMap getCOMMON_PARAMS() { + return COMMON_PARAMS; } - /** - * tell if the command has a script registered - * @return false if step's script is null else return true + * Return the message associated with the exit Value + * @param exitValue + * @return String can be null if exitValue is not define for this step */ - public boolean hasScript(){ - return (step.getScript() != null); + public String getErrorMsg(int exitValue){ + return this.koCodes.getOrDefault(exitValue, null); } -} +} \ No newline at end of file diff --git a/src/main/java/ecorp/easy/installer/models/Step.java b/src/main/java/ecorp/easy/installer/models/Step.java index 4014c0fe44d72440804440f4db9f897068df4250..1965ed978c2495357cd59c863193f0c1c7f61812 100644 --- a/src/main/java/ecorp/easy/installer/models/Step.java +++ b/src/main/java/ecorp/easy/installer/models/Step.java @@ -14,8 +14,6 @@ */ package ecorp.easy.installer.models; -import java.util.LinkedHashMap; -import java.util.Map; /** * This class encapsulate data about a step in the flashing process @@ -24,14 +22,10 @@ import java.util.Map; */ public class Step { private StepUi ui; //Datas about user interface - private String script; //script's file script - private String output; //Key of output to store as common parameter + private Command command; private String afterSuccess; // index of next script if succeed private String afterFail; //index of next script if failure - private Map okCode; - private Map koCode; - private Map parameters; //parameters to add to the script //@TODO think if is possible to set only one map in Thread instance instead of in each Step. - + /** * Default constructor */ @@ -43,69 +37,18 @@ public class Step { * @param s the step to copy */ public Step (Step s){ - this.script = s.script; afterSuccess = s.afterSuccess; afterFail = s.afterFail; ui = s.ui; - okCode = s.okCode; - koCode = s.koCode; - output = s.output; - if(s.parameters != null){ - parameters = new LinkedHashMap<>(); - for(Map.Entry param : s.parameters.entrySet()){ - parameters.put(param.getKey(), param.getValue()); - } - } - } - - /** - * Get the name of the script to run - * @return can be null - */ - public String getScript() { - return script; - } - - /** - * Set the name of the script to execute into this step - * @param name - */ - public void setScript(String name) { - this.script = name; - } - - /** - * In some particular case, a step can produce an output - * that could be use later. This is the "output" of the step - * @return can be null - */ - public String getOutput() { - return output; + this.command = s.getCommand(); } - /** - * Set the output of the step - * @param output - */ - public void setOutput(String output) { - this.output = output; + public Command getCommand() { + return command; } - /** - * List of parameters that should be integrated in - * the command to execute the step - * @return - */ - public Map getParameters() { - return parameters; - } - - /** - * Replace the parameter list by a new one - * @param parameters - */ - public void setParameters(LinkedHashMap parameters) { - this.parameters = parameters; + public void setCommand(Command command) { + this.command = command; } /** @@ -143,41 +86,6 @@ public class Step { public void setAfterFail(String afterFail) { this.afterFail = afterFail; } - - /** - * Get the list of result code that correspond - * to a success - * @return can be null if not set - */ - public Map getOkCode() { - return okCode; - } - - /** - * Define the list of success result's code - * @param okCode - */ - public void setOkCode(Map okCode) { - this.okCode = okCode; - } - - /** - * Get the list of result code that - * corresponds to a failure - * @return can be null if not set - */ - public Map getKoCode() { - return koCode; - } - - /** - * Set the list of result's codes that correspond - * to a failure - * @param koCode - */ - public void setKoCode(Map koCode) { - this.koCode = koCode; - } /** * Get the StepUI object which encapsulate new value for UI. diff --git a/src/main/java/ecorp/easy/installer/tasks/CommandExecutionTask.java b/src/main/java/ecorp/easy/installer/tasks/CommandExecutionTask.java new file mode 100644 index 0000000000000000000000000000000000000000..19933eb14ff6fed1a6894fcaf012903d8f278903 --- /dev/null +++ b/src/main/java/ecorp/easy/installer/tasks/CommandExecutionTask.java @@ -0,0 +1,143 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package ecorp.easy.installer.tasks; + +import ecorp.easy.installer.AppConstants; +import ecorp.easy.installer.models.Command; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import javafx.concurrent.Task; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The

is present for eventual subclass. + * It is useless for CommandExecutionTask itself + * but required for DeviceDetectionTask by example + * @author vincent + */ +public class CommandExecutionTask

extends Task

{ + protected final static Logger logger = LoggerFactory.getLogger(CommandExecutionTask.class); + final protected Command command; //The command to run + protected String shellOutput; //The stdout of the process + protected int exitCode; //The result code of the command + + /** + * Instanciate a CommandExecutionTask + * @param command the Command to execute + */ + public CommandExecutionTask(Command command){ + this.command = command; + } + + /** + * run the command + * @return always null because "P" is for subclass + * @throws Exception + */ + @Override + protected P call() throws Exception { + executeCommand( getProcessBuilder() ); + return null; + } + + /** + * Execute the command + * @param pb + * @throws IOException + */ + protected void executeCommand(ProcessBuilder pb) throws IOException{ + final Process pc= pb.start(); + + /* Collect stdout for further usage */ + final StringBuilder sb = new StringBuilder(); + + try( InputStream stdout = pc.getInputStream(); + InputStreamReader isr = new InputStreamReader (stdout); + BufferedReader br = new BufferedReader(isr); ){ + String line; + + while(pc.isAlive() && !this.isCancelled()){ + line = br.readLine(); + + //I don't remember the reason of the second part of the below test... + if( line != null && !line.equals("null") ){ + sb.append("\n\n").append(line); + } + } + + this.exitCode = pc.exitValue(); + }catch(IOException e){ + this.exitCode = -1; + } + + this.shellOutput = sb.toString(); + + if(pc.isAlive()) + pc.destroy(); + } + + /** + * Build the ProcessBuilder to execute Command + * @return ProcessBuilder instance containing the full command to run + */ + protected ProcessBuilder getProcessBuilder(){ + final ProcessBuilder pb = new ProcessBuilder(getFullCmd().split(" ")); + pb.redirectErrorStream(true); + return pb; + } + + + /** + * Concatenate command base with parameters to obtain + * the full command to be run + * @return String the full command + */ + protected String getFullCmd(){ + final StringBuilder sb = new StringBuilder(); + + // Prepare base of the command + String cmdBase = command.getCommandBase(); + if(AppConstants.isWindowsOs()){ + cmdBase = "cmd.exe /c \"\""+cmdBase+"\""; + } + sb.append(cmdBase); + + //Add the parameters + if(command.getParameters() != null && !command.getParameters().isEmpty()){ + command.getParameters().values().forEach((param) -> { + if(AppConstants.isWindowsOs()){ + param = "\""+param+"\""; + } + sb.append(" ").append(param); + }); + } + // Close the full command + if(AppConstants.isWindowsOs()){ + sb.append("\""); + } + + logger.debug("getFullCmd(), full command = {}", sb.toString()); + return sb.toString(); + } + + /* Getter */ + + public Command getCommand() { + return command; + } + + public String getShellOutput() { + return shellOutput; + } + + public int getExitCode() { + return exitCode; + } + +} \ No newline at end of file diff --git a/src/main/java/ecorp/easy/installer/tasks/CommandRunnerService.java b/src/main/java/ecorp/easy/installer/tasks/CommandRunnerService.java new file mode 100644 index 0000000000000000000000000000000000000000..73606d02a2e8acd1b87c7263dad746a6952c17cf --- /dev/null +++ b/src/main/java/ecorp/easy/installer/tasks/CommandRunnerService.java @@ -0,0 +1,136 @@ +/* + * Copyright 2019-2021 - ECORP SAS + + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package ecorp.easy.installer.tasks; + +import ecorp.easy.installer.AppConstants; +import ecorp.easy.installer.models.Command; +import java.io.IOException; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javafx.concurrent.Service; +import javafx.concurrent.Task; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Service in charge to run Command task + * @author vincent Bourgmayer + */ +public class CommandRunnerService extends Service{ + final protected static char COMMON_PARAM_IDENTIFIER = '$';//allow to identify when an param of a step is to load from common parameter + final protected static Pattern REGEX_FIND_PARAM = Pattern.compile("\\$\\{(.*?)\\}"); + private final static Logger logger = LoggerFactory.getLogger(CommandRunnerService.class); + private final static HashMap COMMON_PARAMS = new HashMap<>(); + + static { + final String sourcePath = AppConstants.getSourcesFolderPath(); + + COMMON_PARAMS.put("SOURCES_PATH", sourcePath); + COMMON_PARAMS.put("TWRP_IMAGE_PATH", sourcePath+AppConstants.getTwrpImgPath()); + COMMON_PARAMS.put("ARCHIVE_PATH", sourcePath+AppConstants.getEArchivePath()); + COMMON_PARAMS.put("ADB_FOLDER_PATH", AppConstants.getADBFolderPath()); + COMMON_PARAMS.put("HEIMDALL_FOLDER_PATH", AppConstants.getHeimdallFolderPath()); + COMMON_PARAMS.put("JAVA_FOLDER_PATH", AppConstants.JavaHome); + } + + private final Command cmd; + + public CommandRunnerService( Command cmd){ + this.cmd = cmd; + } + + @Override + protected Task createTask() { + + Task task = new Task() { + @Override + protected Boolean call() throws Exception { + logger.info("Command Task call()"); + updateParameters(); + try{ + cmd.execAndReadOutput(); + }catch( IOException | InterruptedException e){ + cmd.cancel(); + logger.error("cmd.execAndReadOutput(), error = {}", e.toString() ); + return false; + } + + //read result from command object + final int exitValue = cmd.getExitValue(); + final String shellOutput = cmd.getShellOutput(); + + logger.debug("command output= {}\nexit value = {}\n", shellOutput, exitValue); + + + if(cmd.isSuccess()){ + String outputKey = cmd.getOutputKey(); + //If an output is expected from succeed script + + if( outputKey != null && outputKey.charAt(0) == COMMON_PARAM_IDENTIFIER){ + final int lastIndex = shellOutput.lastIndexOf("\n"); + final int length = shellOutput.length(); + final String shellOutputCleaned = shellOutput.substring(lastIndex+1, length); + logger.debug("shell output cleaned : "+shellOutputCleaned); + COMMON_PARAMS.put(outputKey.replace("${","").replace("}", ""), shellOutputCleaned); + } + + return true; + }else{ //fails case + return false; + } + + } + }; + + task.setOnCancelled(eh->{ + logger.debug("CommandRunnerService.task.onCancelled()"); + cmd.cancel(); + }); + return task; + } + + + /** + * Update parameters of the current command + * It is called before to execute the command + * @param cmd + */ + protected void updateParameters(){ + //Update Parameters + if(cmd.getParameters() != null){ //@TODO: remove functionnal and rewrite it as it was before with simple loop. + cmd.getParameters().entrySet().stream().filter((param) -> (param.getValue().contains("$"))).forEachOrdered((param) -> { + Matcher matcher = REGEX_FIND_PARAM.matcher(param.getValue()); + while(matcher.find()){ + cmd.updateParameter(param.getKey(), param.getValue().replace(matcher.group(0), COMMON_PARAMS.get(matcher.group(1)))); + } + }); + + logger.debug("updateParameters(), Parameters = "+cmd.getParameters().toString()); + } + } + + /** + * Write a new value for the associated key. + * If the value is already present, the precedent value will be overwritten + * @param key the key to identify a param + * @param value the value of the param + */ + public static void updateCommonParam(String key, String value){ + COMMON_PARAMS.put(key, value); + } +} diff --git a/src/main/java/ecorp/easy/installer/tasks/DeviceDetectionTask.java b/src/main/java/ecorp/easy/installer/tasks/DeviceDetectionTask.java index ff384bb4dd4f319dab91a87c8fd7e37618910bdc..5ef76c46696a14d7c1a93985a6bafa6b0091424f 100644 --- a/src/main/java/ecorp/easy/installer/tasks/DeviceDetectionTask.java +++ b/src/main/java/ecorp/easy/installer/tasks/DeviceDetectionTask.java @@ -30,12 +30,19 @@ import org.slf4j.LoggerFactory; * @author vincent Bourgmayer * @author Ingo */ -public class DeviceDetectionTask extends Task{ +public class DeviceDetectionTask extends CommandExecutionTask{ final String CMD_adbDevices = "devices"; + private final static Logger logger = LoggerFactory.getLogger(DeviceDetectionTask.class); private final static Pattern LINEBREAK_PATTERN = Pattern.compile("\\R"); private final static Pattern SPACE_PATTERN = Pattern.compile("\\s+"); + public DeviceDetectionTask() { + super(new Command(AppConstants.getADBFolderPath()+"adb")); + this.command.addParameter("1", CMD_adbDevices); + this.command.addParameter("2", "-l"); + } + /** * @inheritDoc * @return Device object @@ -62,14 +69,12 @@ public class DeviceDetectionTask extends Task{ private Phone runAdbDevicesCmd(String baseCmdString) throws Exception{ logger.info("runADBDevicesCmd({})", baseCmdString); - Command cmd = new Command(baseCmdString); - cmd.addParameter("1", CMD_adbDevices); - cmd.addParameter("2", "-l"); - cmd.execAndReadOutput(); + super.executeCommand(super.getProcessBuilder()); Phone detectedDevice = null; - String[] outputs = LINEBREAK_PATTERN.split(cmd.getShellOutput()); - logger.debug(" raw shell outputs = {} ", cmd.getShellOutput()); + String[] outputs = LINEBREAK_PATTERN.split(shellOutput); + logger.debug(" raw shell outputs = {} ", shellOutput); + if(outputs.length <=1){ logger.info(" Waiting"); Thread.sleep(2250); diff --git a/src/main/java/ecorp/easy/installer/threads/FlashThread.java b/src/main/java/ecorp/easy/installer/threads/FlashThread.java deleted file mode 100644 index 3d255dd15ed63dcfe05d575a8f166bf020a832c5..0000000000000000000000000000000000000000 --- a/src/main/java/ecorp/easy/installer/threads/FlashThread.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright 2019-2020 - ECORP SAS - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package ecorp.easy.installer.threads; - -import ecorp.easy.installer.AppConstants; -import ecorp.easy.installer.models.Phone; -import ecorp.easy.installer.models.Command; -import ecorp.easy.installer.models.DataBundle; -import ecorp.easy.installer.models.StepUi; -import ecorp.easy.installer.models.steps.ICustomStep; -import ecorp.easy.installer.models.steps.IExecutableStep; -import ecorp.easy.installer.models.steps.IStep; -import ecorp.easy.installer.models.steps.LoadStep; -import ecorp.easy.installer.utils.IFlashHandler; -import javafx.application.Platform; -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class handle the background process of flashing a device - * @author Vincent Bourgmayer - * @author Ingo - */ -public class FlashThread extends Thread { - final protected static char COMMON_PARAM_IDENTIFIER = '$';//allow to identify when an param of a step is to load from common parameter - final protected static Pattern REGEX_FIND_PARAM = Pattern.compile("\\$\\{(.*?)\\}"); - private final static Logger logger = LoggerFactory.getLogger(FlashThread.class); - final IFlashHandler application; - final Object pauseLock; - - final Phone device; - protected final Map commonParameters; // this is parameters that are define by a script output and that can be use as parameter by another script - protected final Map steps; - protected String currentStepCode = ""; - protected final String firstCommandKey; - - /** - * Constructor for flashThread - * @param controller This is the controller which change the UI depending on the flash thread result - * @param firstCommandKey The command key to use to get the first step to perform - * @param pauseLock a semaphor to stop allow to pause and restart the thread - * @param device Object containing device info - */ - public FlashThread(IFlashHandler controller, String firstCommandKey, Object pauseLock, Phone device){ - this.steps = new HashMap<>(); - this.commonParameters = new HashMap<>(); - this.firstCommandKey = firstCommandKey; //this is the key of the command's hashmap - this.application = controller; - this.pauseLock = pauseLock; - this.device = device; - String sourcePath = AppConstants.getSourcesFolderPath(); - - //setParameters - this.commonParameters.put("SOURCES_PATH", sourcePath); - this.commonParameters.put("TWRP_IMAGE_PATH", sourcePath+AppConstants.getTwrpImgPath()); - this.commonParameters.put("ARCHIVE_PATH", sourcePath+AppConstants.getEArchivePath()); - this.commonParameters.put("ADB_FOLDER_PATH", AppConstants.getADBFolderPath()); - this.commonParameters.put("HEIMDALL_FOLDER_PATH", AppConstants.getHeimdallFolderPath()); - this.commonParameters.put("DEVICE_ID", device.getSerialNo()); - this.commonParameters.put("DEVICE_DEVICE", device.getAdbDevice()); - this.commonParameters.put("JAVA_FOLDER_PATH", AppConstants.JavaHome); - } - - /** - * Add a command associated to a specific key - * @param key must unique or the value associated with will be replaced by new one - * @param step IStep step to add - */ - public void addStep(String key, IStep step){ - logger.debug("FlashThread.addStep({}, ...)", key); - if(step != null && key!= null) - steps.put(key, step); - } - - /** - * Handle result of a command - * @param command - * @return boolean true is success false either - */ - private boolean handleResult(final Command command){ - logger.info("handleResult()"); - //read result from command object - final int exitValue = command.getExitValue(); - final String shellOutput = command.getShellOutput(); - - logger.debug(" Shell output= {}\nexit value = {}\n", shellOutput, exitValue); - - - if(command.isSuccess()){ - String outputKey = command.getOutputKey(); - //If an output is expected from succeed script - if( outputKey != null && outputKey.charAt(0) == COMMON_PARAM_IDENTIFIER){ - final int lastIndex = shellOutput.lastIndexOf("\n"); - final int length = shellOutput.length(); - final String shellOutputCleaned = shellOutput.substring(lastIndex+1, length); - logger.debug("shell output cleaned : "+shellOutputCleaned); - this.commonParameters.put(outputKey.replace("${","").replace("}", ""), shellOutputCleaned); - } - - return true; - }else{ //fails case - String errorMsgKey = command.getErrorMsg(); - if(errorMsgKey == null || errorMsgKey.isEmpty()){ - errorMsgKey = "script_error_unknown"; - } - logger.warn("Exit value means: "+errorMsgKey ); - showError(errorMsgKey); - return false; - } - } - - /** - * send info to app to make it in error mode - * @param errorMsgKey the error message translation key to send to UI - */ - protected void showError(String errorMsgKey) { - - //@TODO remove below specific code - final DataBundle bundle = new DataBundle(); - bundle.putString("errorMsgKey", errorMsgKey); //@Todo: put errorMsgKey as staticaly defined somewhere - Platform.runLater(() -> { - application.onFlashError(bundle); - }); - } - - - /** - * Execute some code before to execute the current command - * It is runned in the While loop which loops over commands - * It's executed in a Try catch. - * @throws java.lang.ClassCastException - */ - protected void doBeforeToRunCommand() throws ClassCastException{ - //Update UI - final IStep step = steps.get(currentStepCode); - final DataBundle bundle = new DataBundle(); - logger.debug("doBeforeToRunCommand(), currentStepCode: {}", currentStepCode); - //Prepare datas for UI - final String stepType = step.getType(); - bundle.putString("stepType", stepType); - logger.debug("--stepType: {}", stepType); - - final boolean hasScript; - switch(stepType){ - case "custom": - bundle.putString("titleIconName", ((ICustomStep) step).getTitleIconName()); - bundle.putString("stepTitle", ((ICustomStep) step).getTitleKey()); - bundle.putList("stepInstructions", String.class.getSimpleName(), ((ICustomStep) step).getTextContentKeys()); - hasScript = false; - - break; - case "custom-executable": - bundle.putString("titleIconName", ((ICustomStep) step).getTitleIconName()); - bundle.putString("stepTitle", ((ICustomStep) step).getTitleKey()); - bundle.putList("stepInstructions", String.class.getSimpleName(), ((ICustomStep) step).getTextContentKeys()); - hasScript= true; - break; - case "executable": - hasScript= true; - break; - case "load": - hasScript= true; - bundle.putString("stepTitle", ((ICustomStep) step).getTitleKey()); - bundle.putList("stepInstructions", String.class.getSimpleName(), ((ICustomStep) step).getTextContentKeys()); - bundle.putString("titleIconName", ((ICustomStep) step).getTitleIconName()); - bundle.putInteger("averageTime", ((LoadStep) step).getAverageTime()); - break; - default: - hasScript = false; - break; - } - - bundle.putBoolean("hasScript", hasScript); - //Update UI - Platform.runLater(()->{ - application.onStepStart(bundle); - }); - } - - /** - * Do some code at the real end of "run" methodremove-fs- - * It is not executed in a Try Catch; - */ - protected void onRunEnd() { - final DataBundle bundle = new DataBundle(); - bundle.putBoolean("isFlashed", true); - Platform.runLater(() ->{ - application.onFlashStop( bundle); - }); - } - - /** - * @inheritDoc - */ - @Override - public void run(){ - if(steps.isEmpty()) return; - try{ - //execute scripts - String nextCommandKey = firstCommandKey; - while(nextCommandKey != null && !nextCommandKey.equals(IStep.LAST_STEP_KEY)){ - currentStepCode = nextCommandKey; - final IStep step = steps.get(nextCommandKey); - final String stepType = step.getType(); - - //UpdateUI - doBeforeToRunCommand(); - - if(stepType.equals("executable") - || stepType.equals("load") - || stepType.equals("custom-executable")) - { - Command cmd = ((IExecutableStep) step).getCommand(); - updateParameters(cmd); - - - logger.debug("Run(), Command = "+cmd.getCommand()); - cmd.execAndReadOutput(); - handleResult(cmd); - - }else{ - logger.debug("run a no script step. Waiting for user's validation"); - synchronized(pauseLock){ pauseLock.wait(); } - - } - nextCommandKey = step.getNextStepKey(); - } - - }catch(Exception e){ - showError("java_error_unknow"); - e.printStackTrace(); - //logger.error("Java exception: "+ e.toString()); - } - onRunEnd(); - } - - /** - * Return the number of step of the full process - * @return - */ - public int getCommandsSize(){ - return this.steps.size(); - } - - - /** - * Update parameters of the current command - * It is called before to execute the command - * @param cmd - */ - protected void updateParameters(final Command cmd){ - //Update Parameters - if(cmd.getParameters() != null){ //@TODO: remove functionnal and rewrite it as it was before with simple loop. - cmd.getParameters().entrySet().stream().filter((param) -> (param.getValue().contains("$"))).forEachOrdered((param) -> { - Matcher matcher = REGEX_FIND_PARAM.matcher(param.getValue()); - while(matcher.find()){ - cmd.updateParameter(param.getKey(), param.getValue().replace(matcher.group(0), commonParameters.get(matcher.group(1)))); - } - }); - - logger.debug("updateParameters(), Parameters = "+cmd.getParameters().toString()); - } - } -} \ No newline at end of file diff --git a/src/main/java/ecorp/easy/installer/threads/ThreadFactory.java b/src/main/java/ecorp/easy/installer/threads/ThreadFactory.java index 493f206489441477192c34b778f50b19d18034f2..f3e9023e8f2410840b79a3b7aa2c8df288331fc3 100644 --- a/src/main/java/ecorp/easy/installer/threads/ThreadFactory.java +++ b/src/main/java/ecorp/easy/installer/threads/ThreadFactory.java @@ -184,12 +184,10 @@ public class ThreadFactory { * @return FlashThread */ public FlashThread buildFlashThread( IFlashHandler application, Object pauseLock){ - if(flashMould == null || flashMould.getSteps() == null || device == null) return null; - + FlashThread result = new FlashThread(application, "f0", pauseLock, device); - flashMould.getSteps().entrySet().forEach((entry) -> { //@TODO replace the entry.getValue() by a copy by value result.addStep(entry.getKey(), entry.getValue() ); @@ -205,4 +203,9 @@ public class ThreadFactory { if(flashMould == null) return 0; return flashMould.getSteps().size(); } + + + public ProcessMould getFlashMould() { + return flashMould; + } } \ No newline at end of file diff --git a/src/main/java/ecorp/easy/installer/utils/UiUtils.java b/src/main/java/ecorp/easy/installer/utils/UiUtils.java index 4cfdc19eead8398546c57607b76d8cb843b7827f..cf0be1043c283ff5a68708047cd4382bf7e4f118 100644 --- a/src/main/java/ecorp/easy/installer/utils/UiUtils.java +++ b/src/main/java/ecorp/easy/installer/utils/UiUtils.java @@ -5,7 +5,6 @@ */ package ecorp.easy.installer.utils; -import ecorp.easy.installer.controllers.subcontrollers.FlashSceneController; import javafx.animation.FadeTransition; import javafx.event.ActionEvent; import javafx.event.EventHandler; diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index d34871f37fa7b27663f94ba36bf80dd0e2207724..1db438fa82bdd7358cb948000500528c5599ec8b 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -34,7 +34,7 @@ module ecorp.easy.installer { opens ecorp.easy.installer to javafx.fxml; opens ecorp.easy.installer.controllers to javafx.fxml; opens ecorp.easy.installer.controllers.subcontrollers to javafx.fxml; - + opens ecorp.easy.installer.controllers.stepControllers to javafx.fxml; exports ecorp.easy.installer.logger; exports ecorp.easy.installer; } diff --git a/src/main/resources/css/style.css b/src/main/resources/css/style.css index 038d64d41891bd511c4d37e23ac1c47264fd0df1..f9b304bd7537164dee942379e7c08e633634ec3d 100644 --- a/src/main/resources/css/style.css +++ b/src/main/resources/css/style.css @@ -158,6 +158,13 @@ Button:pressed{ -fx-background-insets: 0; -fx-background-radius: 20; } +.progressBar.errorBar .bar { + -fx-background-color: #E50000; +} + +.errorBar .bar { + -fx-background-color: #be1e38; +} #logScrollPane { -fx-background-color: #E5E5E5; diff --git a/src/main/resources/fxml/6-2-eAccount.fxml b/src/main/resources/fxml/6-2-eAccount.fxml index 87f355c40c7d6a5938b83a00fd02eb070c72d13a..4f8f0273ae49fd34bb070b9f419f05711d24bf93 100644 --- a/src/main/resources/fxml/6-2-eAccount.fxml +++ b/src/main/resources/fxml/6-2-eAccount.fxml @@ -27,11 +27,11 @@ - + fx:controller="ecorp.easy.installer.controllers.stepControllers.EAccountController"> diff --git a/src/main/resources/fxml/6-3-unlockOEM.fxml b/src/main/resources/fxml/6-3-unlockOEM.fxml index a4828b96b9f244bec0deea44501f2cc68efb3e46..8974e6d5d781992bd5047c07e79baadc7df3c933 100644 --- a/src/main/resources/fxml/6-3-unlockOEM.fxml +++ b/src/main/resources/fxml/6-3-unlockOEM.fxml @@ -27,11 +27,11 @@ - + fx:controller="ecorp.easy.installer.controllers.stepControllers.UnlockOemController"> diff --git a/src/main/resources/fxml/6-flashScene.fxml b/src/main/resources/fxml/LogPanel.fxml similarity index 52% rename from src/main/resources/fxml/6-flashScene.fxml rename to src/main/resources/fxml/LogPanel.fxml index 7d9138a262cd082aaddc9ff2874672b56e26c524..fe113344e7d6ceadf26fb0a0eaced1c68c8f417c 100644 --- a/src/main/resources/fxml/6-flashScene.fxml +++ b/src/main/resources/fxml/LogPanel.fxml @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/fxml/loadStep.fxml b/src/main/resources/fxml/loadStep.fxml new file mode 100644 index 0000000000000000000000000000000000000000..13fba9498e68fe36ecbbece73c04c8565f39942f --- /dev/null +++ b/src/main/resources/fxml/loadStep.fxml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/lang/translation.properties b/src/main/resources/lang/translation.properties index b4a60f93422702f2312266c8fd05b5d747617916..f937e69bb94b65fb50cebfee828f84b538030c01 100644 --- a/src/main/resources/lang/translation.properties +++ b/src/main/resources/lang/translation.properties @@ -226,6 +226,19 @@ script_error_serialNumber_missing=No device's serial number provided script_error_fastboot_path_missing= No fastboot tool path provided script_error_fastboot_flashingUnlock_failed=Could not unlock flashing script_error_unknown= The installation encounter an error +script_error_cantRebootBootloader= Failed to reboot into bootloader +script_error_cantUnpackSources=Failed to unpack /e/ sources +script_error_cantWipeData=Failed to wipe data +script_error_cantFlashBoot=Failed to flash Boot partition +script_error_cantFlashRecovery=Failed to flash Recovery +script_error_cantFlashVbmeta=Failed to flash vb meta partition +script_error_cantFlashVbmeta_system=Failed to flash vb meta system partition +script_error_cantFlashVBmeta_vendor=Failed to flash vb Meta vendor partition +script_error_cantRebootToFastboot=Failed to reboot into fastboot mode +script_error_cantFlashSystem=Failed to flash system partition +script_error_cantFlashproduct=Failed to flash product partition +script_error_cantFlashVendor=Failed to flash vendor partition +script_error_cantrebootFromFasboot= Failed to reboot from fastboot java_error_unknow= The installation encounter an internal error flash_process_cancelled=The installation process has been cancelled diff --git a/src/main/resources/yaml/Teracube_2e_flash.yml b/src/main/resources/yaml/Teracube_2e_flash.yml index f92e4103ca901f20573286f11a2599c6fdd33b9b..a8336662aaa1a9d29db285cbdb55924dbff4e4ec 100644 --- a/src/main/resources/yaml/Teracube_2e_flash.yml +++ b/src/main/resources/yaml/Teracube_2e_flash.yml @@ -45,8 +45,8 @@ steps: koCodes: 1: script_error_unknown 10: script_error_cantRebootBootloader - 101: script_error_deviceID_missing - 102: script_error_fastbootPath_missing + 101: script_error_serialNumber_missing + 102: script_error_fastboot_path_missing f2: type: custom-executable stepNumber: 3 @@ -64,9 +64,9 @@ steps: 0: ~ koCodes: 1: script_error_unknown - 2: script_error_flashingUnlockFailed - 101: script_error_deviceID_missing - 102: script_error_fastbootPath_missing + 2: script_error_fastboot_flashingUnlock_failed + 101: script_error_serialNumber_missing + 102: script_error_fastboot_path_missing f3: type: load stepNumber: 4 @@ -96,9 +96,9 @@ steps: 18: script_error_cantFlashSystem 19: script_error_cantFlashproduct 20: script_error_cantFlashVendor - 101: script_error_deviceID_missing + 101: script_error_serialNumber_missing 102: script_error_installFromFastboot_102 - 103: script_error_fastbootPath_missing + 103: script_error_fastboot_path_missing f4: type: askAccount stepNumber: 5 @@ -119,4 +119,4 @@ steps: koCodes: 1: script_error_unknown 10: script_error_cantrebootFromFasboot - 101: script_error_noDeviceFoundInFastboot \ No newline at end of file + 101: script_error_waitFastboot_1 \ No newline at end of file