package com.applang.components;
import static com.applang.Util.*;
import static com.applang.Util2.*;
import static com.applang.SwingUtil.*;
import static com.applang.PluginUtils.*;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.Writer;
import java.util.List;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import org.apache.commons.lang.StringUtils;
import org.gjt.sp.jedit.View;
import com.applang.berichtsheft.BerichtsheftApp;
import com.applang.berichtsheft.plugin.BerichtsheftPlugin;
public class AndroidBridge
{
private static final int behavior = Behavior.MODAL;
public static void main(String...args) {
BerichtsheftApp.loadSettings();
println(chooseFileFromSdcard(null, false, null));
System.exit(0);
}
// NOTE used in scripts
@SuppressWarnings({ "rawtypes", "unchecked" })
public static String chooseFileFromSdcard(final View view, final boolean onlyDirs, final String androidFileName) {
final Object[] devices = deviceInfo(null);
if (notAvailable(0, devices) || nullOrEmpty(devices[0])) {
BerichtsheftPlugin.consoleMessage("berichtsheft.android-devices.message");
return null;
}
final String title = "Android file";
final String sd = "/sdcard/";
final JTextField itemField = new JTextField();
final JLabel[] labels = new JLabel[]{new JLabel("Device"), new JLabel("")};
final JList[] lists = new JList[]{new JList(devices), new JList()};
final Function<List> fileLister = new Function<List>() {
public List apply(Object... params) {
List<Object> list = asList(params);
DefaultListModel model = defaultListModel(list);
lists[1].setModel(model);
return list;
}
};
final Function<Boolean> highLiter = new Function<Boolean>() {
public Boolean apply(Object... params) {
Object item = param(null, 0, params);
JList list = param(null, 1, params);
ListModel model = list.getModel();
for (int i = 0; i < model.getSize(); i++)
if (model.getElementAt(i).equals(item)) {
list.setSelectedIndex(i);
list.ensureIndexIsVisible(i);
return true;
}
return false;
}
};
AncestorListener ancestorListener = new AncestorListener() {
public void ancestorRemoved(AncestorEvent event) {
}
public void ancestorMoved(AncestorEvent event) {
}
public void ancestorAdded(AncestorEvent event) {
if (notNullOrEmpty(androidFileName) && androidFileName.contains("|")) {
ValList parts = splitAndroidFileName(androidFileName);
String device = parts.get(0).toString();
File file = new File(parts.get(1).toString());
int index = asList(devices).indexOf(device);
if (index > -1) {
lists[0].setSelectedValue(devices[index], true);
String dir = file.getParent() + "/";
labels[1].setText(dir);
fileLister.apply(deviceInfo(device, dir, onlyDirs));
String name = file.getName();
if (!highLiter.apply(name, lists[1]))
highLiter.apply(name + "/", lists[1]);
itemField.setText(name);
}
}
}
};
final JPanel panel = new JPanel() {
@Override
public void add(Component comp, Object constraints) {
GridBagConstraints gbc = (GridBagConstraints) constraints;
Writer writer = write(null, "[");
writer = write_assoc(writer, "gridx", gbc.gridx);
writer = write_assoc(writer, "gridy", gbc.gridy, 1);
writer = write_assoc(writer, "gridwidth", gbc.gridwidth, 1);
writer = write_assoc(writer, "gridheight", gbc.gridheight, 1);
writer = write_assoc(writer, "anchor", gbc.anchor, 1);
no_println(write(writer, "]").toString());
super.add(comp, constraints);
}
};
MouseAdapter clickListener = new MouseAdapter() {
public void mouseClicked(MouseEvent ev) {
boolean doubleClick = ev.getClickCount() == 2;
JList list = (JList) ev.getSource();
String dir = null, device = null;
String item = (String) list.getSelectedValue();
if (list.equals(lists[1])) {
dir = labels[1].getText();
if (doubleClick) {
if (item.equals("..")) {
String regex = "[^/]+/$";
item = findFirstIn(dir, Pattern.compile(regex))
.group();
dir = dir.replaceFirst(regex, "");
} else if (item.endsWith("/")) {
dir += item;
item = null;
}
}
device = stringValueOf(lists[0].getSelectedValue());
if (item != null && item.trim().equals("."))
item = null;
}
else if (item != null) {
dir = sd;
device = item;
item = "";
}
labels[1].setText(dir);
fileLister.apply(deviceInfo(device, dir, onlyDirs));
highLiter.apply(item, list);
itemField.setText(item);
}
};
panel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
for (int i = 0; i < lists.length; i++) {
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = i;
gbc.gridy = 0;
gbc.gridheight = 1;
switch (i) {
case 0:
panel.add(itemField, gbc);
gbc.gridy += 1;
break;
case 1:
JPanel p = new JPanel();
JButton[] buttons = new JButton[2];
buttons[0] = new JButton("add");
buttons[0].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String name = stringValueOf(itemField.getText());
if (name.length() > 0) {
String dir = stringValueOf(labels[1].getText());
String device = stringValueOf(lists[0].getSelectedValue());
if (deviceOperation("mkdir", device, dir, name, fileLister))
highLiter.apply(name, lists[1]);
}
}
});
p.add(buttons[0]);
buttons[1] = new JButton("remove");
buttons[1].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String name = stringValueOf(itemField.getText());
if (name.length() > 0) {
String dir = stringValueOf(labels[1].getText());
String quest = "Do you really want to remove '%s'";
if (name.endsWith("/"))
quest += "\nand all files within this directory";
if (question(String.format(quest, dir + name))) {
String device = stringValueOf(lists[0].getSelectedValue());
if (deviceOperation("rm", device, dir, name, fileLister))
itemField.setText("");
}
}
}
});
p.add(buttons[1]);
panel.add(p, gbc);
gbc.gridy += 1;
break;
}
panel.add(labels[i], gbc);
gbc.fill = GridBagConstraints.BOTH;
gbc.gridy += 1;
gbc.gridheight = 1;
lists[i].setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
lists[i].addMouseListener(clickListener);
panel.add(new JScrollPane(lists[i]), gbc);
}
int dialogResult = showResizableDialog(panel, ancestorListener, new Function<Integer>() {
public Integer apply(Object...params) {
JScrollPane scrollPane = new JScrollPane((Component) params[0]);
return showOptionDialog(view, scrollPane, title,
JOptionPane.OK_CANCEL_OPTION + behavior,
JOptionPane.PLAIN_MESSAGE,
null,
null, null);
}
});
if (JOptionPane.OK_OPTION == dialogResult) {
String device = stringValueOf(lists[0].getSelectedValue());
String path = stringValueOf(labels[1].getText());
String name = stringValueOf(lists[1].getSelectedValue());
return joinAndroidFileName(device, path + name);
}
return null;
}
@SuppressWarnings("rawtypes")
public static boolean deviceOperation(String oper, String device, String dir, String name, Function<List> fileLister) {
boolean isDirectory = name.endsWith("/");
if ("mkdir".equals(oper)) {
if (!isDirectory) {
message(getProperty("berichtsheft.android-sdcard-directory.message"));
return false;
}
}
else if ("rm".equals(oper)) {
if (isDirectory)
oper = "rm -r";
}
String cmd = buildAdbCommand(oper, joinAndroidFileName(device, dir + name), "");
String response = runShellScript("cmd", cmd);
List files = fileLister.apply(deviceInfo(device, dir));
if (oper.startsWith("mk") && files.contains(name))
response = null;
else if (oper.startsWith("rm") && !files.contains(name))
response = null;
if (notNullOrEmpty(response))
message(response);
return response == null;
}
public static Object[] deviceInfo(String device, Object...params) {
String dir = param_String(null, 0, params);
boolean onlyDirs = param(false, 1, params);
String script, response;
Object[] array;
if (dir != null) {
script = "gsub(/[ \\t\\r\\n\\f\\v\\b]+$/, \"\", $NF) ;";
script += " m = match($0, /d/) ;";
script += " if (m == 1) print $NF\"/\"";
if (!onlyDirs)
script += " ; else print $NF";
script = awkCommand("{" + script + "}");
script = adbScript(device, "shell ls -l \"" + dir + "\" | " + script);
response = runShellScript("ls", script);
ValList list = split(response, NEWLINE_REGEX);
list.add(0, "." + repeat(" ", 30));
MatchResult[] mr = findAllIn(dir, Pattern.compile("/"));
if (mr.length > 2)
list.add(0, "..");
array = sortedSet(list).toArray();
}
else {
script = awkCommand("NR > 1 {print $1}");
script = adbScript(null, "devices | " + script);
response = runShellScript("dev", script);
array = split(response, NEWLINE_REGEX).toArray();
}
return array;
}
public static ValList splitAndroidFileName(String androidFileName) {
ValList parts = split(androidFileName, GLUE_REGEX, 2);
if (parts.size() < 2)
parts.add(0, "");
return parts;
}
public static String joinAndroidFileName(Object...parts) {
return strip(Constraint.END, join(GLUE, parts), GLUE);
}
public static String getAdbCommand() {
return BerichtsheftPlugin.getCommand("ADB_COMMAND");
}
public static String adbScript(String device, String part) {
String cmd = getAdbCommand();
if (notNullOrEmpty(device))
cmd += " -s " + device;
cmd += " " + part;
return cmd;
}
public static String adbRestart() {
String[] commands = strings(
adbScript(null, "kill-server"),
adbScript(null, "start-server"),
adbScript(null, "version")
);
return runShellScript("cmd", join(NEWLINE, commands));
}
public static String buildAdbCommand(String oper, String androidFileName, String fileName) {
if (oper.endsWith("mkdir"))
oper = "shell mkdir";
else if (oper.endsWith("rmdir"))
oper = "shell rmdir";
else if (oper.endsWith("rm"))
oper = "shell rm";
else if (oper.endsWith("-r"))
oper = "shell rm -r";
else if (!oper.startsWith("pu"))
oper = "version";
Object device = null;
ValList parts = splitAndroidFileName(androidFileName);
if (parts.size() > 1) {
device = parts.get(0);
parts.set(0, oper);
}
else {
parts.sizeAtLeast(2);
parts.set(0, oper);
}
parts.set(1, enclose("\"", stringValueOf(parts.get(1))));
fileName = enclose("\"", fileName);
if ("push".equals(oper))
parts.add(1, fileName);
else if ("pull".equals(oper))
parts.add(2, fileName);
String cmd = join(" ", parts.toArray());
return adbScript(stringValueOf(device), cmd);
}
public static String awkCommand(String part) {
String cmd = getProperty("AWK_COMMAND");
return cmd + " " + enclose("'", part);
}
public static String repeat(String string, int times) {
return StringUtils.repeat(string, times);
}
}