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
53
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 }