Skip to content

Commit a724112

Browse files
author
Simon Pinfold
committed
- Added colorisation to the message log
- Message log now displays pretty-printed XML of command response parameters
1 parent 436a1c9 commit a724112

File tree

3 files changed

+136
-17
lines changed

3 files changed

+136
-17
lines changed

app/src/main/java/com/imgtec/hobbyist/fragments/menu/InteractiveModeFragment.java

Lines changed: 80 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
import android.os.Bundle;
2323
import android.os.Handler;
2424
import android.support.v4.app.Fragment;
25+
import android.text.Html;
26+
import android.text.Spanned;
27+
import android.text.TextUtils;
28+
import android.util.Log;
2529
import android.view.LayoutInflater;
2630
import android.view.View;
2731
import android.view.ViewGroup;
@@ -47,6 +51,7 @@
4751
import com.imgtec.hobbyist.flow.DevicePresenceListener;
4852
import com.imgtec.hobbyist.flow.FlowEntities;
4953
import com.imgtec.hobbyist.flow.FlowHelper;
54+
import com.imgtec.hobbyist.fragments.menu.setupguide.SpannedAdapter;
5055
import com.imgtec.hobbyist.fragments.navigationdrawer.NDListeningFragment;
5156
import com.imgtec.hobbyist.fragments.navigationdrawer.NDMenuItem;
5257
import com.imgtec.hobbyist.utils.BackgroundExecutor;
@@ -60,6 +65,8 @@
6065
import com.imgtec.hobbyist.utils.WifiUtil;
6166
import com.imgtec.hobbyist.views.InstantAutoCompleteTextView;
6267

68+
import java.io.StringReader;
69+
import java.io.StringWriter;
6370
import java.util.ArrayList;
6471
import java.util.Calendar;
6572
import java.util.Date;
@@ -68,6 +75,13 @@
6875
import java.util.Locale;
6976
import java.util.concurrent.CopyOnWriteArrayList;
7077

78+
import javax.xml.transform.OutputKeys;
79+
import javax.xml.transform.Transformer;
80+
import javax.xml.transform.TransformerException;
81+
import javax.xml.transform.TransformerFactory;
82+
import javax.xml.transform.stream.StreamResult;
83+
import javax.xml.transform.stream.StreamSource;
84+
7185
/**
7286
* Fragment used to interact with Board through Flow.
7387
* There are two modes: Commands and Messages.
@@ -80,9 +94,9 @@ public class InteractiveModeFragment extends NDListeningFragment implements Asyn
8094

8195
public static final String TAG = "InteractiveModeFragment";
8296

83-
public static final String TX_MESSAGE = "TX message:\n";
84-
public static final String RX_MESSAGE = "RX message:\n";
85-
public static final String CMD_MESSAGE = "Received message:\n";
97+
public static final String TX_MESSAGE = "<b>TX message:</b>";
98+
public static final String RX_MESSAGE = "<b>RX message:</b>";
99+
public static final String CMD_MESSAGE = "<b>Received message:</b>";
86100
private RadioGroup interactiveModeChoice;
87101
private TextView deviceName;
88102
private EditText messageText;
@@ -91,8 +105,8 @@ public class InteractiveModeFragment extends NDListeningFragment implements Asyn
91105
private Button clearButton;
92106
private Button searchUsersButton;
93107
private ListView messagesListView;
94-
private List<String> messageList = new CopyOnWriteArrayList<>();
95-
private ArrayAdapter<String> messageListAdapter;
108+
private List<Spanned> messageList = new CopyOnWriteArrayList<>();
109+
private SpannedAdapter messageListAdapter;
96110
private ConnectivityReceiver connectionReceiver;
97111

98112
private boolean isCommandMode = true;
@@ -158,7 +172,7 @@ private void initFlowHelper() {
158172
}
159173

160174
private void initListAdapter() {
161-
messageListAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, messageList);
175+
messageListAdapter = new SpannedAdapter(getActivity(), android.R.layout.simple_list_item_1, messageList);
162176
messagesListView.setAdapter(messageListAdapter);
163177
}
164178

@@ -319,8 +333,8 @@ public void execute() {
319333
} catch (FlowException e) {
320334
DebugLogger.log(getClass().getSimpleName(), e);
321335
ActivitiesAndFragmentsHelper.showToast(appContext,
322-
ErrorHtmlLogger.log(FlowEntities.getInstance(appContext).getLastError()),
323-
handler);
336+
ErrorHtmlLogger.log(FlowEntities.getInstance(appContext).getLastError()),
337+
handler);
324338
}
325339
}
326340
});
@@ -332,7 +346,9 @@ public void execute() {
332346
* @param commandString previously sent command text.
333347
*/
334348
private void showCommandTXMessage(String commandString) {
335-
messageList.add(0, TX_MESSAGE + DateFormatter.now(appContext) + "\n" + commandString + "\n");
349+
messageList.add(0, Html.fromHtml("<font color='#006400'>" + TX_MESSAGE + "<br/>" +
350+
DateFormatter.now(appContext) + "<br/>" +
351+
TextUtils.htmlEncode(commandString) + "<br/></font>"));
336352
removeMessageIfListIsTooLong();
337353
notifyMessageListAdapter();
338354
}
@@ -373,7 +389,7 @@ public void onAsyncMessageResponse(MessagingEvent.AsyncMessageResponse response)
373389
responseText = "";
374390
break;
375391
}
376-
messageList.add(0, "Command " + responseText);
392+
messageList.add(0, Html.fromHtml("<font color='fuchsia'><b>Response:</b> " + TextUtils.htmlEncode(responseText) + "</font>"));
377393
removeMessageIfListIsTooLong();
378394
notifyMessageListAdapter();
379395
setCommandUIEnabled(true);
@@ -395,7 +411,7 @@ public void onCommandRXMessageReceived(final AsyncMessage msg) {
395411
public void run() {
396412
if (isCommandMode) {
397413
String commandText = commandEditText.getText().toString();
398-
if (commandText.equalsIgnoreCase(Command.REBOOT.getCommand()) || commandText.equalsIgnoreCase(Command.REBOOT_SOFTAP.getCommand())) {
414+
if (commandText.equalsIgnoreCase(Command.REBOOT.getCommand()) || commandText.equalsIgnoreCase(Command.GET_STATUS.getCommand())) {
399415
reactOnRebootCommand();
400416
}
401417
}
@@ -426,14 +442,58 @@ public void onCommandMessageReceived(AsyncMessage msg) {
426442
* @param msg AsyncMessage object which can be parsed to get additional data.
427443
*/
428444
private void showCommandRXMessage(AsyncMessage msg) {
429-
messageList.add(0, RX_MESSAGE + DateFormatter.now(appContext) + "\n" + commandEditText.getText().toString()
430-
+ " " + msg.getNode(AsyncMessageNodeKeys.RESPONSE_CODE) + msg.getNode(AsyncMessageNodeKeys.RESPONSE_PARAMS));
445+
String html = RX_MESSAGE + "<br/>" +
446+
DateFormatter.now(appContext) + "<br/>" +
447+
Html.fromHtml(commandEditText.getText().toString()).toString() + " &#8594; " +
448+
Html.fromHtml(msg.getNode(AsyncMessageNodeKeys.RESPONSE_CODE)).toString() + "<br/>";
449+
String params = msg.getNode(AsyncMessageNodeKeys.RESPONSE_PARAMS);
450+
if (params != null && !params.equals("")) {
451+
try {
452+
html += "</font><font color='#4169E1'>" + formatXML(params) + "</font>";
453+
} catch (TransformerException e) {
454+
e.printStackTrace();
455+
Log.e("InteractiveModeFragment.showCommandRXMessage", "Failed to format response parameters from command", e);
456+
html += "</font><font color='red'>Error formatting response \"" + params + "\"</font>";
457+
}
458+
} else {
459+
html += "</font><font color='black'>No response parameters</font>";
460+
}
461+
messageList.add(0, Html.fromHtml("<font color='blue'>" + html + "</font>"));
431462
removeMessageIfListIsTooLong();
432463
notifyMessageListAdapter();
433464
}
434465

435-
private void showCommandMessage(AsyncMessage msg) {
436-
messageList.add(0, CMD_MESSAGE + DateFormatter.now(appContext) + "\n" + msg.getNode(AsyncMessageNodeKeys.DETAILS));
466+
private String formatXML(String input) throws TransformerException {
467+
// adapted from http://stackoverflow.com/a/139096
468+
469+
// add on temporary tags to ensure correct parsing
470+
// this is necessary as we are pretty-printing <i>part</i>
471+
// of a XML document, so we allow a simple string (content)
472+
// and allow multiple children at the "root" level
473+
input = "<t>" + input + "</t>";
474+
475+
Transformer transformer = TransformerFactory.newInstance().newTransformer();
476+
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
477+
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
478+
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
479+
StreamResult result = new StreamResult(new StringWriter());
480+
StreamSource source = new StreamSource(new StringReader(input));
481+
transformer.transform(source, result);
482+
String xmlString = result.getWriter().toString();
483+
484+
// remove temporary tags and newlines at beginning and end
485+
xmlString = xmlString.substring(3, xmlString.length()-5).replaceAll("(?m)^\\s*\r?\n", "");
486+
if (xmlString.endsWith("\n")) xmlString = xmlString.substring(0, xmlString.length()-2);
487+
488+
// if this is a one-line string then add a tab to the beginning
489+
if (!xmlString.contains("\n")) xmlString = "\t" + xmlString;
490+
491+
return TextUtils.htmlEncode(xmlString).replace("\n", "<br>").replace("\t", " ").replace(" ", "&nbsp;");
492+
}
493+
494+
private void showCommandMessage(AsyncMessage msg) {
495+
messageList.add(0, Html.fromHtml( CMD_MESSAGE + DateFormatter.now(appContext) + "<br/>" +
496+
Html.fromHtml(msg.getNode(AsyncMessageNodeKeys.DETAILS)).toString()));
437497
removeMessageIfListIsTooLong();
438498
notifyMessageListAdapter();
439499
}
@@ -492,8 +552,11 @@ private void showTextMessagesFromHourAgoOn() {
492552
* @param msg AsyncMessage object which can be parsed to get additional data.
493553
*/
494554
private void addTextMessage(AsyncMessage msg) {
495-
messageList.add(0, DateFormatter.formatForDisplay(msg.getNode(AsyncMessageNodeKeys.SENT_WITH_TYPE_INFO), appContext)
496-
+ "\n" + msg.getNode(AsyncMessageNodeKeys.FROM) + ":\n" + msg.getNode(AsyncMessageNodeKeys.MESSAGE));
555+
messageList.add(0, Html.fromHtml(DateFormatter.formatForDisplay(msg.getNode(AsyncMessageNodeKeys.SENT_WITH_TYPE_INFO), appContext) + "<br/>" +
556+
msg.getNode(AsyncMessageNodeKeys.FROM) + ":<br/>" +
557+
Html.fromHtml(msg.getNode(AsyncMessageNodeKeys.MESSAGE)).toString()
558+
)
559+
);
497560
}
498561

499562
/**
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.imgtec.hobbyist.fragments.menu.setupguide;
2+
3+
import android.content.Context;
4+
import android.text.Spanned;
5+
import android.view.LayoutInflater;
6+
import android.view.View;
7+
import android.view.ViewGroup;
8+
import android.widget.ArrayAdapter;
9+
import android.widget.TextView;
10+
11+
import com.imgtec.hobbyist.R;
12+
13+
import java.util.List;
14+
15+
/**
16+
* Created by simon.pinfold on 27/01/2015.
17+
*/
18+
public class SpannedAdapter extends ArrayAdapter<Spanned> {
19+
private LayoutInflater mInflater;
20+
21+
public SpannedAdapter(Context context, int resource, List<Spanned> articleList) {
22+
super(context, resource, articleList);
23+
mInflater = LayoutInflater.from(context);
24+
}
25+
26+
public View getView(int position, View convertView, ViewGroup parent) {
27+
ViewHolder holder;
28+
if (convertView == null) {
29+
convertView = mInflater.inflate(R.layout.single_row, null);
30+
holder = new ViewHolder();
31+
holder.text = (TextView) convertView.findViewById(R.id.singleRow);
32+
33+
convertView.setTag(holder);
34+
} else {
35+
holder = (ViewHolder) convertView.getTag();
36+
}
37+
38+
holder.text.setText(getItem(position));
39+
40+
return convertView;
41+
}
42+
43+
static class ViewHolder {
44+
TextView text;
45+
}
46+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:orientation="vertical" android:layout_width="match_parent"
4+
android:layout_height="match_parent">
5+
6+
<TextView
7+
android:layout_width="wrap_content"
8+
android:layout_height="wrap_content"
9+
android:id="@+id/singleRow" />
10+
</LinearLayout>

0 commit comments

Comments
 (0)