DumpsysAlarmPanel.java
package edu.jiangxin.apktoolbox.android.dumpsys.alarm;
import edu.jiangxin.apktoolbox.file.core.EncoderDetector;
import edu.jiangxin.apktoolbox.swing.extend.EasyPanel;
import edu.jiangxin.apktoolbox.swing.treetable.MyAbstractTreeTableModel;
import edu.jiangxin.apktoolbox.swing.treetable.MyTreeTable;
import edu.jiangxin.apktoolbox.utils.Constants;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
public class DumpsysAlarmPanel extends EasyPanel {
private JPanel operationPanel;
private JPanel lastDateTimePanel;
private JTextField lastDateTimeField;
private JPanel systemUptime1Panel;
private JTextField systemUptime1Field;
private JPanel systemUptime2Panel;
private JTextField systemUptime2Field;
private JPanel packagePanel;
private JTextField packageField;
private JTabbedPane tabbedPane;
private JPanel tabularFormTabPanel;
private JPanel rawSourceTabPanel;
private JEditorPane editorPane;
private List<AlarmTreeTableDataNode> children;
private String alarmInfoString;
private boolean alarmInfoValid;
public DumpsysAlarmPanel() throws HeadlessException {
super();
}
@Override
public void initUI() {
BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS);
setLayout(boxLayout);
createOptionPanel();
add(operationPanel);
add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
createLastDateTimePanel();
add(lastDateTimePanel);
add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
createSystemUptime1Panel();
add(systemUptime1Panel);
add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
createSystemUptime2Panel();
add(systemUptime2Panel);
add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
createPackagePanel();
add(packagePanel);
add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
createTabbedPane();
add(tabbedPane);
}
private void createOptionPanel() {
operationPanel = new JPanel();
operationPanel.setLayout(new BoxLayout(operationPanel, BoxLayout.X_AXIS));
JButton loadFromDeviceButton = new JButton("Load From Device");
loadFromDeviceButton.addActionListener(new LoadFromDeviceButtonActionListener());
JButton loadFromFileButton = new JButton("Load From File");
loadFromFileButton.addActionListener(new LoadFromFileButtonActionListener());
operationPanel.add(loadFromDeviceButton);
operationPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
operationPanel.add(loadFromFileButton);
operationPanel.add(Box.createHorizontalGlue());
}
private void createLastDateTimePanel() {
lastDateTimePanel = new JPanel();
lastDateTimePanel.setLayout(new BoxLayout(lastDateTimePanel, BoxLayout.X_AXIS));
JLabel lastDateTimeLabel = new JLabel("Last DateTime");
lastDateTimeField = new JTextField();
lastDateTimePanel.add(lastDateTimeLabel);
lastDateTimePanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
lastDateTimePanel.add(lastDateTimeField);
}
private void createSystemUptime1Panel() {
systemUptime1Panel = new JPanel();
systemUptime1Panel.setLayout(new BoxLayout(systemUptime1Panel, BoxLayout.X_AXIS));
JLabel systemUptime1Label = new JLabel("System Uptime(ms)");
systemUptime1Field = new JTextField();
systemUptime1Panel.add(systemUptime1Label);
systemUptime1Panel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
systemUptime1Panel.add(systemUptime1Field);
}
private void createSystemUptime2Panel() {
systemUptime2Panel = new JPanel();
systemUptime2Panel.setLayout(new BoxLayout(systemUptime2Panel, BoxLayout.X_AXIS));
JLabel systemUptime2Label = new JLabel("System Uptime");
systemUptime2Field = new JTextField();
systemUptime2Panel.add(systemUptime2Label);
systemUptime2Panel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
systemUptime2Panel.add(systemUptime2Field);
}
private void createPackagePanel() {
packagePanel = new JPanel();
packagePanel.setLayout(new BoxLayout(packagePanel, BoxLayout.X_AXIS));
JLabel packageLabel = new JLabel("Package");
packageField = new JTextField();
packagePanel.add(packageLabel);
packagePanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
packagePanel.add(packageField);
}
private void createTabbedPane() {
tabbedPane = new JTabbedPane();
tabularFormTabPanel = new JPanel();
createTable();
tabbedPane.addTab("Tabular Form", null, tabularFormTabPanel, "Tabular Form");
rawSourceTabPanel = new JPanel();
createRawSource();
tabbedPane.addTab("Raw source", null, rawSourceTabPanel, "Raw source");
}
private void createTable() {
children = new ArrayList<>();
AlarmTreeTableDataNode root = new AlarmTreeTableDataNode("Root", "", "", "", "", children);
MyAbstractTreeTableModel treeTableModel = new AlarmTreeTableDataModel(root);
MyTreeTable myTreeTable = new MyTreeTable(treeTableModel);
JScrollPane scrollPane = new JScrollPane(myTreeTable);
scrollPane.setPreferredSize(new Dimension(Constants.DEFAULT_SCROLL_PANEL_WIDTH, Constants.DEFAULT_SCROLL_PANEL_HEIGHT));
tabularFormTabPanel.add(scrollPane);
}
private void createRawSource() {
editorPane = new JEditorPane("text/plain", "");
editorPane.setEditable(false);
JScrollPane scrollPane = new JScrollPane(editorPane);
scrollPane.setPreferredSize(new Dimension(Constants.DEFAULT_SCROLL_PANEL_WIDTH, Constants.DEFAULT_SCROLL_PANEL_HEIGHT));
rawSourceTabPanel.add(scrollPane);
}
private void getAlarmInfoStringFromDevice() {
final String cmd = "adb shell dumpsys alarm";
logger.info(cmd);
try (ByteArrayOutputStream outStream = new ByteArrayOutputStream();
ByteArrayOutputStream errStream = new ByteArrayOutputStream()
) {
CommandLine commandLine = CommandLine.parse(cmd);
DefaultExecutor exec = new DefaultExecutor();
PumpStreamHandler streamHandler = new PumpStreamHandler(outStream, errStream);
exec.setStreamHandler(streamHandler);
int exitValue = exec.execute(commandLine);
logger.info("exitValue: [" + exitValue + "]");
alarmInfoString = outStream.toString("UTF-8");
alarmInfoValid = !StringUtils.isEmpty(alarmInfoString);
if (!alarmInfoValid) {
alarmInfoString = errStream.toString("UTF-8");
}
} catch (IOException ioe) {
logger.error("exec fail", ioe.getMessage());
}
}
private void getAlarmInfoStringFromFile() {
JFileChooser jfc = new JFileChooser();
jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
jfc.setDialogTitle("Select a dumpsys alarm file");
int ret = jfc.showDialog(new JLabel(), null);
File file = jfc.getSelectedFile();
switch (ret) {
case JFileChooser.APPROVE_OPTION:
try {
alarmInfoString = FileUtils.readFileToString(file, Charset.forName(EncoderDetector.judgeFile(file.getCanonicalPath())));
alarmInfoValid = true;
} catch (IOException ex) {
logger.error("readFileToString failed", ex);
alarmInfoValid = false;
}
break;
default:
break;
}
}
private void updateUIFromString() {
alarmInfoString = StringUtils.isEmpty(alarmInfoString) ? "" : alarmInfoString;
editorPane.setText(alarmInfoString);
if (!alarmInfoValid) {
children.clear();
return;
}
String tmpInputString = alarmInfoString;
String timeInformation = StringUtils.substringBetween(alarmInfoString, "nowRTC=", "mLastTimeChangeClockTime=").trim().replace(" ", "=");
String[] components = timeInformation.split("=");
SharedData sharedData = SharedData.getInstance();
sharedData.setTimestamp(Long.valueOf(components[0]));
sharedData.setDateTime(components[1] + " " + components[2]);
sharedData.setUptimeMs(Long.valueOf(components[4]));
long uptimeSeconds = sharedData.getUptimeMs() / 1000;
long uptimeHours = uptimeSeconds / 3600;
long uptimeMinutes = (uptimeSeconds % 3600) / 60;
long uptimeSecs = uptimeSeconds % 60;
systemUptime1Field.setText(String.valueOf(sharedData.getUptimeMs()));
systemUptime2Field.setText(uptimeHours + ":" + uptimeMinutes + ":" + uptimeSecs);
lastDateTimeField.setText(sharedData.getDateTime());
String pendingAlarmBatchesCountStr = StringUtils.substringBetween(tmpInputString, "Pending alarm batches: ", System.getProperty("line.separator"));
int pendingAlarmBatches = Integer.valueOf(pendingAlarmBatchesCountStr);
tmpInputString = StringUtils.substringAfter(tmpInputString, "Pending alarm batches: ");
List<AlarmBatch> listBatches = new ArrayList<>();
while (true) {
String batchDefinition = StringUtils.substringBetween(tmpInputString, "Batch{", "}:" + System.getProperty("line.separator"));
if (StringUtils.isEmpty(batchDefinition)) {
break;
}
AlarmBatch alarmBatch = AlarmBatch.fromString(batchDefinition);
if (alarmBatch == null) {
break;
}
String alarmListDefinition = StringUtils.substringBetween(tmpInputString, "}:" + System.getProperty("line.separator"), "Batch{");
alarmListDefinition.replace("ELAPSED_WAKEUP", "ELAPSED").replace("RTC_WAKEUP", "ELAPSED").replace("RTC", "ELAPSED");
String[] alarmListTmp = alarmListDefinition.split("ELAPSED");
List<String> alarmList = new ArrayList<>();
for (int i = 0; i < alarmListTmp.length; i++) {
if (StringUtils.isNotEmpty(alarmListTmp[i]) && StringUtils.isNotBlank(alarmListTmp[i])) {
alarmList.add(alarmListTmp[i]);
}
}
for (int i = 0; i < alarmList.size(); ++i) {
Alarm alarm = Alarm.fromString(alarmList.get(i));
if (StringUtils.isNotEmpty(packageField.getText()) && StringUtils.equals(alarm.getOwnerPackageName(), packageField.getText())) {
continue;
}
alarmBatch.appendAlarm(alarm);
}
listBatches.add(alarmBatch);
if (listBatches.size() == pendingAlarmBatches) {
break;
}
tmpInputString = StringUtils.substringAfter(tmpInputString, "Batch{");
}
children.clear();
children.addAll(alarmBatches2AlarmTreeTableDataNodeList(listBatches));
}
private List<AlarmTreeTableDataNode> alarmBatches2AlarmTreeTableDataNodeList(List<AlarmBatch> listBatches) {
List<AlarmTreeTableDataNode> sonList = new ArrayList<>();
for (AlarmBatch alarmBatch : listBatches) {
List<AlarmTreeTableDataNode> grandsonList = new ArrayList<>();
List<Alarm> alarmList = alarmBatch.getListAlarms();
for (Alarm alarm : alarmList) {
String objectId = alarm.getSignature() + " [" + alarm.getId() + "]";
AlarmTreeTableDataNode grandson = new AlarmTreeTableDataNode(objectId, alarm.getOwnerPackageName(), alarm.getAlarmType(), String.valueOf(alarm.getWhen()),String.valueOf(alarm.getWhen()), null);
grandsonList.add(grandson);
}
String objectId = alarmBatch.getSignature() + " [" + alarmBatch.getId() + "] (" + alarmBatch.getAlarmCount() + " alarms)";
AlarmTreeTableDataNode son = new AlarmTreeTableDataNode(objectId, null, null, null, null, grandsonList);
sonList.add(son);
}
return sonList;
}
private final class LoadFromDeviceButtonActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
getAlarmInfoStringFromDevice();
updateUIFromString();
}
}
private final class LoadFromFileButtonActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
getAlarmInfoStringFromFile();
updateUIFromString();
}
}
}