2222import android .os .Bundle ;
2323import android .os .Handler ;
2424import 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 ;
2529import android .view .LayoutInflater ;
2630import android .view .View ;
2731import android .view .ViewGroup ;
4751import com .imgtec .hobbyist .flow .DevicePresenceListener ;
4852import com .imgtec .hobbyist .flow .FlowEntities ;
4953import com .imgtec .hobbyist .flow .FlowHelper ;
54+ import com .imgtec .hobbyist .fragments .menu .setupguide .SpannedAdapter ;
5055import com .imgtec .hobbyist .fragments .navigationdrawer .NDListeningFragment ;
5156import com .imgtec .hobbyist .fragments .navigationdrawer .NDMenuItem ;
5257import com .imgtec .hobbyist .utils .BackgroundExecutor ;
6065import com .imgtec .hobbyist .utils .WifiUtil ;
6166import com .imgtec .hobbyist .views .InstantAutoCompleteTextView ;
6267
68+ import java .io .StringReader ;
69+ import java .io .StringWriter ;
6370import java .util .ArrayList ;
6471import java .util .Calendar ;
6572import java .util .Date ;
6875import java .util .Locale ;
6976import 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 () + " → " +
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 (" " , " " );
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 /**
0 commit comments