package com.example.student.ledssh; //import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.app.Activity; import android.os.Environment; import android.support.design.widget.Snackbar; import android.view.View; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.TextView; import android.widget.Toast; import android.widget.ToggleButton; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import org.json.JSONArray; import org.json.JSONException; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Locale; import java.util.Properties; public class OperateLEDs extends Activity { public final static String USERNAME_KEY = "com.example.student.ledssh.USERNAME"; public final static String HOST_KEY = "com.example.student.ledssh.HOST"; public final static String PORT_KEY = "com.example.student.ledssh.PORT"; public final static String PRIVATEKEYFILENAME_KEY = "com.example.student.ledssh.PRIVATEKEYFILENAME"; public final static String PASSPHRASE_KEY = "com.example.student.ledssh.PASSPHRASE"; public final static int NUM_LEDS = 4; public final static int NUM_SENSORS = 2; // Video of LEDs WebView webView; int assigned_port; // Required for SSH local port forwarding // Sensor fields (text, data) held in arrays // (first = temperature, second = humidity) TextView sensorDataViews[]; Integer sensorValues[]; // Data related to the controller we want to contact protected String username; protected String host; protected int port; protected String privateKeyFileName; protected String passphrase; // Store the results and commands sent to the SSH server protected String JSON_text; protected String command_text; // Keep track of whether the network is ready private boolean network_available; // If we have a command executing, queue others to run // after it's completion. boolean command_in_progress; ArrayList pending_commands; // Keep the LED on/off status in an array protected int status_array[]; // Store the four LED control buttons in an array ToggleButton tbLedButtons[]; private class VideoTunnel extends AsyncTask { // Do the video stream work in here com.jcraft.jsch.Session session = null; ChannelExec channel = null; String lcommand_text = "VIDEO STREAM"; // local command only protected String doInBackground(Intent... intents) { if (isCancelled()) return ""; // For future cancelling functionality String result = ""; int count = intents.length; for (int i = 0; i < count; i++) { publishProgress(i); try { result = runVideo(); } catch (Exception e) { e.printStackTrace(); } finally { System.out.println("Done trying command: " + lcommand_text); } // Escape early if cancel() is called if (isCancelled()) break; } return result; } // This is called each time you call publishProgress() protected void onProgressUpdate(Integer... progress) { Snackbar.make(findViewById(R.id.activity_operate_leds), getString(R.string.sending_command_text) + " " + lcommand_text, Snackbar.LENGTH_LONG) .setAction("Action", null).show(); //Toast.makeText(getApplicationContext(), getString(R.string.sending_command_text)+" "+command_text, Toast.LENGTH_SHORT).show(); System.out.println(getString(R.string.sending_command_text)); } // This is called when doInBackground() is finished protected void onPostExecute(String result) { Snackbar.make(findViewById(R.id.activity_operate_leds), getString(R.string.command_completed_text) + " " + result, Snackbar.LENGTH_LONG) .setAction("Action", null).show(); System.out.println(getString(R.string.command_completed_text) + " " + result); tunnelAvailable(); // Call our webview setup method } String runVideo() throws IOException { JSch jsch = new JSch(); String result = ""; int lport = 0; int rport = 8080; // rport and rhost should be provided by the controller in a config method String rhost = "192.168.1.124"; String boundaddress ="127.0.0.1"; // Get the SD card root directory File currentFolder; currentFolder = new File(Environment.getExternalStorageDirectory() .getAbsolutePath()); //Toast.makeText(getApplicationContext(), currentFolder.toString(), Toast.LENGTH_LONG).show(); File idFile = new File(currentFolder, privateKeyFileName); assigned_port = 0; try { jsch.addIdentity(idFile.getAbsolutePath(), passphrase); session = jsch.getSession(username, host, port); // Avoid asking for key confirmation Properties prop = new Properties(); prop.put("StrictHostKeyChecking", "no"); prop.put("RequestTTY", "no"); assigned_port=session.setPortForwardingL(boundaddress, lport, rhost, rport); System.out.println("localhost:"+assigned_port+" -> "+rhost+":"+rport); session.setConfig(prop); //Toast toast = Toast.makeText(getApplicationContext(), "About to connect", Toast.LENGTH_LONG); //toast.show(); System.out.println("About to connect"); session.connect(); System.out.println("After connect, about to make channel"); // SSH Channel channel = (ChannelExec) session.openChannel("exec"); ByteArrayOutputStream stream = new ByteArrayOutputStream(); channel.setOutputStream(stream); // Execute command System.out.println("About to try command: " + lcommand_text); channel.setCommand(lcommand_text); channel.connect(1000); java.lang.Thread.sleep(1000); // a little delay result = stream.toString(); // won't get a result } catch (JSchException ex) { String s = ex.toString(); //Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show(); System.out.println("JSchException Tunnel *****************************"); System.out.println(s); //network_available = false; result = "Tunnel not available"; onDestroy(); } catch (InterruptedException ex) { String s = ex.toString(); System.out.println(s); onDestroy(); } System.out.println("Result of ssh tunnel connection: " + result); return result; } // end runVideo private void onDestroy() { if (channel != null) channel.disconnect(); if (session != null) session.disconnect(); } } private class RunSSHCommand extends AsyncTask { // Do the long-running work in here protected String doInBackground(Intent... intents) { if (isCancelled()) return ""; command_in_progress = true; String result = ""; int count = intents.length; for (int i = 0; i < count; i++) { publishProgress(i); try { result = tryCommand(); } catch (Exception e) { e.printStackTrace(); } finally { System.out.println("Done trying command. "); } // Escape early if cancel() is called if (isCancelled()) break; } return result; } // This is called each time you call publishProgress() protected void onProgressUpdate(Integer... progress) { Snackbar.make(findViewById(R.id.activity_operate_leds), getString(R.string.sending_command_text) + " " + command_text, Snackbar.LENGTH_LONG) .setAction("Action", null).show(); //Toast.makeText(getApplicationContext(), getString(R.string.sending_command_text)+" "+command_text, Toast.LENGTH_SHORT).show(); System.out.println(getString(R.string.sending_command_text)); //setProgressPercent(progress[0]); } // This is called when doInBackground() is finished protected void onPostExecute(String result) { Snackbar.make(findViewById(R.id.activity_operate_leds), getString(R.string.command_completed_text) + " " + result, Snackbar.LENGTH_LONG) .setAction("Action", null).show(); System.out.println(getString(R.string.command_completed_text) + " " + result); //Toast.makeText(getApplicationContext(), getString(R.string.command_completed_text), Toast.LENGTH_SHORT).show(); JSON_text = result; decodeCommandResults(); //showNotification("Downloaded " + result + " bytes"); } String tryCommand() throws IOException { JSch jsch = new JSch(); com.jcraft.jsch.Session session = null; String result = ""; // Get the SD card root directory File currentFolder; currentFolder = new File(Environment.getExternalStorageDirectory() .getAbsolutePath()); //Toast.makeText(getApplicationContext(), currentFolder.toString(), Toast.LENGTH_LONG).show(); File idFile = new File(currentFolder, privateKeyFileName); try { jsch.addIdentity(idFile.getAbsolutePath(), passphrase); session = jsch.getSession(username, host, port); // Avoid asking for key confirmation Properties prop = new Properties(); prop.put("StrictHostKeyChecking", "no"); prop.put("RequestTTY", "no"); session.setConfig(prop); //Toast toast = Toast.makeText(getApplicationContext(), "About to connect", Toast.LENGTH_LONG); //toast.show(); System.out.println("About to connect"); session.connect(); System.out.println("After connect, about to make channel"); // SSH Channel ChannelExec channel = (ChannelExec) session.openChannel("exec"); ByteArrayOutputStream stream = new ByteArrayOutputStream(); channel.setOutputStream(stream); // Execute command System.out.println("About to try command: " + command_text); channel.setCommand(command_text); channel.connect(1000); java.lang.Thread.sleep(1200); // there is a little delay // talking to the arduino sensor server. channel.disconnect(); result = stream.toString(); } catch (JSchException ex) { String s = ex.toString(); //Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show(); System.out.println("JSchException *****************************"); System.out.println(s); network_available = false; result = "Network not available"; } catch (InterruptedException ex) { String s = ex.toString(); System.out.println(s); } finally { if (session != null) session.disconnect(); } System.out.println("Result of ssh connection: " + result); return result; } // end tryCommand } RunSSHCommand ssh_task = null; VideoTunnel ssh_tunnel = null; // ProgressDialog pDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); status_array = new int[NUM_LEDS]; pending_commands = new ArrayList<>(); network_available = true; command_text = "STATUS"; Intent intent = getIntent(); username = intent.getStringExtra(USERNAME_KEY); host = intent.getStringExtra(HOST_KEY); port = intent.getIntExtra(PORT_KEY, 22); privateKeyFileName = intent.getStringExtra(PRIVATEKEYFILENAME_KEY); passphrase = intent.getStringExtra(PASSPHRASE_KEY); setContentView(R.layout.activity_operate_leds); tbLedButtons = new ToggleButton[NUM_LEDS]; tbLedButtons[0] = (ToggleButton) findViewById(R.id.led1Button); tbLedButtons[1] = (ToggleButton) findViewById(R.id.led2Button); tbLedButtons[2] = (ToggleButton) findViewById(R.id.led3Button); tbLedButtons[3] = (ToggleButton) findViewById(R.id.led4Button); System.out.println("Creating sensor array."); sensorDataViews = new TextView[NUM_SENSORS]; sensorValues = new Integer[NUM_SENSORS]; sensorDataViews[0] = (TextView) findViewById(R.id.tempData); sensorValues[0] = -999; sensorDataViews[1] = (TextView) findViewById(R.id.humData); sensorValues[1] = -999; Toast.makeText(getApplicationContext(), getString(R.string.retrieving_initial_status)+" "+command_text, Toast.LENGTH_SHORT).show(); if (network_available) { command_in_progress = true; ssh_task = new RunSSHCommand(); ssh_task.execute(intent); System.out.println("Started command: " + command_text); } else { System.out.println(getString(R.string.net_not_available)); Toast.makeText(getApplicationContext(), getString(R.string.net_not_available), Toast.LENGTH_LONG).show(); } } public void ledButtonClicked(View view) { ToggleButton btn = (ToggleButton) view; boolean toggle_value = btn.isChecked(); String tmp_command; if (toggle_value) { tmp_command = "ON " + btn.getHint(); } else { tmp_command = "OFF " + btn.getHint(); } if (command_in_progress) { pending_commands.add(tmp_command); return; } command_text = tmp_command; if (network_available) { command_in_progress = true; ssh_task = new RunSSHCommand(); ssh_task.execute(getIntent()); System.out.println("Started command: " + command_text); } else { System.out.println(getString(R.string.net_not_available)); Toast.makeText(getApplicationContext(), getString(R.string.net_not_available), Toast.LENGTH_LONG).show(); btn.setChecked(!toggle_value); } } public void decodeCommandResults() { JSONArray jsonArray = new JSONArray(); System.out.println("Decoding command: " + command_text); System.out.println("Decoding JSON: " + JSON_text); //Snackbar.make(findViewById(R.id.activity_operate_leds), JSON_text, Snackbar.LENGTH_LONG).setAction("Action", null).show(); try { jsonArray = new JSONArray(JSON_text); System.out.print("Length of jsonArray: "); System.out.println(jsonArray.length()); } catch (JSONException e) { System.out.println("JSONException *****************************"); e.printStackTrace(); } if (jsonArray.length() == NUM_LEDS) { try { for (int i=0; i < NUM_LEDS; i++) { boolean toggle_value = (int) (jsonArray.get(i)) != 0; System.out.print("toggle_value: "); System.out.print(jsonArray.get(i).toString()+" "); System.out.println(toggle_value); tbLedButtons[i].setChecked(toggle_value); } } catch (JSONException e) { e.printStackTrace(); } } else if (jsonArray.length() == NUM_LEDS + NUM_SENSORS) { System.out.println("Sensor reading *******************************************: "); try { for (int i = 0; i < NUM_LEDS; i++) { boolean toggle_value = (int) (jsonArray.get(i)) != 0; System.out.print("toggle_value: "); System.out.print(jsonArray.get(i).toString() + " "); System.out.println(toggle_value); tbLedButtons[i].setChecked(toggle_value); //toggle_value ? tbLedButtons[i].set(toggle_value); } } catch (JSONException e) { e.printStackTrace(); } try { boolean have_sentinel = false; // Check if any sensor values are set to -999 for (int i = 0; i < NUM_SENSORS; i++) { sensorValues[i] = (int) jsonArray.get(i + NUM_LEDS); System.out.print("sensor_value: "); System.out.print(jsonArray.get(i + NUM_LEDS).toString() + " "); System.out.println(sensorValues[i]); if (sensorValues[i] == -999) { have_sentinel = true; } } for (int i = 0; i < NUM_SENSORS; i++) { if (have_sentinel) { sensorDataViews[i].setText("---"); } else { sensorDataViews[i].setText(String.format(Locale.getDefault(), "%3d", sensorValues[i])); } } } catch (JSONException e) { e.printStackTrace(); } } // Check for pending commands if (pending_commands.size() > 0) { command_text = pending_commands.remove(0); ssh_task = new RunSSHCommand(); ssh_task.execute(getIntent()); System.out.println("Started command: " + command_text); } else { command_in_progress = false; } } protected void onPause() { super.onPause(); if (ssh_tunnel != null) ssh_tunnel.onDestroy(); } protected void onResume() { super.onResume(); ssh_tunnel = new VideoTunnel(); ssh_tunnel.execute(getIntent()); } protected void tunnelAvailable(){ String videoURL = "http://127.0.0.1:"+assigned_port+"/?action=stream"; webView = (WebView) findViewById(R.id.webView); webView.setWebViewClient(new WebViewClient()); webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); webView.loadUrl(videoURL); } } // end class