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