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