package org.commcare.tasks; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.commcare.android.logging.ForceCloseLogger; import org.commcare.tasks.templates.CommCareTask; import org.javarosa.core.services.Logger; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; /** * Runs various tasks that diagnose problems that a user may be facing in connecting to commcare services. * * @author srengesh */ public abstract class ConnectionDiagnosticTask<R> extends CommCareTask<Void, String, ConnectionDiagnosticTask.Test, R> { private final Context c; public enum Test { isOnline, googlePing, commCarePing } public static final int CONNECTION_ID = 12335800; /** * Problem reported via connection diagnostic tool **/ public static final String CONNECTION_DIAGNOSTIC_REPORT = "connection-report"; //strings used to in various diagnostics tests. Change these values if the URLs/HTML code is changed. private static final String googleURL = "www.google.com"; private static final String commcareURL = "http://www.commcarehq.org/serverup.txt"; private static final String commcareHTML = "success"; private static final String pingPrefix = "ping -c 1 "; //the various log messages that will be returned regarding the outcomes of the tests private static final String logNotConnectedMessage = "Network test: Not connected."; private static final String logConnectionSuccessMessage = "Network test: Success."; private static final String logGoogleNullPointerMessage = "Google ping test: Process could not be started."; private static final String logGoogleIOErrorMessage = "Google ping test: Local error."; private static final String logGoogleInterruptedMessage = "Google ping test: Process was interrupted."; private static final String logGoogleSuccessMessage = "Google ping test: Success."; private static final String logGoogleUnexpectedResultMessage = "Google ping test: Unexpected HTML Result."; private static final String logCCIllegalStateMessage = "CCHQ ping test: Illegal state."; private static final String logCCNetworkFailureMessge = "CCHQ ping test: Network failure."; private static final String logCCIOErrorMessage = "CCHQ ping test: Local error."; private static final String logCCUnexpectedResultMessage = "CCHQ ping test: Unexpected HTML result"; private static final String logCCSuccessMessage = "CCHQ ping test: Success."; public ConnectionDiagnosticTask(Context c) { this.c = c; this.taskId = CONNECTION_ID; TAG = ConnectionDiagnosticTask.class.getSimpleName(); } @Override protected Test doTaskBackground(Void... params) { Test out = null; if (!isOnline(this.c)) { out = Test.isOnline; } else if (!pingSuccess(googleURL)) { out = Test.googlePing; } else if (!pingCC(commcareURL)) { out = Test.commCarePing; } return out; } //checks if the network is connected or not. private boolean isOnline(Context context) { ConnectivityManager conManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = conManager.getActiveNetworkInfo(); boolean notInAirplaneMode = (netInfo != null && netInfo.isConnected()); //if user is not online, log not connected. if online, log success String logMessage = !notInAirplaneMode ? logNotConnectedMessage : logConnectionSuccessMessage; Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logMessage); return notInAirplaneMode; } //check if a ping to a specific ip address (used for google url) is successful. private boolean pingSuccess(String url) { Process pingCommand = null; try { //append the input url to the ping command String pingURL = pingPrefix + url; //run the ping command at runtime pingCommand = java.lang.Runtime.getRuntime().exec(pingURL); if (pingCommand == null) { Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logGoogleNullPointerMessage); return false; } } catch (IOException e) { Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logGoogleIOErrorMessage + System.getProperty("line.separator") + "Stack trace: " + ForceCloseLogger.getStackTrace(e)); return false; } int pingReturn = Integer.MAX_VALUE; try { pingReturn = pingCommand.waitFor(); } catch (InterruptedException e) { Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logGoogleInterruptedMessage + System.getProperty("line.separator") + "Stack trace: " + ForceCloseLogger.getStackTrace(e)); return false; } //0 if success, 2 if fail String messageOut = pingReturn == 0 ? logGoogleSuccessMessage : logGoogleUnexpectedResultMessage; Logger.log(CONNECTION_DIAGNOSTIC_REPORT, messageOut); return pingReturn == 0; } private boolean pingCC(String url) { //uses HttpClient and HttpGet to read the HTML from the specified url HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(url); InputStream stream = null; String htmlLine = null; BufferedReader buffer = null; InputStreamReader reader = null; try { //read html using an input stream reader stream = client.execute(get).getEntity().getContent(); reader = new InputStreamReader(stream); buffer = new BufferedReader(reader); //should read "success" if the server is up. htmlLine = buffer.readLine(); } catch (IllegalStateException e) { //if a stream to this web address has already been invoked on the same thread Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logCCIllegalStateMessage + System.getProperty("line.separator") + "Stack trace: " + ForceCloseLogger.getStackTrace(e)); return false; } catch (ClientProtocolException e) { //general HTTP Exception Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logCCNetworkFailureMessge + System.getProperty("line.separator") + "Stack trace: " + ForceCloseLogger.getStackTrace(e)); return false; } catch (IOException e) { //error on client side Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logCCIOErrorMessage + System.getProperty("line.separator") + "Stack trace: " + ForceCloseLogger.getStackTrace(e)); return false; } finally { if (buffer != null) { try { buffer.close(); } catch (IOException e) { Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logCCIOErrorMessage + System.getProperty("line.separator") + "Stack trace: " + ForceCloseLogger.getStackTrace(e)); } } if (reader != null) { try { reader.close(); } catch (IOException e) { Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logCCIOErrorMessage + System.getProperty("line.separator") + "Stack trace: " + ForceCloseLogger.getStackTrace(e)); } } if (stream != null) { try { stream.close(); } catch (IOException e) { String out = logCCIOErrorMessage + System.getProperty("line.separator") + "Stack trace: " + ForceCloseLogger.getStackTrace(e); Logger.log(CONNECTION_DIAGNOSTIC_REPORT, out); } } } if (htmlLine.equals(commcareHTML)) { Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logCCSuccessMessage); return true; } else { Logger.log(CONNECTION_DIAGNOSTIC_REPORT, logCCUnexpectedResultMessage); return false; } } }