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