ApktoolPanel.java

package edu.jiangxin.apktoolbox.reverse;

import edu.jiangxin.apktoolbox.swing.extend.plugin.PluginPanel;
import edu.jiangxin.apktoolbox.swing.extend.listener.SelectDirectoryListener;
import edu.jiangxin.apktoolbox.swing.extend.listener.SelectFileListener;
import edu.jiangxin.apktoolbox.utils.Constants;
import edu.jiangxin.apktoolbox.utils.Utils;
import org.apache.commons.io.FilenameUtils;

import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

public class ApktoolPanel extends PluginPanel {
    public ApktoolPanel() throws HeadlessException {
        super();
    }

    @Override
    public String getPluginFilename() {
        return "apktool_2.9.2.jar";
    }

    @Override
    public void initUI() {
        BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS);
        setLayout(boxLayout);

        JTabbedPane categoryTabbedPane = new JTabbedPane();
        add(categoryTabbedPane);

        JPanel decodeCategoryPanel = new ApktoolDecodePanel();
        JPanel rebuildCategoryPanel = new ApktoolRebuildPanel();

        categoryTabbedPane.addTab("Decode", null, decodeCategoryPanel, "Decode the APK file");
        categoryTabbedPane.setSelectedIndex(0);
        categoryTabbedPane.addTab("Rebuild", null, rebuildCategoryPanel, "Rebuild the APK file");
    }

    abstract class ApktoolPanelBase extends JPanel {
        protected JPanel srcPanel;

        protected JPanel targetPanel;

        protected JPanel optionPanel;

        protected JPanel operationPanel;

        protected ApktoolPanelBase() throws HeadlessException {
            super();
            initUI();
        }

        private void initUI() {
            BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS);
            setLayout(boxLayout);

            createSrcPanel();
            add(srcPanel);
            add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));

            createTargetPanel();
            add(targetPanel);
            add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));

            createOptionPanel();
            add(optionPanel);
            add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));

            createOperationPanel();
            add(operationPanel);
        }

        protected void createSrcPanel() {
            srcPanel = new JPanel();
            srcPanel.setLayout(new BoxLayout(srcPanel, BoxLayout.X_AXIS));
        }

        protected void createTargetPanel() {
            targetPanel = new JPanel();
            targetPanel.setLayout(new BoxLayout(targetPanel, BoxLayout.X_AXIS));
        }

        protected void createOptionPanel() {
            optionPanel = new JPanel();
            optionPanel.setLayout(new BoxLayout(optionPanel, BoxLayout.X_AXIS));
        }

        protected void createOperationPanel() {
            operationPanel = new JPanel();
            operationPanel.setLayout(new BoxLayout(operationPanel, BoxLayout.X_AXIS));
        }
    }

    class ApktoolDecodePanel extends ApktoolPanelBase {
        private JTextField srcTextField;

        private JTextField targetTextField;

        private JCheckBox resourceIgnoreCheckBox;

        private JCheckBox overrideCheckBox;

        public ApktoolDecodePanel() throws HeadlessException {
            super();
        }

        @Override
        public void createSrcPanel() {
            super.createSrcPanel();

            srcTextField = new JTextField();
            srcTextField.setText(conf.getString("apktool.decode.src.file"));

            JButton srcButton = new JButton(bundle.getString("choose.file.button"));
            srcButton.addActionListener(new SelectFileListener("select a file", srcTextField));

            srcPanel.add(srcTextField);
            srcPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
            srcPanel.add(srcButton);
        }

        @Override
        public void createTargetPanel() {
            super.createTargetPanel();

            targetTextField = new JTextField();
            targetTextField.setText(conf.getString("apktool.decode.target.dir"));

            JButton targetButton = new JButton(bundle.getString("save.dir.button"));
            targetButton.addActionListener(new SelectDirectoryListener("Save To", targetTextField));

            targetPanel.add(targetTextField);
            targetPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
            targetPanel.add(targetButton);
        }

        @Override
        public void createOptionPanel() {
            super.createOptionPanel();

            resourceIgnoreCheckBox = new JCheckBox("Ignore res");
            resourceIgnoreCheckBox.setSelected(false);
            optionPanel.add(resourceIgnoreCheckBox);

            overrideCheckBox = new JCheckBox("Override");
            overrideCheckBox.setSelected(true);
            optionPanel.add(overrideCheckBox);
        }

        @Override
        public void createOperationPanel() {
            super.createOperationPanel();

            JButton decodeButton = new JButton("Decode");
            decodeButton.addActionListener(new ApktoolDecodePanel.DecodeButtonActionListener());

            operationPanel.add(decodeButton);
        }

        private final class DecodeButtonActionListener implements ActionListener {
            @Override
            public void actionPerformed(ActionEvent e) {
                String srcPath = checkAndGetFileContent(srcTextField, "apktool.decode.src.file", "Source file is invalid");
                if (srcPath == null) {
                    return;
                }

                String targetPath = checkAndGetDirContent(targetTextField, "apktool.decode.target.dir", "Target directory is invalid");
                if (targetPath == null) {
                    return;
                }

                String srcBaseName = FilenameUtils.getBaseName(srcPath);
                StringBuilder sb = new StringBuilder();
                sb.append(ApktoolPanel.this.getPluginStartupCmd()).append(" d ")
                        .append(srcPath).append(" -o ").append(targetPath).append(File.separator).append(srcBaseName);
                if (resourceIgnoreCheckBox.isSelected()) {
                    sb.append(" -r");
                }
                if (overrideCheckBox.isSelected()) {
                    sb.append(" -f");
                }
                Utils.blockedExecutor(sb.toString());
            }
        }
    }

    class ApktoolRebuildPanel extends ApktoolPanelBase {
        private JTextField srcTextField;

        private JTextField targetTextField;

        private JCheckBox signAPK;

        public ApktoolRebuildPanel() throws HeadlessException {
            super();
        }

        @Override
        public void createSrcPanel() {
            super.createSrcPanel();

            srcTextField = new JTextField();
            srcTextField.setText(conf.getString("apktool.rebuild.src.dir"));

            JButton srcButton = new JButton(bundle.getString("choose.dir.button"));
            srcButton.addActionListener(new SelectDirectoryListener("Select Directory", srcTextField));

            srcPanel.add(srcTextField);
            srcPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
            srcPanel.add(srcButton);
        }

        @Override
        public void createTargetPanel() {
            super.createTargetPanel();

            targetTextField = new JTextField();
            targetTextField.setText(conf.getString("apktool.rebuild.target.file"));

            JButton targetButton = new JButton(bundle.getString("save.file.button"));
            targetButton.addActionListener(new SelectFileListener("save to", targetTextField, new ApktoolRebuildPanel.ApkFileFilter()));

            targetPanel.add(targetTextField);
            targetPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
            targetPanel.add(targetButton);
        }

        @Override
        public void createOptionPanel() {
            super.createOptionPanel();

            signAPK = new JCheckBox("sign APK");
            signAPK.setSelected(false);
            optionPanel.add(signAPK);
        }

        @Override
        public void createOperationPanel() {
            super.createOperationPanel();

            JButton rebuildButton = new JButton("Rebuild");
            rebuildButton.addActionListener(new ApktoolRebuildPanel.RebuildButtonActionListener());
            operationPanel.add(rebuildButton);
        }

        private final class RebuildButtonActionListener implements ActionListener {
            @Override
            public void actionPerformed(ActionEvent e) {
                String srcPath = checkAndGetDirContent(srcTextField, "apktool.rebuild.src.dir", "Source directory is invalid");
                if (srcPath == null) {
                    return;
                }

                String targetPath = checkAndGetNewFileContent(targetTextField, "apktool.rebuild.target.file", "Target file is invalid");
                if (targetPath == null) {
                    return;
                }

                StringBuilder sb = new StringBuilder();
                sb.append(ApktoolPanel.this.getPluginStartupCmd()).append(" b ")
                        .append(srcPath).append(" -o ").append(targetPath);
                Utils.blockedExecutor(sb.toString());
                if (signAPK.isSelected()) {
                    sb = new StringBuilder();
                    sb.append(ApktoolPanel.this.getPluginStartupCmd())
                            .append(" -keystore ").append(Utils.getToolsPath()).append(File.separator)
                            .append("debug.keystore").append(" -alias androiddebugkey -pswd android ")
                            .append(targetPath);
                    Utils.blockedExecutor(sb.toString());
                }
            }
        }

        private final class ApkFileFilter extends FileFilter {

            @Override
            public boolean accept(File f) {
                String nameString = f.getName();
                return nameString.toLowerCase().endsWith(".apk");
            }

            @Override
            public String getDescription() {
                return "*.apk";
            }
        }
    }
}