diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..9be5dbf --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +TechneauxMobileApp \ No newline at end of file diff --git a/.idea/TechneauxMobileApp.iml b/.idea/TechneauxMobileApp.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/TechneauxMobileApp.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..7e63416 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..ca8d54d --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..6d4fafa --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1445364525486 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Android/TechneauxMobileApp/.gitignore b/Android/TechneauxMobileApp/.gitignore new file mode 100644 index 0000000..9c4de58 --- /dev/null +++ b/Android/TechneauxMobileApp/.gitignore @@ -0,0 +1,7 @@ +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/Android/TechneauxMobileApp/.idea/.name b/Android/TechneauxMobileApp/.idea/.name new file mode 100644 index 0000000..9be5dbf --- /dev/null +++ b/Android/TechneauxMobileApp/.idea/.name @@ -0,0 +1 @@ +TechneauxMobileApp \ No newline at end of file diff --git a/Android/TechneauxMobileApp/.idea/compiler.xml b/Android/TechneauxMobileApp/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/Android/TechneauxMobileApp/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Android/TechneauxMobileApp/.idea/copyright/profiles_settings.xml b/Android/TechneauxMobileApp/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/Android/TechneauxMobileApp/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Android/TechneauxMobileApp/.idea/encodings.xml b/Android/TechneauxMobileApp/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/Android/TechneauxMobileApp/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Android/TechneauxMobileApp/.idea/gradle.xml b/Android/TechneauxMobileApp/.idea/gradle.xml new file mode 100644 index 0000000..5f8ec24 --- /dev/null +++ b/Android/TechneauxMobileApp/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/Android/TechneauxMobileApp/.idea/misc.xml b/Android/TechneauxMobileApp/.idea/misc.xml new file mode 100644 index 0000000..5d19981 --- /dev/null +++ b/Android/TechneauxMobileApp/.idea/misc.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Android/TechneauxMobileApp/.idea/modules.xml b/Android/TechneauxMobileApp/.idea/modules.xml new file mode 100644 index 0000000..a78ec89 --- /dev/null +++ b/Android/TechneauxMobileApp/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/Android/TechneauxMobileApp/.idea/runConfigurations.xml b/Android/TechneauxMobileApp/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/Android/TechneauxMobileApp/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/Android/TechneauxMobileApp/.idea/vcs.xml b/Android/TechneauxMobileApp/.idea/vcs.xml new file mode 100644 index 0000000..6564d52 --- /dev/null +++ b/Android/TechneauxMobileApp/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Android/TechneauxMobileApp/TechneauxMobileApp.iml b/Android/TechneauxMobileApp/TechneauxMobileApp.iml new file mode 100644 index 0000000..c8e6c4b --- /dev/null +++ b/Android/TechneauxMobileApp/TechneauxMobileApp.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Android/TechneauxMobileApp/app/.gitignore b/Android/TechneauxMobileApp/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/Android/TechneauxMobileApp/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/Android/TechneauxMobileApp/app/app.iml b/Android/TechneauxMobileApp/app/app.iml new file mode 100644 index 0000000..1f75cb8 --- /dev/null +++ b/Android/TechneauxMobileApp/app/app.iml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Android/TechneauxMobileApp/app/build.gradle b/Android/TechneauxMobileApp/app/build.gradle new file mode 100644 index 0000000..4cb5500 --- /dev/null +++ b/Android/TechneauxMobileApp/app/build.gradle @@ -0,0 +1,25 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion "23.0.0" + + defaultConfig { + applicationId "com.techneaux.techneauxmobileapp" + minSdkVersion 15 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:22.2.0' +} diff --git a/Android/TechneauxMobileApp/app/proguard-rules.pro b/Android/TechneauxMobileApp/app/proguard-rules.pro new file mode 100644 index 0000000..f992690 --- /dev/null +++ b/Android/TechneauxMobileApp/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in D:\Android SDK/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/Android/TechneauxMobileApp/app/src/androidTest/java/com/techneaux/techneauxmobileapp/ApplicationTest.java b/Android/TechneauxMobileApp/app/src/androidTest/java/com/techneaux/techneauxmobileapp/ApplicationTest.java new file mode 100644 index 0000000..71d15da --- /dev/null +++ b/Android/TechneauxMobileApp/app/src/androidTest/java/com/techneaux/techneauxmobileapp/ApplicationTest.java @@ -0,0 +1,13 @@ +package com.techneaux.techneauxmobileapp; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/Android/TechneauxMobileApp/app/src/main/AndroidManifest.xml b/Android/TechneauxMobileApp/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..9374857 --- /dev/null +++ b/Android/TechneauxMobileApp/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Android/TechneauxMobileApp/app/src/main/ic_launcher-web.png b/Android/TechneauxMobileApp/app/src/main/ic_launcher-web.png new file mode 100644 index 0000000..6d3a83f Binary files /dev/null and b/Android/TechneauxMobileApp/app/src/main/ic_launcher-web.png differ diff --git a/Android/TechneauxMobileApp/app/src/main/java/com/techneaux/techneauxmobileapp/API_Communications.java b/Android/TechneauxMobileApp/app/src/main/java/com/techneaux/techneauxmobileapp/API_Communications.java new file mode 100644 index 0000000..74ab984 --- /dev/null +++ b/Android/TechneauxMobileApp/app/src/main/java/com/techneaux/techneauxmobileapp/API_Communications.java @@ -0,0 +1,247 @@ +package com.techneaux.techneauxmobileapp; + +import android.util.Log; + +import org.apache.http.HttpResponse; +import org.apache.http.HttpVersion; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpParams; +import org.apache.http.params.HttpProtocolParams; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HTTP; +import org.apache.http.protocol.HttpContext; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + + +public class API_Communications implements Runnable { + + public static String urlSTR; //url string + public static JSONObject json; //json obj + public static String result; //result for other activities to pull + + /** + * Preconditions: none + * Post Conditions: init the url string json object and result variables + * Parameters: url string json object and result + * Use: when starting API Communications + */ + public API_Communications(String setUrl, JSONObject setJson) { + urlSTR = setUrl; + json = setJson; + result = null; + + } + + + /** + * Preconditions: none + * Post Conditions: runs HTTPS Post to API + * Parameters: None + * Use: when starting API Communications + */ + public void run() { + + postData(); + } + + /** + * Note: Please only use this for development testing (for self signed in certificate). Adding this to the + * public application is a serious blunder. + * + * @author Sandip Jadhav + */ + public static DefaultHttpClient createSSLHTTP() throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException { + + // Setup a custom SSL Factory object which simply ignore the certificates + // validation and accept all type of self signed certificates + SSLSocketFactory sslFactory = new SimpleSSLSocketFactory(null); + sslFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + + // Enable HTTP parameters + HttpParams params = new BasicHttpParams(); + HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); + HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); + + // Register the HTTP and HTTPS Protocols. For HTTPS, register our custom SSL Factory object. + SchemeRegistry registry = new SchemeRegistry(); + registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + registry.register(new Scheme("https", sslFactory, 443)); + + // Create a new connection manager using the newly created registry and then create a new HTTP client + // using this connection manager + ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); + DefaultHttpClient client = new DefaultHttpClient(ccm, params); + + // To-do: Get or Post the data using this newly created http client object + return client; + } + /** + * Preconditions: none + * Post Conditions: HTTPS Post to API + * Parameters: None + * Use: when sending API Communications + */ + public static void postData() { + // Create a new HttpClient and Post Header + HttpClient httpclient = new DefaultHttpClient(); + HttpPost httppost = new HttpPost(urlSTR); + + + //bypassing ssl self-signed cert + try { + httpclient = createSSLHTTP(); + } catch (UnrecoverableKeyException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (KeyStoreException e) { + e.printStackTrace(); + } catch (KeyManagementException e) { + e.printStackTrace(); + } + + + try { + httppost.setEntity(new ByteArrayEntity( + json.toString().getBytes("UTF8"))); //defines httppost body + // Execute HTTP Post Request + Log.d("API", "json: " + json); + Log.d("API", "Count: " + json.toString().length()); + HttpContext localContext = new BasicHttpContext(); + + //set http client params + httpclient.getParams().setBooleanParameter("http.protocol.expect-continue", false); + + //get http response from api + HttpResponse response = httpclient.execute(httppost, localContext); + + + // for JSON response : + if (response != null) { + InputStream is = response.getEntity().getContent(); //get body response + + //decode response into string + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + StringBuilder sb = new StringBuilder(); + + String line = null; + try { + while ((line = reader.readLine()) != null) { + sb.append(line + "\n"); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + //end decode response to string + result = sb.toString(); + Log.d("API", "Result: " + result); + Log.d("API", response.getStatusLine().toString()); + + + } + + + } catch (ClientProtocolException e) { + e.printStackTrace(); + // TODO Auto-generated catch block + } catch (IOException e) { + e.printStackTrace(); + // TODO Auto-generated catch block + } + + + } + + +} + + +/** + * Note: Please only use this for development testing (for self signed in certificate). Adding this to the + * public application is a serious blunder. + * + * @author Sandip Jadhav + */ + +class SimpleSSLSocketFactory extends org.apache.http.conn.ssl.SSLSocketFactory { + private javax.net.ssl.SSLSocketFactory sslFactory = HttpsURLConnection.getDefaultSSLSocketFactory(); + + public SimpleSSLSocketFactory(KeyStore truststore) + throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { + super(null); + + try { + SSLContext context = SSLContext.getInstance("TLS"); + + // Create a trust manager that does not validate certificate chains and simply + // accept all type of certificates + TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[]{}; + } + + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + }}; + + // Initialize the socket factory + context.init(null, trustAllCerts, new SecureRandom()); + sslFactory = context.getSocketFactory(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) + throws IOException, UnknownHostException { + return sslFactory.createSocket(socket, host, port, autoClose); + } + + @Override + public Socket createSocket() throws IOException { + return sslFactory.createSocket(); + } +} \ No newline at end of file diff --git a/Android/TechneauxMobileApp/app/src/main/java/com/techneaux/techneauxmobileapp/MainActivity.java b/Android/TechneauxMobileApp/app/src/main/java/com/techneaux/techneauxmobileapp/MainActivity.java new file mode 100644 index 0000000..d05c8f0 --- /dev/null +++ b/Android/TechneauxMobileApp/app/src/main/java/com/techneaux/techneauxmobileapp/MainActivity.java @@ -0,0 +1,354 @@ +package com.techneaux.techneauxmobileapp; + +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import org.json.JSONException; +import org.json.JSONObject; + + +public class MainActivity extends AppCompatActivity { + private static Button submitLoginInfo; //object to link to the submit login info layout object + private static EditText username; //object to link to the username layout object + private static EditText password; //object to link to the password layout object + private static TextView CSNumber; //object to link to the customer service number layout object + public static final String MY_PREFS_NAME = "MyPrefsFile"; //file to store prefs for the app. + public static TextView errorText; + private ProgressBar spinner; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + //********Initialize the layout objects to a variable for manipulation******** + submitLoginInfo = (Button) findViewById(R.id.loginSubmit); + username = (EditText) findViewById(R.id.username); + password = (EditText) findViewById(R.id.password); + CSNumber = (TextView) findViewById(R.id.CSNumberText); + errorText=(TextView) findViewById(R.id.loginErrorText); + spinner = (ProgressBar)findViewById(R.id.loginProgressBar); + spinner.setVisibility(View.INVISIBLE); + + setButtons(); //function to initialize the two buttons (submit and call) + //********End Initialize the layout objects to a variable for manipulation******** + + + SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE); + username.setText(prefs.getString("companyname",null)); // init username to what was stored + + final View v = findViewById(android.R.id.content); + + if( (prefs.getInt("screen_state",0) == 2 )) //checks saved state from last run time, + { // if state = 2, go to Registration + + Intent myIntent = new Intent(v.getContext(), RegistrationActivity.class); + startActivityForResult(myIntent, 0); + } + else if( (prefs.getInt("screen_state",0) == 3 )) { //if 3, go to Ticket Activity + + Intent myIntent = new Intent(v.getContext(), TicketActivity.class); + startActivityForResult(myIntent, 0); + } + + + + } + + /** + * Preconditions: None + * Post Conditions: Buttons have functional actions upon click + * Parameters: None + * Use: Only needs to be called once to set the onclick methods. + */ + private void setButtons() + { + //********Customer Service Call Phone ******** + CSNumber.setOnClickListener(new Button.OnClickListener() { + + public void onClick(View v) { + + String phone_no = "5045540101"; //number to call + Intent callIntent = new Intent(Intent.ACTION_CALL); // making new intent object + // to switch screen + callIntent.setData(Uri.parse("tel:" + phone_no)); //define screen to switch to with parameters + startActivity(callIntent); //switch + + } + }); + //********End Customer Service Call Phone ******** + + + //********Submit Login Info ******** + submitLoginInfo.setOnClickListener(new Button.OnClickListener() { + + public void onClick(View v) { + submitLoginInfo.setText("Logging In..."); + submitLoginInfo.setEnabled(false); + String sUsername = username.getText().toString(); //get text from username layout object + String sPassword = password.getText().toString(); //get text from password layout object + + if (sUsername.matches("")) //tests to see if Username field has text + { + errorText.setText("Username not entered!"); + submitLoginInfo.setText("Submit"); + submitLoginInfo.setEnabled(true); + return; + } else if (sPassword.matches("")) //tests to see if Password field has text + { + errorText.setText("Password not entered!"); + submitLoginInfo.setText("Submit"); + submitLoginInfo.setEnabled(true); + return; + } else //username & password is accepted, save company name and switch to next screen, + { + + JSONObject login = new JSONObject(); //create JSON Obj to hold data for API + try { + login.put("companyID", sUsername); //push companyID + login.put("password", sPassword); //push password + + + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + spinner.setVisibility(v.VISIBLE); //have load spinne be visible + + //Code to create a thread to send data to API + Thread thread = new Thread(new API_Communications("https://cmps.techneaux.com/login", login)); + thread.start(); + + + runThread(v, sUsername);//process API data returned + return; + } + + + } + }); + //********End Submit Login Info ******** + } + private void runThread(final View v, final String sUsername) { + + new Thread() { + public void run() { + SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit(); + + + while (API_Communications.result == null) { // wait for reply from API + } + + final String result = API_Communications.result; //get response from API + JSONObject obj = null; + try { //attempt to make json obj from API Response + + obj = new JSONObject(result); + + + } catch (Throwable t) { // post error message if api does not give a proper JSON obj + runOnUiThread(new Runnable() { + + @Override + public void run() { //need to invoke runonUI to set text boxes + errorText.setText("Invalid Response from Server, please try again." + result); + submitLoginInfo.setText("Submit"); + submitLoginInfo.setEnabled(true); + } + }); + + + + } + String error = null; //string to hold error from api json reply + if (obj.has("niceMessage")) { //parse a nice debug message error + try { //from API to print to screen + error = obj.get("niceMessage").toString(); //parse out nicemessage + + } catch (JSONException e) { + runOnUiThread(new Runnable() { + + @Override + public void run() { //need to invoke runonUI to set text boxes + spinner.setVisibility(v.INVISIBLE); + submitLoginInfo.setText("Submit"); + submitLoginInfo.setEnabled(true); + + } + }); + e.printStackTrace(); + } + } + if (obj.has("authKey")) { //check if the object has a field for an authkey + if (error == null) { //make sure there is no error from api + try { + String authKey = obj.get("authKey").toString(); //get authkey from jsonobj + editor.putString("authKey", authKey); + + editor.commit(); + } catch (JSONException e) { + runOnUiThread(new Runnable() { + + @Override + public void run() { //need to invoke runonUI to set text boxes + spinner.setVisibility(v.INVISIBLE); + submitLoginInfo.setText("Submit"); + submitLoginInfo.setEnabled(true); + + } + }); + e.printStackTrace(); + } + } + + editor.putString("companyname", sUsername); //save username to shared prefs + editor.putInt("screen_state", 2); //update app state to 2, so app can jump to the next screen. + + editor.commit(); + runOnUiThread(new Runnable() { + + @Override + public void run() { //need to invoke runonUI to set text boxes + spinner.setVisibility(v.INVISIBLE); + submitLoginInfo.setText("Submit"); + submitLoginInfo.setEnabled(true); + + //go to next screen + Intent myIntent = new Intent(v.getContext(), RegistrationActivity.class); + startActivityForResult(myIntent, 0); + } + }); + + } else { + final String finalError = error; //got an error to print to screen + runOnUiThread(new Runnable() { + + @Override + public void run() { //need to invoke runonUI to set text boxes + spinner.setVisibility(v.INVISIBLE); + submitLoginInfo.setText("Submit"); + submitLoginInfo.setEnabled(true); + errorText.setText(finalError); + } + }); + + } + + } + }.start();//thread starter + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + /** + * Preconditions: None + * Post Conditions: login fields are wiped out + * Parameters: None + * Use: whenever wipe data button is used in app. + */ + public static void wipeData(SharedPreferences.Editor editor) + { + + + editor.putString("ticket_photo", null); //wipe out ticket photo data + editor.putString("ticket_location", null); //wipe out ticket location data + editor.putInt("screen_state", 0); // wipe app state to defaults + editor.putString("emp_firstname", null); //wipe firstname + editor.putString("emp_lastname", null); //wipe last name + editor.putString("emp_phonenumber", null); // wipe phone number + editor.putString("emp_emailaddress", null); //wipe email address + editor.putString("companyname", null); //Wipe out company name + editor.putString("ticket_description",null);//wipe out ticket description + editor.putInt("screen_state", 0); //Wipe out company name + editor.putString("authKey",null); //wipe authkey + editor.commit(); //save! + + + username.setText(null); //sets field to empty + password.setText(null); //sets field to empty + } + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + //preventing default implementation previous to android.os.Build.VERSION_CODES.ECLAIR + return true; + } + return super.onKeyDown(keyCode, event); + } + @Override + public void onBackPressed() { + // Do Here what ever you want do on back press; + } + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.wipe_data) { //wipes all data from login screen + AlertDialog eraseConfirm = eraseDialogAlertMaker(); //dialog before wiping + // data to confirm wipe + + eraseConfirm.show(); //show dialog + + + + return true; + } + + return super.onOptionsItemSelected(item); + } + + private AlertDialog eraseDialogAlertMaker(){ + + AlertDialog eraseDialog = + + new AlertDialog.Builder(this) + //set message, title, and icon + .setTitle("Erase Data?") + .setMessage("Are you sure that you want to erase all stored data?") + + //set three option buttons + .setPositiveButton("Yes", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + //whatever should be done when answering "YES" goes here + SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit(); + wipeData(editor); + Toast.makeText(getApplicationContext(), "Data Erased", + Toast.LENGTH_LONG).show(); + + } + }) + .setNegativeButton("NO", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + //whatever should be done when answering "NO" goes here + + + } + })//setNegativeButton + + .create(); + + return eraseDialog; + } +} diff --git a/Android/TechneauxMobileApp/app/src/main/java/com/techneaux/techneauxmobileapp/RegistrationActivity.java b/Android/TechneauxMobileApp/app/src/main/java/com/techneaux/techneauxmobileapp/RegistrationActivity.java new file mode 100644 index 0000000..2abc291 --- /dev/null +++ b/Android/TechneauxMobileApp/app/src/main/java/com/techneaux/techneauxmobileapp/RegistrationActivity.java @@ -0,0 +1,419 @@ +package com.techneaux.techneauxmobileapp; + +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.text.SpannableString; +import android.text.style.UnderlineSpan; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class RegistrationActivity extends AppCompatActivity { + + private Button verifyButton; // Create button + private static EditText firstname; //object to link to the username layout object + private static EditText lastname; //object to link to the password layout object + private static EditText phonenumber; //object to link to the username layout object + private static EditText emailaddress; //object to link to the password layout object + private static TextView loggedInName; //object to link to the companyName layout object + private static TextView empError; + public static final String MY_PREFS_NAME = "MyPrefsFile"; //file to store prefs for the app. + private ProgressBar spinner; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.employee_info); + //********Initialize the layout objects to a variable for manipulation******** + + verifyButton = (Button) findViewById(R.id.verifyButton); + firstname = (EditText) findViewById(R.id.firstname); + lastname = (EditText) findViewById(R.id.lastname); + phonenumber = (EditText) findViewById(R.id.Phone); + emailaddress = (EditText) findViewById(R.id.emailaddress); + loggedInName = (TextView) findViewById(R.id.companynameLoggedIn); + empError = (TextView) findViewById(R.id.employeeError); + spinner = (ProgressBar) findViewById(R.id.employeeProgressBar); + spinner.setVisibility(View.INVISIBLE); + //********End Initialize the layout objects to a variable for manipulation******** + + setButtons(); //set button onclick listeners + + //********Initialize the text boxes to data from shared preferences, if any exist ******** + SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE); + firstname.setText(prefs.getString("emp_firstname", null)); // init first name to what was stored + lastname.setText(prefs.getString("emp_lastname", null)); // init last name to what was stored + phonenumber.setText(prefs.getString("emp_phonenumber", null)); // init phone number to what was stored + emailaddress.setText(prefs.getString("emp_emailaddress", null)); // init email address to what was stored + String mystring = new String("Company Name: " + prefs.getString("companyname", null)); + SpannableString content = new SpannableString(mystring); + content.setSpan(new UnderlineSpan(), 14, mystring.length(), 0); + loggedInName.setText(content); // init companyname to what was stored + //********End Initialize the text boxes to data from shared preferences, if any exist ******** + + + final View v = findViewById(android.R.id.content); + + if ((prefs.getInt("screen_state", 0) == 3)) { //check if state is 3 to go to ticket screen + Intent myIntent = new Intent(v.getContext(), TicketActivity.class); + startActivityForResult(myIntent, 0); //go to ticket activity + } + + } + @Override +protected void onPause() +{ + super.onPause(); + + //****Store Data on application minimize to shared prefs **************** + SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit(); + editor.putString("emp_firstname", firstname.getText().toString()); + editor.putString("emp_lastname", lastname.getText().toString()); + editor.putString("emp_phonenumber", phonenumber.getText().toString()); + editor.putString("emp_emailaddress", emailaddress.getText().toString()); + editor.commit(); + //****End Store Data on application minimize to shared prefs **************** + +} + /** + * Preconditions: None + * Post Conditions: Buttons have functional actions upon click + * Parameters: None + * Use: Only needs to be called once to set the onclick methods. + */ + private void setButtons() { + // throws a toast saying information has been verfied when Verify button is clicked. + verifyButton.setOnClickListener(new Button.OnClickListener() { + public void onClick(View v) { + verifyButton.setEnabled(false); + verifyButton.setText("Verifying..."); + String sFirstName = firstname.getText().toString(); //get text from username layout object + String sLastName = lastname.getText().toString(); //get text from password layout object + String sPhone = phonenumber.getText().toString(); //get text from username layout object + String sEmail = emailaddress.getText().toString(); //get text from password layout object + + if (sFirstName.matches("")) //tests to see if first name field has text + { + empError.setText("Employee First Name not entered!"); + verifyButton.setEnabled(true); + verifyButton.setText("Verify"); + return; + } + if (sLastName.matches("")) //tests to see if last name field has text + { + empError.setText("Employee Last Name not entered!"); + verifyButton.setEnabled(true); + verifyButton.setText("Verify"); + return; + } + if (sPhone.matches("")) //tests to see if phone number field has text + { + empError.setText("Phone Number not entered!"); + verifyButton.setEnabled(true); + verifyButton.setText("Verify"); + return; + } + + if (isPhoneValid(sPhone) == false) { + empError.setText("Phone Number not valid!"); + + verifyButton.setEnabled(true); + verifyButton.setText("Verify"); + return; + } + if (sEmail.matches("")) //tests to see if email address field has text + { + empError.setText("Email Address not entered!"); + verifyButton.setEnabled(true); + verifyButton.setText("Verify"); + return; + } + if (isEmailValid(sEmail) == false) { //check to see if email is validly formed + empError.setText("Email Address not valid!"); + verifyButton.setEnabled(true); + verifyButton.setText("Verify"); + return; + } else { + + + SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE); + JSONObject EmployeeInfo = new JSONObject(); //create json obj + try { //store data to json object to send to API + EmployeeInfo.put("authKey", prefs.getString("authKey", null)); + EmployeeInfo.put("firstName", sFirstName); + EmployeeInfo.put("lastName", sLastName); + EmployeeInfo.put("email", sEmail); + EmployeeInfo.put("phoneNumber", sPhone); + + + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + spinner.setVisibility(v.VISIBLE);//make load spinner visible + + Thread thread = new Thread(new API_Communications("https://cmps.techneaux.com/update-employee", EmployeeInfo)); + thread.start(); //send data to API in other thread + + runThread(sFirstName,sLastName,sEmail,sPhone, v ); //run sep thread to handle data from API + return; + } + + } + }); + } + private void runThread(final String sFirstName, final String sLastName, final String sEmail, final String sPhone, final View v ) { + + new Thread() { + public void run() { + SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit(); + + + while (API_Communications.result == null) { //wait for api to respond + } + + final String result = API_Communications.result; //get result from api + + JSONObject obj = null; //make json obj to hold api response + try { //try to form json from api response + + obj = new JSONObject(result); + + + } catch (Throwable t) { //incase api response not valid json + runOnUiThread(new Runnable() { + + @Override + public void run() { //invoke runonUI to alter layout objects + verifyButton.setEnabled(true); + verifyButton.setText("Verify"); + empError.setText("Invalid Response from Server, please try again.\n " + result); + } + }); + + + } + String error = null; //string to hold possible error message + if (obj.has("niceMessage")) { //check if a nicemessage exists in the json obj + try { + error = obj.get("niceMessage").toString(); //take error from json to string + + } catch (JSONException e) { + e.printStackTrace(); + } + } + if (error == null) { // Store data to shared preferences + editor.putString("emp_firstname", sFirstName); + editor.putString("emp_lastname", sLastName); + editor.putString("emp_phonenumber", sPhone); + editor.putString("emp_emailaddress", sEmail); + editor.putInt("screen_state", 3); + editor.commit(); + + runOnUiThread(new Runnable() { + + @Override + public void run() {//invoke runonui to update layout objs + verifyButton.setEnabled(true); + verifyButton.setText("Verify"); + spinner.setVisibility(View.INVISIBLE); + Intent myIntent = new Intent(v.getContext(), TicketActivity.class); + startActivityForResult(myIntent, 0); //go to ticket activity + } + }); + + + } else { + final String finalError = error; + runOnUiThread(new Runnable() { + + @Override + public void run() { + verifyButton.setEnabled(true); + verifyButton.setText("Verify"); + spinner.setVisibility(View.INVISIBLE); + empError.setText(finalError); + } + }); + + } + + + + + + + } + + }.start(); + } + /** + * method is used for checking valid phone number format. + * Borrowed from http://buzycoder.blogspot.com/2013/06/android-check-if-phone-number-is-valid.html + * + * @param phone number + * @return boolean true for valid false for invalid + */ + static boolean isPhoneValid(String phoneNo) { + //validate phone numbers of format "1234567890" + if (phoneNo.matches("\\d{10}")) return true; + //validating phone number with -, . or spaces + else if (phoneNo.matches("\\d{3}[-\\.\\s]\\d{3}[-\\.\\s]\\d{4}")) return true; + //validating phone number with extension length from 3 to 5 + else if (phoneNo.matches("\\d{3}-\\d{3}-\\d{4}\\s(x|(ext))\\d{3,5}")) return true; + //validating phone number where area code is in braces () + else if (phoneNo.matches("\\(\\d{3}\\)-\\d{3}-\\d{4}")) return true; + //return false if nothing matches the input + else return false; + } + + /** + * method is used for checking valid email id format. + * Borrowed from http://stackoverflow.com/questions/6119722/how-to-check-edittexts-text-is-email-address-or-not + * + * @param email + * @return boolean true for valid false for invalid + */ + private static boolean isEmailValid(String email) { + boolean isValid = false; + + String expression = "^[\\w\\.-]+@([\\w\\-]+\\.)+[A-Z]{2,4}$"; + CharSequence inputStr = email; + + Pattern pattern = Pattern.compile(expression, Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(inputStr); + if (matcher.matches()) { + isValid = true; + } + return isValid; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + //preventing default implementation previous to android.os.Build.VERSION_CODES.ECLAIR + return true; + } + return super.onKeyDown(keyCode, event); + } + + @Override + public void onBackPressed() { + // Do Here what ever you want do on back press; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + /** + * Preconditions: None + * Post Conditions: all data fields are wiped out + * Parameters: None + * Use: whenever wipe data button is used in app. + */ + public static void wipeData(SharedPreferences.Editor editor, SharedPreferences prefs) { + if (!(prefs.getInt("screen_state", 0) == 2)) { + + firstname.setText(null); //sets field to empty + lastname.setText(null); //sets field to empty + phonenumber.setText(null); //sets field to empty + emailaddress.setText(null); //sets field to empty + } + //wipe all shared preferences + editor.putString("ticket_photo", null); + editor.putString("ticket_location", null); + editor.putInt("screen_state", 0); + editor.putString("ticket_description", null);//wipe out ticket description + editor.putString("emp_firstname", null); + editor.putString("emp_lastname", null); + editor.putString("emp_phonenumber", null); + editor.putString("emp_emailaddress", null); + editor.putInt("screen_state", 0); + editor.putString("companyname", null); //Wipe out company name + editor.putInt("screen_state", 0); //Wipe out company name + editor.putString("authKey", null); + editor.commit(); + //end wipe + + + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.wipe_data) { + AlertDialog eraseConfirm = eraseDialogAlertMaker(); //dialog before wiping + // data to confirm wipe + + eraseConfirm.show(); //show dialog + + return true; + } + + return super.onOptionsItemSelected(item); + } + + private AlertDialog eraseDialogAlertMaker(){ + + AlertDialog eraseDialog = + + new AlertDialog.Builder(this) + //set message, title, and icon + .setTitle("Erase Data?") + .setMessage("Are you sure that you want to erase all stored data?") + + //set three option buttons + .setPositiveButton("Yes", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + //whatever should be done when answering "YES" goes here + SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit(); + SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE); + MainActivity.wipeData(editor); + wipeData(editor, prefs); + final View v = findViewById(android.R.id.content); + Intent myIntent = new Intent(v.getContext(), MainActivity.class); + startActivityForResult(myIntent, 0); + Toast.makeText(getApplicationContext(), "Data Erased", + Toast.LENGTH_LONG).show(); + + + } + }) + .setNegativeButton("NO", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + //whatever should be done when answering "NO" goes here + + + } + })//setNegativeButton + + .create(); + + return eraseDialog; + } +} diff --git a/Android/TechneauxMobileApp/app/src/main/java/com/techneaux/techneauxmobileapp/TicketActivity.java b/Android/TechneauxMobileApp/app/src/main/java/com/techneaux/techneauxmobileapp/TicketActivity.java new file mode 100644 index 0000000..0f5d217 --- /dev/null +++ b/Android/TechneauxMobileApp/app/src/main/java/com/techneaux/techneauxmobileapp/TicketActivity.java @@ -0,0 +1,593 @@ +package com.techneaux.techneauxmobileapp; + +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.support.v7.app.AppCompatActivity; +import android.text.SpannableString; +import android.text.style.UnderlineSpan; +import android.util.Base64; +import android.util.Log; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.ByteArrayOutputStream; +import java.io.File; + +/** + * Created by CMD Drake on 10/27/2015. + */ +public class TicketActivity extends AppCompatActivity { + + public static final String MY_PREFS_NAME = "MyPrefsFile"; //file to store prefs for the app. + + private static TextView employeename; //object to link to the employeename layout object + private static TextView companyname; //object to link to the company name layout object + private static TextView phonenumber; //object to link to the phone number layout object + private static TextView emailaddress; //object to link to the email address layout object + + private static EditText Location; //object to link to the location layout object + private static EditText Description; //object to link to the description layout object + private static TextView ErrorTicket; //object to link to the errorticket layout object + private static Button clearPhoto; //object to link to the clear photo button layout object + + private static Button SubmitTicketBTN; //object to link to the submit btn layout object + private static Button CameraBTN; //object to link to the take a picture btn layout object + + private ProgressBar spinner; //load spinner used to show app is sending data to API + private static final int CAMERA_REQUEST = 1888; + private static ImageView imageView; //imageview for photo preview + + private static Bitmap photo; //holds bitmap representation of picture taken + private String photo_ticket; //holds base64 representation of picture taken + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.ticket_activity); + + //********Initialize the layout objects to a variable for manipulation******** + employeename = (TextView) findViewById(R.id.ticket_employeename); + companyname = (TextView) findViewById(R.id.ticket_companynameLoggedIn); + phonenumber = (TextView) findViewById(R.id.ticket_phonenumber); + emailaddress = (TextView) findViewById(R.id.ticket_emailaddress); + SubmitTicketBTN = (Button) findViewById(R.id.SubmitTicketBTN); + CameraBTN = (Button) this.findViewById(R.id.cameraBTN); + Location = (EditText) findViewById(R.id.locationsite); + Description = (EditText) findViewById(R.id.ticket_description); + imageView = (ImageView) this.findViewById(R.id.imageView); + ErrorTicket = (TextView) this.findViewById(R.id.ticketError); + clearPhoto = (Button) this.findViewById(R.id.clearPhoto); + spinner = (ProgressBar) findViewById(R.id.employeeProgressBar); + spinner.setVisibility(View.INVISIBLE); + //********End Initialize the layout objects to a variable for manipulation******** + + setButtons(); //set button onclick listeners + + + SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE); + //Company name read + String mystring = new String("Company Name: " + prefs.getString("companyname", null)); + SpannableString content = new SpannableString(mystring); + content.setSpan(new UnderlineSpan(), 14, mystring.length(), 0); + companyname.setText(content); + //end company name read + + //employee name read + mystring = new String("Employee Name: " + prefs.getString("emp_firstname", null) + " " + prefs.getString("emp_lastname", null)); + content = new SpannableString(mystring); + content.setSpan(new UnderlineSpan(), 15, mystring.length(), 0); + employeename.setText(content); + //end name read + + //phone number read + mystring = new String("Phone Number: " + prefs.getString("emp_phonenumber", null)); + content = new SpannableString(mystring); + content.setSpan(new UnderlineSpan(), 14, mystring.length(), 0); + phonenumber.setText(content); + //end phone number read + + //email read + mystring = new String("Email Address: " + prefs.getString("emp_emailaddress", null)); + content = new SpannableString(mystring); + content.setSpan(new UnderlineSpan(), 15, mystring.length(), 0); + emailaddress.setText(content); + //email end read + + //location read + Location.setText(prefs.getString("ticket_location", null)); + //end location read + + //location read + Description.setText(prefs.getString("ticket_description", null)); + //end location read + + //read and decode photo into bitmap from shared prefs + String base = prefs.getString("ticket_photo", null); + photo_ticket = ""; + + if (base != null) { + photo_ticket = base; + byte[] imageAsBytes = Base64.decode(base.getBytes(), Base64.DEFAULT); + photo = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length); + imageView.setImageBitmap( + BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)); + } + //end read and decode photo into bitmap from shared prefs + } + + /** + * Preconditions: None + * Post Conditions: Buttons have functional actions upon click + * Parameters: None + * Use: Only needs to be called once to set the onclick methods. + */ + private void setButtons() { + + // throws a toast saying information has been verfied when Verify button is clicked. + SubmitTicketBTN.setOnClickListener(new Button.OnClickListener() { + public void onClick(View v) { + //disable buttons while attempting to talk with API + SubmitTicketBTN.setEnabled(false); + SubmitTicketBTN.setText("Submitting..."); + CameraBTN.setEnabled(false); + clearPhoto.setEnabled(false); + //end disable buttons while attempting to talk with API + + String sDescription = Description.getText().toString(); //get text from username layout object + String sLocation = Location.getText().toString(); //get text from password layout object + + if (sDescription.matches("")) //tests to see if Password field has text + { + ErrorTicket.setText("Description not Entered!"); + SubmitTicketBTN.setEnabled(true); + SubmitTicketBTN.setText("Submit Ticket"); + CameraBTN.setEnabled(true); + clearPhoto.setEnabled(true); + return; + } else //username & password is accepted, save company name and switch to next screen, + { + SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE); + JSONObject TicketInfo = new JSONObject(); //make json object + try { //populate json object with data for API + TicketInfo.put("authKey", prefs.getString("authKey", null)); + TicketInfo.put("location", sLocation); + TicketInfo.put("description", sDescription); + TicketInfo.put("photo", photo_ticket); + + + } catch (JSONException e) {//re-enable all buttons + // TODO Auto-generated catch block + SubmitTicketBTN.setEnabled(true); + CameraBTN.setEnabled(true); + clearPhoto.setEnabled(true); + SubmitTicketBTN.setText("Submit Ticket"); + e.printStackTrace(); + } + Log.d("API", "In Ticket: START " + photo_ticket + " END"); + Log.d("API", "In Ticket Count: " + photo_ticket.length()); + spinner.setVisibility(v.VISIBLE); //sets spinner loader to visible + Thread thread = new Thread(new API_Communications("https://cmps.techneaux.com/submit-ticket", TicketInfo)); + thread.start(); //send data to API via helper thread + + startTestThread(sLocation); //handle API response on another thread + return; + } + + } + + + }); + + clearPhoto.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) {//listener to clear photo from app + SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit(); + photo_ticket = ""; + editor.putString("ticket_photo", null); + editor.commit(); + + imageView.setImageBitmap(null); + } + }); + CameraBTN.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { //listener to take a picture and store into phone app. + + imageFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/picture.jpg"; + File imageFile = new File(imageFilePath); + Uri imageFileUri = Uri.fromFile(imageFile); // convert path to Uri + + Intent it = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); + it.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageFileUri); + startActivityForResult(it, CAMERA_REQUEST); } + }); + imageView.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + loadPhoto(imageView); + } + }); + + + } + private String imageFilePath; + + /** + * Preconditions: None + * Post Conditions: check for photo and store photo into applicatio + * Parameters: requestCode, resultcode, and data + * Use: when we need to take a picture. + */ + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (RESULT_OK == resultCode) { + + + // Decode it for real + BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options(); + bmpFactoryOptions.inJustDecodeBounds = false; + + //imageFilePath image path which you pass with intent + Bitmap bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions); + + Bitmap scaledBitmap = scaleDown(bmp, 1000, true); //scale picture to 1000 pixel resolution + + //convert bitmap to base64 + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + scaledBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream); + byte[] byteArray = byteArrayOutputStream.toByteArray(); + String encoded = Base64.encodeToString(byteArray, Base64.NO_WRAP); + //end convert bitmap to base64 + + Log.d("API", "Init Photo Size:" + encoded.length()); + SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit(); + editor.putString("ticket_photo", encoded); + editor.commit(); // save base64 to shared preferences + + + photo_ticket = encoded; // set base64 to global var + + // Display it + imageView.setImageBitmap(bmp); //set pic taken to the preview image view + } + } + /** + * Preconditions: has a bitmap to scale down + * Post Conditions: photo scaled to desired size + * Parameters: bitmap image, max size of photo, and filter + * Use: when we need to take a picture. + */ + public static Bitmap scaleDown(Bitmap realImage, float maxImageSize, + boolean filter) { + float ratio = Math.min( + (float) maxImageSize / realImage.getWidth(), + (float) maxImageSize / realImage.getHeight()); + int width = Math.round((float) ratio * realImage.getWidth()); + int height = Math.round((float) ratio * realImage.getHeight()); + + Bitmap newBitmap = Bitmap.createScaledBitmap(realImage, width, + height, filter); + return newBitmap; + } + +@Override +protected void onPause() +{ + super.onPause(); + + //store ticket location and description to memory on app minimize + SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit(); + editor.putString("ticket_location", Location.getText().toString()); + editor.putString("ticket_description", Description.getText().toString()); + editor.commit(); + + +} + /** + * Preconditions: data sent to API + * Post Conditions: response from API handled + * Parameters: location sent to ticket api + * Use: when we need to send a ticket + */ + protected void startTestThread(final String sLocation) { + Thread t = new Thread() { + public void run() { + Log.d("API", "In thread"); + SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE); + final SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit(); + + + while (API_Communications.result == null) { //wait for API result + } + + final String result = API_Communications.result; //get api result + + JSONObject obj = null; //make json obj + try {//try to parse api result into json obj + + obj = new JSONObject(result); + + + } catch (Throwable t) { + runOnUiThread(new Runnable() { + + @Override + public void run() {//use runonUI to modify layout objects + SubmitTicketBTN.setEnabled(true); + CameraBTN.setEnabled(true); + clearPhoto.setEnabled(true); + ErrorTicket.setText("Invalid Response from Server, please try again.\n " + result); + SubmitTicketBTN.setText("Submit Ticket"); + + } + }); + + + } + String error = null; //string to hold error message if any from API. + if (obj.has("niceMessage")) {//checks for error message + try { + error = obj.get("niceMessage").toString(); //pulls niceMessage out of json from API + + } catch (JSONException e) { + e.printStackTrace(); + runOnUiThread(new Runnable() { + + @Override + public void run() { //alter UI objects + CameraBTN.setEnabled(true); + clearPhoto.setEnabled(true); + SubmitTicketBTN.setEnabled(true); + SubmitTicketBTN.setText("Submit Ticket"); + + } + }); + + } + } + String PhotoStatus = ""; //string to display check if picture is present + if (error == null) {//check for no error + + //condition to know no pic present to send + if (prefs.getString("ticket_photo", null) == null) { + PhotoStatus = "No Photo"; + } else { //otherwise there is a pic + PhotoStatus = "Photo Attached"; + } + + runOnUiThread(new Runnable() { + + @Override + public void run() { + Description.setText(""); + } + }); //clear description + + + photo_ticket = ""; + editor.putString("ticket_photo", null); //wipe photo off memory + editor.commit(); + final String finalPhotoStatus = PhotoStatus; + runOnUiThread(new Runnable() { + + @Override + public void run() { //do all UI updates to text boxes and make confirmation toast + editor.putString("ticket_location", sLocation); + editor.commit(); + ErrorTicket.setText(""); + CameraBTN.setEnabled(true); + clearPhoto.setEnabled(true); + imageView.setImageBitmap(null); + spinner.setVisibility(View.INVISIBLE); + SubmitTicketBTN.setEnabled(true); + SubmitTicketBTN.setText("Submit Ticket"); + Toast.makeText(getApplicationContext(), "Ticket Sent Successfully!\n\n" + + companyname.getText().toString() + "\nLocation: " + + Location.getText().toString() + "\n" + + employeename.getText().toString() + "\n" + + phonenumber.getText().toString() + "\n" + + emailaddress.getText().toString() + "\nDescription: " + + Description.getText().toString() + "\nPhoto: " + + finalPhotoStatus, + Toast.LENGTH_LONG).show(); + + } + }); + + } else { //error detected, print error to screen + final String finalError = error; + runOnUiThread(new Runnable() { + + @Override + public void run() { + spinner.setVisibility(View.INVISIBLE); + ErrorTicket.setText(finalError); + CameraBTN.setEnabled(true); + clearPhoto.setEnabled(true); + SubmitTicketBTN.setText("Submit Ticket"); + SubmitTicketBTN.setEnabled(true); + } + }); + + + } + } + }; + + t.start(); + } + /** + * Preconditions: none + * Post Conditions: show picture preview in bigger screen + * Parameters: imageview photo + * Use: when we need to show a picture bigger + */ + private void loadPhoto(ImageView imageView) { + + ImageView tempImageView = imageView; + + + AlertDialog.Builder imageDialog = new AlertDialog.Builder(this); + LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE); + + View layout = inflater.inflate(R.layout.photo_preview, null); + ImageView image = (ImageView) layout.findViewById(R.id.imageView2); + image.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 1500)); + image.setImageDrawable(tempImageView.getDrawable()); + imageDialog.setView(layout); + imageDialog.create(); + imageDialog.show(); + } + + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + //preventing default implementation previous to android.os.Build.VERSION_CODES.ECLAIR + return true; + } + return super.onKeyDown(keyCode, event); + } + + @Override + public void onBackPressed() { + // Do Here what ever you want do on back press; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.ticket_menu, menu); + return true; + } + + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.wipe_data) { + AlertDialog eraseConfirm = eraseDialogAlertMaker(); //dialog before wiping + // data to confirm wipe + + eraseConfirm.show(); //show dialog + Toast.makeText(getApplicationContext(), "Data Erased", + Toast.LENGTH_LONG).show(); + + return true; + } + if (id == R.id.EmployeeCredentials) { + //------Save Location and Description to memory + SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit(); + editor.putString("ticket_location", Location.getText().toString()); + editor.putString("ticket_description", Description.getText().toString()); + editor.putInt("screen_state", 2); + editor.commit(); + //------End Save Location and Description to memory + + //------Go back to registration + final View v = findViewById(android.R.id.content); + Intent myIntent = new Intent(v.getContext(), RegistrationActivity.class); + startActivityForResult(myIntent, 0); + finish(); + //end go back to reg + + + } + + return super.onOptionsItemSelected(item); + } + + private AlertDialog eraseDialogAlertMaker(){ + + AlertDialog eraseDialog = + + new AlertDialog.Builder(this) + //set message, title, and icon + .setTitle("Erase Data?") + .setMessage("Are you sure that you want to erase all stored data?") + + //set three option buttons + .setPositiveButton("Yes", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + //whatever should be done when answering "YES" goes here + SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit(); + SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE); + try { + MainActivity.wipeData(editor); + RegistrationActivity.wipeData(editor, prefs); + } catch (Exception e) { + e.printStackTrace(); + } + wipeData(editor, prefs); + final View v = findViewById(android.R.id.content); + Intent myIntent = new Intent(v.getContext(), MainActivity.class); + startActivityForResult(myIntent, 0); + + + } + }) + .setNegativeButton("NO", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + //whatever should be done when answering "NO" goes here + + + } + })//setNegativeButton + + .create(); + + return eraseDialog; + } + public static void wipeData(SharedPreferences.Editor editor, SharedPreferences prefs) { + //wipe shared preferences + editor.putString("ticket_photo", null); + editor.putString("ticket_location", null); + editor.putInt("screen_state", 0); + editor.putString("emp_firstname", null); + editor.putString("emp_lastname", null); + editor.putString("emp_phonenumber", null); + editor.putString("emp_emailaddress", null); + editor.putInt("screen_state", 0); + editor.putString("companyname", null); + editor.putInt("screen_state", 0); + editor.putString("ticket_description",null);//wipe out ticket description + editor.putString("authKey", null); + editor.commit(); + //end wipe shared preferences + if (!(prefs.getInt("screen_state", 0) == 3)) { //if screenstate is 3 wipe local text fields + + Location.setText(null); + Description.setText(null); + } + } + +} diff --git a/Android/TechneauxMobileApp/app/src/main/res/drawable-hdpi/techneauxlogo.png b/Android/TechneauxMobileApp/app/src/main/res/drawable-hdpi/techneauxlogo.png new file mode 100644 index 0000000..7756ffa Binary files /dev/null and b/Android/TechneauxMobileApp/app/src/main/res/drawable-hdpi/techneauxlogo.png differ diff --git a/Android/TechneauxMobileApp/app/src/main/res/drawable-mdpi/techneauxlogo.png b/Android/TechneauxMobileApp/app/src/main/res/drawable-mdpi/techneauxlogo.png new file mode 100644 index 0000000..7756ffa Binary files /dev/null and b/Android/TechneauxMobileApp/app/src/main/res/drawable-mdpi/techneauxlogo.png differ diff --git a/Android/TechneauxMobileApp/app/src/main/res/drawable-xhdpi/techneauxlogo.png b/Android/TechneauxMobileApp/app/src/main/res/drawable-xhdpi/techneauxlogo.png new file mode 100644 index 0000000..7756ffa Binary files /dev/null and b/Android/TechneauxMobileApp/app/src/main/res/drawable-xhdpi/techneauxlogo.png differ diff --git a/Android/TechneauxMobileApp/app/src/main/res/drawable-xxhdpi/phone.png b/Android/TechneauxMobileApp/app/src/main/res/drawable-xxhdpi/phone.png new file mode 100644 index 0000000..e50ce9c Binary files /dev/null and b/Android/TechneauxMobileApp/app/src/main/res/drawable-xxhdpi/phone.png differ diff --git a/Android/TechneauxMobileApp/app/src/main/res/drawable-xxhdpi/techneauxlogo.png b/Android/TechneauxMobileApp/app/src/main/res/drawable-xxhdpi/techneauxlogo.png new file mode 100644 index 0000000..7756ffa Binary files /dev/null and b/Android/TechneauxMobileApp/app/src/main/res/drawable-xxhdpi/techneauxlogo.png differ diff --git a/Android/TechneauxMobileApp/app/src/main/res/layout/activity_main.xml b/Android/TechneauxMobileApp/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..d639444 --- /dev/null +++ b/Android/TechneauxMobileApp/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,120 @@ + + + // Company Name + + + // Password + + //Progress Bar + + // Submit button +