View Javadoc
1   package edu.jiangxin.apktoolbox.main;
2   
3   import edu.jiangxin.apktoolbox.Version;
4   import edu.jiangxin.apktoolbox.android.dumpsys.DumpsysPanel;
5   import edu.jiangxin.apktoolbox.convert.color.ColorPickerPanel;
6   import edu.jiangxin.apktoolbox.convert.protobuf.supervised.SupervisedProtobufConvertPanel;
7   import edu.jiangxin.apktoolbox.convert.protobuf.unsupervised.UnsupervisedProtobufConvertPanel;
8   import edu.jiangxin.apktoolbox.file.batchrename.BatchRenamePanel;
9   import edu.jiangxin.apktoolbox.file.EncodeConvertPanel;
10  import edu.jiangxin.apktoolbox.file.OsConvertPanel;
11  import edu.jiangxin.apktoolbox.file.checksum.ChecksumPanel;
12  import edu.jiangxin.apktoolbox.file.password.recovery.RecoveryPanel;
13  import edu.jiangxin.apktoolbox.file.duplicate.DuplicateSearchPanel;
14  import edu.jiangxin.apktoolbox.file.zhconvert.ZhConvertPanel;
15  import edu.jiangxin.apktoolbox.help.*;
16  import edu.jiangxin.apktoolbox.android.i18n.I18nAddPanel;
17  import edu.jiangxin.apktoolbox.android.i18n.I18nFindLongestPanel;
18  import edu.jiangxin.apktoolbox.android.i18n.I18nRemovePanel;
19  import edu.jiangxin.apktoolbox.android.monkey.MonkeyPanel;
20  import edu.jiangxin.apktoolbox.help.settings.SettingsPanel;
21  import edu.jiangxin.apktoolbox.pdf.finder.PdfFinderPanel;
22  import edu.jiangxin.apktoolbox.pdf.passwordremover.PdfPasswordRemoverPanel;
23  import edu.jiangxin.apktoolbox.pdf.pic2pdf.Pic2PdfPanel;
24  import edu.jiangxin.apktoolbox.pdf.stat.PdfStatPanel;
25  import edu.jiangxin.apktoolbox.reverse.*;
26  import edu.jiangxin.apktoolbox.android.screenshot.ScreenShotPanel;
27  import edu.jiangxin.apktoolbox.reverse.ApktoolPanel;
28  import edu.jiangxin.apktoolbox.swing.extend.EasyFrame;
29  import edu.jiangxin.apktoolbox.swing.extend.EasyPanel;
30  import edu.jiangxin.apktoolbox.swing.extend.listener.ChangeMenuListener;
31  import edu.jiangxin.apktoolbox.swing.extend.listener.ChangeMenuToUrlListener;
32  import edu.jiangxin.apktoolbox.swing.extend.listener.IPreChangeMenuCallBack;
33  import edu.jiangxin.apktoolbox.swing.extend.plugin.ChangeMenuPreparePluginController;
34  import edu.jiangxin.apktoolbox.swing.extend.plugin.PluginPanel;
35  import edu.jiangxin.apktoolbox.swing.keeper.UiStateKeeper;
36  import edu.jiangxin.apktoolbox.utils.Utils;
37  import org.apache.commons.configuration2.Configuration;
38  import org.apache.commons.lang3.StringUtils;
39  import org.apache.logging.log4j.LogManager;
40  import org.apache.logging.log4j.Logger;
41  
42  import javax.swing.*;
43  import javax.swing.border.EmptyBorder;
44  import java.awt.*;
45  import java.awt.event.*;
46  import java.io.Serial;
47  import java.lang.reflect.InvocationTargetException;
48  import java.text.MessageFormat;
49  import java.util.Locale;
50  import java.util.Objects;
51  
52  /**
53   * @author jiangxin
54   * @author 2018-08-19
55   */
56  public final class MainFrame extends EasyFrame {
57  
58      @Serial
59      private static final long serialVersionUID = 1L;
60  
61      private JPanel contentPane;
62      private EasyPanel currentEasyPanel = null;
63      private JMenuBar menuBar;
64  
65      public static void main(String[] args) {
66          final Logger logger = LogManager.getLogger(MainFrame.class.getSimpleName());
67          boolean isEnvironmentOk = Utils.checkAndInitEnvironment();
68          if (!isEnvironmentOk) {
69              logger.error("Environment is not ready, exit");
70              return;
71          }
72          EventQueue.invokeLater(() -> {
73              Configuration conf = Utils.getConfiguration();
74              String lookAndFeelClassName = conf.getString("look.and.feel.class.name");
75              if (StringUtils.isEmpty(lookAndFeelClassName)) {
76                  lookAndFeelClassName = "com.formdev.flatlaf.FlatDarculaLaf";
77                  conf.setProperty("look.and.feel.class.name", lookAndFeelClassName);
78              }
79              try {
80                  UIManager.setLookAndFeel(lookAndFeelClassName);
81              } catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
82                  logger.error("setLookAndFeel failed, use default instead", e);
83              }
84  
85              String currentLocaleLanguage = conf.getString("locale.language");
86              if (StringUtils.isEmpty(currentLocaleLanguage)) {
87                  currentLocaleLanguage = Locale.ENGLISH.getLanguage();
88                  conf.setProperty("locale.language", currentLocaleLanguage);
89              }
90              Locale.setDefault(Locale.forLanguageTag(currentLocaleLanguage));
91  
92              MainFrame frame = new MainFrame();
93  
94              boolean isAlwaysOnTop = conf.getBoolean("always.on.top", false);
95              conf.setProperty("always.on.top", isAlwaysOnTop);
96              frame.setAlwaysOnTop(isAlwaysOnTop);
97  
98              frame.setVisible(true);
99          });
100     }
101 
102     public MainFrame() {
103         super();
104         initialize();
105         if (SystemTray.isSupported()) {
106             configSystemTray();
107         }
108 
109         setTitle(MessageFormat.format(bundle.getString("main.title"), Version.VERSION));
110         setDefaultCloseOperation(EXIT_ON_CLOSE);
111         setMenuBar();
112         contentPane = new JPanel();
113         contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
114         contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
115         contentPane.add(Box.createVerticalGlue());
116         EasyPanel initPanel = new AboutPanel();
117         initPanel.init();
118         initPanel.setBorder(BorderFactory.createTitledBorder(bundle.getString("help.about.title")));
119         contentPane.add(initPanel);
120         contentPane.add(Box.createVerticalGlue());
121         setContentPane(contentPane);
122         refreshSizeAndLocation();
123     }
124 
125     private void configSystemTray() {
126         SystemTray systemTray = SystemTray.getSystemTray();
127         PopupMenu popupMenu = new PopupMenu();
128         final MenuItem show = new MenuItem("Open");
129         final MenuItem exit = new MenuItem("Close");
130         ActionListener actionListener = e -> {
131             if (e.getSource() == show) {
132                 setExtendedState(NORMAL);
133                 setVisible(true);
134             }
135             if (e.getSource() == exit) {
136                 dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
137             }
138         };
139         exit.addActionListener(actionListener);
140         show.addActionListener(actionListener);
141         popupMenu.add(show);
142         popupMenu.add(exit);
143         TrayIcon trayIcon = new TrayIcon(image, "系统托盘", popupMenu);
144         trayIcon.setImageAutoSize(true);
145         try {
146             systemTray.add(trayIcon);
147         } catch (AWTException e) {
148             logger.error("add icon to tray failed");
149         }
150         trayIcon.addMouseListener(new MouseAdapter() {
151             @Override
152             public void mouseClicked(MouseEvent e) {
153                 if (e.getClickCount() == 2) {
154                     setExtendedState(NORMAL);
155                     setVisible(true);
156                 }
157             }
158         });
159     }
160 
161     private void setMenuBar() {
162         menuBar = new JMenuBar();
163         setJMenuBar(menuBar);
164 
165         createReverseMenu();
166 
167         createAndroidMenu();
168 
169         createPdfMenu();
170 
171         createFileMenu();
172 
173         createConvertMenu();
174 
175         createHelpMenu();
176     }
177 
178     private void createHelpMenu() {
179         JMenu helpMenu = new JMenu(bundle.getString("help.title"));
180         menuBar.add(helpMenu);
181 
182         JMenuItem documentMenuItem = new JMenuItem(bundle.getString("help.document.title"));
183         documentMenuItem.addActionListener(new ChangeMenuToUrlListener(Constant.URL_DOCUMENT));
184         helpMenu.add(documentMenuItem);
185 
186         JMenuItem settingsMenuItem = new JMenuItem(bundle.getString("help.settings.title"));
187         settingsMenuItem.addActionListener(new ChangeMenuToPanelListener(SettingsPanel.class, settingsMenuItem.getText()));
188         helpMenu.add(settingsMenuItem);
189 
190         JMenuItem feedbackMenuItem = new JMenuItem(bundle.getString("help.feedback.title"));
191         feedbackMenuItem.addActionListener(new ChangeMenuToUrlListener(Constant.URL_FEEDBACK));
192         helpMenu.add(feedbackMenuItem);
193 
194         JMenuItem checkUpdateMenuItem = new JMenuItem(bundle.getString("help.checkupdate.title"));
195         checkUpdateMenuItem.addActionListener(new CheckUpdateActionListener(this));
196         helpMenu.add(checkUpdateMenuItem);
197 
198         JMenuItem contributeMenuItem = new JMenuItem(bundle.getString("help.contribute.title"));
199         contributeMenuItem.addActionListener(new ChangeMenuToUrlListener(Constant.URL_CONTRIBUTE));
200         helpMenu.add(contributeMenuItem);
201 
202         JMenuItem aboutMenuItem = new JMenuItem(bundle.getString("help.about.title"));
203         aboutMenuItem.addActionListener(new ChangeMenuToPanelListener(AboutPanel.class, aboutMenuItem.getText()));
204         helpMenu.add(aboutMenuItem);
205     }
206 
207     private void createPdfMenu() {
208         JMenu pdfMenu = new JMenu(bundle.getString("pdf.title"));
209         menuBar.add(pdfMenu);
210 
211         JMenuItem pdfStatMenuItem = new JMenuItem(bundle.getString("pdf.stat.title"));
212         pdfStatMenuItem.addActionListener(new ChangeMenuToPanelListener(PdfStatPanel.class, pdfStatMenuItem.getText()));
213         pdfMenu.add(pdfStatMenuItem);
214 
215         JMenuItem pdfFinderMenuItem = new JMenuItem(bundle.getString("pdf.finder.title"));
216         pdfFinderMenuItem.addActionListener(new ChangeMenuToPanelListener(PdfFinderPanel.class, pdfFinderMenuItem.getText()));
217         pdfMenu.add(pdfFinderMenuItem);
218 
219         JMenuItem pdfPasswordRemoverMenuItem = new JMenuItem(bundle.getString("pdf.password.remover.title"));
220         pdfPasswordRemoverMenuItem.addActionListener(new ChangeMenuToPanelListener(PdfPasswordRemoverPanel.class, pdfPasswordRemoverMenuItem.getText()));
221         pdfMenu.add(pdfPasswordRemoverMenuItem);
222 
223         JMenuItem pic2PdfMenuItem = new JMenuItem(bundle.getString("pictures.to.pdf.title"));
224         pic2PdfMenuItem.addActionListener(new ChangeMenuToPanelListener(Pic2PdfPanel.class, pic2PdfMenuItem.getText()));
225         pdfMenu.add(pic2PdfMenuItem);
226     }
227 
228     private void createFileMenu() {
229         JMenu fileMenu = new JMenu(bundle.getString("file.title"));
230         menuBar.add(fileMenu);
231 
232         JMenuItem osConvertMenuItem = new JMenuItem(bundle.getString("file.os.convert.title"));
233         osConvertMenuItem.addActionListener(new ChangeMenuToPanelListener(OsConvertPanel.class, osConvertMenuItem.getText()));
234         fileMenu.add(osConvertMenuItem);
235 
236         JMenuItem encodeConvertMenuItem = new JMenuItem(bundle.getString("file.encode.convert.title"));
237         encodeConvertMenuItem.addActionListener(new ChangeMenuToPanelListener(EncodeConvertPanel.class, encodeConvertMenuItem.getText()));
238         fileMenu.add(encodeConvertMenuItem);
239 
240         JMenuItem zhConvertMenuItem = new JMenuItem(bundle.getString("file.zh.convert.title"));
241         zhConvertMenuItem.addActionListener(new ChangeMenuToPanelListener(ZhConvertPanel.class, zhConvertMenuItem.getText()));
242         fileMenu.add(zhConvertMenuItem);
243 
244         JMenuItem duplicateFindMenuItem = new JMenuItem(bundle.getString("file.duplicate.title"));
245         duplicateFindMenuItem.addActionListener(new ChangeMenuToPanelListener(DuplicateSearchPanel.class, duplicateFindMenuItem.getText()));
246         fileMenu.add(duplicateFindMenuItem);
247 
248         JMenuItem batchRenameMenuItem = new JMenuItem(bundle.getString("file.batch.rename.title"));
249         batchRenameMenuItem.addActionListener(new ChangeMenuToPanelListener(BatchRenamePanel.class, batchRenameMenuItem.getText()));
250         fileMenu.add(batchRenameMenuItem);
251 
252         JMenuItem checkSumMenuItem = new JMenuItem(bundle.getString("file.check.summary.title"));
253         checkSumMenuItem.addActionListener(new ChangeMenuToPanelListener(ChecksumPanel.class, checkSumMenuItem.getText()));
254         fileMenu.add(checkSumMenuItem);
255 
256         JMenuItem recoveryMenuItem = new JMenuItem(bundle.getString("file.password.recovery.title"));
257         recoveryMenuItem.addActionListener(new ChangeMenuToPanelListener(RecoveryPanel.class, recoveryMenuItem.getText()));
258         fileMenu.add(recoveryMenuItem);
259     }
260 
261     private void createConvertMenu() {
262         JMenu convertMenu = new JMenu(bundle.getString("convert.title"));
263         menuBar.add(convertMenu);
264 
265         JMenuItem colorPickerMenuItem = new JMenuItem(bundle.getString("picker.color.title"));
266         colorPickerMenuItem.addActionListener(new ChangeMenuToPanelListener(ColorPickerPanel.class, colorPickerMenuItem.getText()));
267         convertMenu.add(colorPickerMenuItem);
268 
269         JMenuItem unsupervisedProtobufConvertMenuItem = new JMenuItem(bundle.getString("convert.protobuf.unsupervised.title"));
270         unsupervisedProtobufConvertMenuItem.addActionListener(new ChangeMenuToPanelListener(UnsupervisedProtobufConvertPanel.class, unsupervisedProtobufConvertMenuItem.getText()));
271         convertMenu.add(unsupervisedProtobufConvertMenuItem);
272 
273         JMenuItem supervisedProtobufConvertMenuItem = new JMenuItem(bundle.getString("convert.protobuf.supervised.title"));
274         supervisedProtobufConvertMenuItem.addActionListener(new ChangeMenuToPanelListener(SupervisedProtobufConvertPanel.class, supervisedProtobufConvertMenuItem.getText()));
275         convertMenu.add(supervisedProtobufConvertMenuItem);
276     }
277 
278     private void createAndroidMenu() {
279         JMenu androidMenu = new JMenu(bundle.getString("android.title"));
280         menuBar.add(androidMenu);
281 
282         JMenuItem i18nAddMenuItem = new JMenuItem(bundle.getString("android.i18n.add.title"));
283         i18nAddMenuItem.addActionListener(new ChangeMenuToPanelListener(I18nAddPanel.class, i18nAddMenuItem.getText()));
284         androidMenu.add(i18nAddMenuItem);
285 
286         JMenuItem i18nFindLongestMenuItem = new JMenuItem(bundle.getString("android.i18n.longest.title"));
287         i18nFindLongestMenuItem.addActionListener(new ChangeMenuToPanelListener(I18nFindLongestPanel.class, i18nFindLongestMenuItem.getText()));
288         androidMenu.add(i18nFindLongestMenuItem);
289 
290         JMenuItem i18nRemoveMenuItem = new JMenuItem(bundle.getString("android.i18n.remove.title"));
291         i18nRemoveMenuItem.addActionListener(new ChangeMenuToPanelListener(I18nRemovePanel.class, i18nRemoveMenuItem.getText()));
292         androidMenu.add(i18nRemoveMenuItem);
293 
294         JMenuItem screenShotMenuItem = new JMenuItem(bundle.getString("android.screenshot.title"));
295         screenShotMenuItem.addActionListener(new ChangeMenuToPanelListener(ScreenShotPanel.class, screenShotMenuItem.getText()));
296         screenShotMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK));
297         androidMenu.add(screenShotMenuItem);
298 
299         JMenuItem monkeyMenuItem = new JMenuItem(bundle.getString("android.monkey.title"));
300         monkeyMenuItem.addActionListener(new ChangeMenuToPanelListener(MonkeyPanel.class, monkeyMenuItem.getText()));
301         androidMenu.add(monkeyMenuItem);
302 
303         JMenuItem dumpsysMenuItem = new JMenuItem(bundle.getString("android.dumpsys.title"));
304         dumpsysMenuItem.addActionListener(new ChangeMenuToPanelListener(DumpsysPanel.class, dumpsysMenuItem.getText()));
305         androidMenu.add(dumpsysMenuItem);
306     }
307 
308     private void createReverseMenu() {
309         JMenu reverseMenu = new JMenu(bundle.getString("reverse.title"));
310         reverseMenu.setMnemonic(KeyEvent.VK_R);
311         menuBar.add(reverseMenu);
312 
313         JMenuItem pluginVersionMenuItem = new JMenuItem(bundle.getString("reverse.plugin.version.title"));
314         pluginVersionMenuItem.addActionListener(new ChangeMenuToUrlListener(Constant.URL_PLUGIN_VERSION));
315         reverseMenu.add(pluginVersionMenuItem);
316 
317         JMenuItem apktoolMenuItem = new JMenuItem(bundle.getString("reverse.apktool.title"), KeyEvent.VK_D);
318         apktoolMenuItem.addActionListener(new ChangeMenuToPanelListener(ApktoolPanel.class, apktoolMenuItem.getText()));
319         reverseMenu.add(apktoolMenuItem);
320 
321         JMenuItem apkSignMenuItem = new JMenuItem(bundle.getString("reverse.apksigner.title"));
322         apkSignMenuItem.addActionListener(new ChangeMenuToPanelListener(ApkSignerPanel.class, apkSignMenuItem.getText()));
323         reverseMenu.add(apkSignMenuItem);
324 
325         JMenuItem jDMenuItem = new JMenuItem(bundle.getString("reverse.jd.gui.title"));
326         jDMenuItem.addActionListener(new ChangeMenToPluginJdListener());
327         reverseMenu.add(jDMenuItem);
328 
329         JMenuItem bytecodeViewerMenuItem = new JMenuItem(bundle.getString("reverse.bytecode.viewer.title"));
330         bytecodeViewerMenuItem.addActionListener(new ChangeMenuToPluginBytecodeViewerListener());
331         reverseMenu.add(bytecodeViewerMenuItem);
332 
333         JMenuItem luytenMenuItem = new JMenuItem(bundle.getString("reverse.luyten.title"));
334         luytenMenuItem.addActionListener(new ChangeMenuToPluginLuytenListener());
335         reverseMenu.add(luytenMenuItem);
336 
337         JMenuItem jdDuoMenuItem = new JMenuItem(bundle.getString("reverse.jd.duo.title"));
338         jdDuoMenuItem.addActionListener(new ChangeMenuToPluginJdDuoListener());
339         reverseMenu.add(jdDuoMenuItem);
340 
341         JMenuItem jdaMenuItem = new JMenuItem(bundle.getString("reverse.jda.title"));
342         jdaMenuItem.addActionListener(new ChangeMenuToPluginJdaListener());
343         reverseMenu.add(jdaMenuItem);
344 
345         JMenuItem jADXMenuItem = new JMenuItem(bundle.getString("reverse.jadx.title"));
346         jADXMenuItem.addActionListener(new ChangeMenuToPluginJadxListener());
347         reverseMenu.add(jADXMenuItem);
348 
349         JMenuItem aXMLPrinter = new JMenuItem(bundle.getString("reverse.axmlprinter.title"));
350         aXMLPrinter.addActionListener(new ChangeMenuToPanelListener(AxmlPrinterPanel.class, aXMLPrinter.getText()));
351         reverseMenu.add(aXMLPrinter);
352     }
353 
354     class ChangeMenuToPanelListener implements ChangeMenuListener {
355 
356         Class<? extends EasyPanel> easyPanelClass;
357 
358         EasyPanel panel = null;
359 
360         String title;
361 
362         public ChangeMenuToPanelListener(Class<? extends EasyPanel> easyPanelClass, String title) {
363             this.easyPanelClass = easyPanelClass;
364             this.title = title;
365             panel = createEasyPanel();
366         }
367 
368         @Override
369         public boolean isNeedPreChangeMenu() {
370             return panel.isNeedPreChangeMenu();
371         }
372 
373         @Override
374         public void onPreChangeMenu(IPreChangeMenuCallBack callBack) {
375             if (panel instanceof PluginPanel pluginPanel) {
376                 pluginPanel.preparePlugin(new ChangeMenuPreparePluginController(pluginPanel.getPluginFilename(), pluginPanel.isPluginNeedUnzip(), pluginPanel.isPluginNeedUnzipToSeparateDir(), callBack));
377             }
378         }
379 
380         @Override
381         public void onChangeMenu() {
382             UiStateKeeper.save(currentEasyPanel);
383             contentPane.removeAll();
384             contentPane.add(Box.createVerticalGlue());
385             panel.init();
386             panel.setBorder(BorderFactory.createTitledBorder(title));
387             contentPane.add(panel);
388             logger.info("Panel changed: " + panel.getClass().getSimpleName());
389             contentPane.add(Box.createVerticalGlue());
390             contentPane.revalidate();
391             contentPane.repaint();
392             refreshSizeAndLocation();
393             panel.afterPainted();
394             UiStateKeeper.restore(panel);
395             currentEasyPanel = panel;
396         }
397 
398         private EasyPanel createEasyPanel() {
399             if (easyPanelClass == null) {
400                 return new EasyPanel();
401             }
402             EasyPanel retEasyPanel = null;
403             try {
404                 retEasyPanel = easyPanelClass.getDeclaredConstructor().newInstance();
405             } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
406                      NoSuchMethodException e) {
407                 logger.info("createEasyPanel failed: {}", e.getMessage());
408             }
409             return Objects.requireNonNullElseGet(retEasyPanel, EasyPanel::new);
410         }
411     }
412 
413     @Override
414     protected void onWindowClosing(WindowEvent e) {
415         super.onWindowClosing(e);
416         UiStateKeeper.save(currentEasyPanel);
417     }
418 
419     @Override
420     protected void onWindowIconified(WindowEvent e) {
421         super.onWindowIconified(e);
422         UiStateKeeper.save(currentEasyPanel);
423     }
424 }