diff --git a/phoneClients/README.md b/phoneClients/README.md new file mode 100644 index 0000000..e703c24 --- /dev/null +++ b/phoneClients/README.md @@ -0,0 +1,7 @@ +Just a note about the 2 android clients (android and android-wp). The android-wp client is for the wordpress plugin and the android client is for the php website. They will not work if they are swapped. I may decide to create one client for both later but don't feel like doing it right now. + +The difference between the two is that the wordpress client gets a "nonce" from the wordpress plugin: + +https://codex.wordpress.org/WordPress_Nonces + +This is used for added security so that apps that have not been properly verified will not be able to send updates to the plugin. A nice safety feature. \ No newline at end of file diff --git a/phoneClients/android-wp/.gitignore b/phoneClients/android-wp/.gitignore new file mode 100644 index 0000000..d6bfc95 --- /dev/null +++ b/phoneClients/android-wp/.gitignore @@ -0,0 +1,4 @@ +.gradle +/local.properties +/.idea/workspace.xml +.DS_Store diff --git a/phoneClients/android-wp/.idea/.name b/phoneClients/android-wp/.idea/.name new file mode 100644 index 0000000..1fd74d1 --- /dev/null +++ b/phoneClients/android-wp/.idea/.name @@ -0,0 +1 @@ +android \ No newline at end of file diff --git a/phoneClients/android-wp/.idea/compiler.xml b/phoneClients/android-wp/.idea/compiler.xml new file mode 100644 index 0000000..217af47 --- /dev/null +++ b/phoneClients/android-wp/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/phoneClients/android-wp/.idea/copyright/profiles_settings.xml b/phoneClients/android-wp/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/phoneClients/android-wp/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/phoneClients/android-wp/.idea/encodings.xml b/phoneClients/android-wp/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/phoneClients/android-wp/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/phoneClients/android-wp/.idea/gradle.xml b/phoneClients/android-wp/.idea/gradle.xml new file mode 100644 index 0000000..736c7b5 --- /dev/null +++ b/phoneClients/android-wp/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/phoneClients/android-wp/.idea/libraries/android_async_http_1_4_9.xml b/phoneClients/android-wp/.idea/libraries/android_async_http_1_4_9.xml new file mode 100644 index 0000000..ccea99d --- /dev/null +++ b/phoneClients/android-wp/.idea/libraries/android_async_http_1_4_9.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/phoneClients/android-wp/.idea/libraries/appcompat_v7_21_0_3.xml b/phoneClients/android-wp/.idea/libraries/appcompat_v7_21_0_3.xml new file mode 100644 index 0000000..751a9d9 --- /dev/null +++ b/phoneClients/android-wp/.idea/libraries/appcompat_v7_21_0_3.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/phoneClients/android-wp/.idea/libraries/httpclient_4_3_6.xml b/phoneClients/android-wp/.idea/libraries/httpclient_4_3_6.xml new file mode 100644 index 0000000..a479d14 --- /dev/null +++ b/phoneClients/android-wp/.idea/libraries/httpclient_4_3_6.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/phoneClients/android-wp/.idea/libraries/play_services_6_5_87.xml b/phoneClients/android-wp/.idea/libraries/play_services_6_5_87.xml new file mode 100644 index 0000000..aa87556 --- /dev/null +++ b/phoneClients/android-wp/.idea/libraries/play_services_6_5_87.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/phoneClients/android-wp/.idea/libraries/support_annotations_21_0_3.xml b/phoneClients/android-wp/.idea/libraries/support_annotations_21_0_3.xml new file mode 100644 index 0000000..6fbaa90 --- /dev/null +++ b/phoneClients/android-wp/.idea/libraries/support_annotations_21_0_3.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/phoneClients/android-wp/.idea/libraries/support_v4_21_0_3.xml b/phoneClients/android-wp/.idea/libraries/support_v4_21_0_3.xml new file mode 100644 index 0000000..1948aee --- /dev/null +++ b/phoneClients/android-wp/.idea/libraries/support_v4_21_0_3.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/phoneClients/android-wp/.idea/misc.xml b/phoneClients/android-wp/.idea/misc.xml new file mode 100644 index 0000000..8fef058 --- /dev/null +++ b/phoneClients/android-wp/.idea/misc.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + localhost + 5050 + + + + diff --git a/phoneClients/android-wp/.idea/modules.xml b/phoneClients/android-wp/.idea/modules.xml new file mode 100644 index 0000000..2863810 --- /dev/null +++ b/phoneClients/android-wp/.idea/modules.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/phoneClients/android-wp/.idea/scopes/scope_settings.xml b/phoneClients/android-wp/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/phoneClients/android-wp/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/phoneClients/android-wp/.idea/vcs.xml b/phoneClients/android-wp/.idea/vcs.xml new file mode 100644 index 0000000..a5dd086 --- /dev/null +++ b/phoneClients/android-wp/.idea/vcs.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/phoneClients/android-wp/GpsTracker.iml b/phoneClients/android-wp/GpsTracker.iml new file mode 100644 index 0000000..8c0cc17 --- /dev/null +++ b/phoneClients/android-wp/GpsTracker.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/phoneClients/android-wp/GpsTracker/GpsTracker.iml b/phoneClients/android-wp/GpsTracker/GpsTracker.iml new file mode 100644 index 0000000..9d3a505 --- /dev/null +++ b/phoneClients/android-wp/GpsTracker/GpsTracker.iml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/phoneClients/android-wp/GpsTrackerProject.iml b/phoneClients/android-wp/GpsTrackerProject.iml new file mode 100644 index 0000000..9d3a505 --- /dev/null +++ b/phoneClients/android-wp/GpsTrackerProject.iml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/phoneClients/android-wp/README.md b/phoneClients/android-wp/README.md new file mode 100644 index 0000000..fda350c --- /dev/null +++ b/phoneClients/android-wp/README.md @@ -0,0 +1 @@ +This project was built with *android studio* and is close to the original version but uses GET instead of POST to update the wordpress plugin. diff --git a/phoneClients/android-wp/android-wp.iml b/phoneClients/android-wp/android-wp.iml new file mode 100644 index 0000000..0bb6048 --- /dev/null +++ b/phoneClients/android-wp/android-wp.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/phoneClients/android-wp/android.iml b/phoneClients/android-wp/android.iml new file mode 100644 index 0000000..edb62a6 --- /dev/null +++ b/phoneClients/android-wp/android.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/phoneClients/android-wp/app/.gitignore b/phoneClients/android-wp/app/.gitignore new file mode 100644 index 0000000..3a36c6e --- /dev/null +++ b/phoneClients/android-wp/app/.gitignore @@ -0,0 +1,26 @@ +# Built application files +*.apk +*.ap_ + +# Files for the Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +#Log Files +*.log diff --git a/phoneClients/android-wp/app/app.iml b/phoneClients/android-wp/app/app.iml new file mode 100644 index 0000000..a2ed29e --- /dev/null +++ b/phoneClients/android-wp/app/app.iml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/phoneClients/android-wp/app/build.gradle b/phoneClients/android-wp/app/build.gradle new file mode 100644 index 0000000..0e2f230 --- /dev/null +++ b/phoneClients/android-wp/app/build.gradle @@ -0,0 +1,28 @@ +apply plugin: 'android' + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.2" + + defaultConfig { + applicationId "com.websmithing.wp.gpstracker" + minSdkVersion 10 + targetSdkVersion 21 + versionCode 4 + versionName "1.0.3" + } + buildTypes { + release { + debuggable false + runProguard false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:21.0.3' + compile 'com.google.android.gms:play-services:6.5.87' + compile 'com.loopj.android:android-async-http:1.4.9' +} diff --git a/phoneClients/android-wp/app/proguard-rules.txt b/phoneClients/android-wp/app/proguard-rules.txt new file mode 100644 index 0000000..cb8998d --- /dev/null +++ b/phoneClients/android-wp/app/proguard-rules.txt @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Applications/Android Studio.app/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# 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 *; +#} \ No newline at end of file diff --git a/phoneClients/android-wp/app/src/main/AndroidManifest.xml b/phoneClients/android-wp/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..69b917d --- /dev/null +++ b/phoneClients/android-wp/app/src/main/AndroidManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/GpsTrackerActivity.java b/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/GpsTrackerActivity.java new file mode 100644 index 0000000..c977abd --- /dev/null +++ b/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/GpsTrackerActivity.java @@ -0,0 +1,324 @@ +package com.websmithing.wp.gpstracker; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Color; +import android.os.Bundle; +import android.os.SystemClock; +import android.support.v7.app.ActionBarActivity; +import android.util.Log; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.widget.Button; +import android.widget.EditText; +import android.widget.RadioGroup; +import android.widget.Toast; + +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GooglePlayServicesUtil; +import com.loopj.android.http.AsyncHttpResponseHandler; +import com.loopj.android.http.RequestParams; + +import java.util.UUID; +import java.util.Date; + +public class GpsTrackerActivity extends ActionBarActivity { + private static final String TAG = "GpsTrackerActivity"; + + // use the websmithing defaultUploadWebsite for testing and then check your + // location with your browser here: https://www.websmithing.com/gpstracker/displaymap.php + private String defaultUploadWebsite; + + private static EditText txtUserName; + private static EditText txtWebsite; + private static Button trackingButton; + + private boolean currentlyTracking; + private RadioGroup intervalRadioGroup; + private int intervalInMinutes = 1; + private AlarmManager alarmManager; + private Intent gpsTrackerIntent; + private PendingIntent pendingIntent; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_gpstracker); + + defaultUploadWebsite = getString(R.string.default_upload_website); + + txtWebsite = (EditText)findViewById(R.id.txtWebsite); + txtUserName = (EditText)findViewById(R.id.txtUserName); + intervalRadioGroup = (RadioGroup)findViewById(R.id.intervalRadioGroup); + trackingButton = (Button)findViewById(R.id.trackingButton); + txtUserName.setImeOptions(EditorInfo.IME_ACTION_DONE); + + SharedPreferences sharedPreferences = this.getSharedPreferences("com.websmithing.gpstracker.prefs", Context.MODE_PRIVATE); + currentlyTracking = sharedPreferences.getBoolean("currentlyTracking", false); + + boolean firstTimeLoadindApp = sharedPreferences.getBoolean("firstTimeLoadindApp", true); + if (firstTimeLoadindApp) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean("firstTimeLoadindApp", false); + editor.putString("appID", UUID.randomUUID().toString()); + editor.apply(); + } + + intervalRadioGroup.setOnCheckedChangeListener( + new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup radioGroup, int i) { + saveInterval(); + } + }); + + trackingButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + trackLocation(view); + } + }); + } + + private void saveInterval() { + if (currentlyTracking) { + Toast.makeText(getApplicationContext(), R.string.user_needs_to_restart_tracking, Toast.LENGTH_LONG).show(); + } + + SharedPreferences sharedPreferences = this.getSharedPreferences("com.websmithing.gpstracker.prefs", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreferences.edit(); + + switch (intervalRadioGroup.getCheckedRadioButtonId()) { + case R.id.i1: + editor.putInt("intervalInMinutes", 1); + break; + case R.id.i5: + editor.putInt("intervalInMinutes", 5); + break; + case R.id.i15: + editor.putInt("intervalInMinutes", 15); + break; + } + + editor.commit(); + } + + private void startAlarmManager() { + Log.d(TAG, "startAlarmManager"); + + Context context = getBaseContext(); + alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); + gpsTrackerIntent = new Intent(context, GpsTrackerAlarmReceiver.class); + pendingIntent = PendingIntent.getBroadcast(context, 0, gpsTrackerIntent, 0); + + SharedPreferences sharedPreferences = this.getSharedPreferences("com.websmithing.gpstracker.prefs", Context.MODE_PRIVATE); + intervalInMinutes = sharedPreferences.getInt("intervalInMinutes", 1); + + alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime(), + intervalInMinutes * 60000, // 60000 = 1 minute + pendingIntent); + } + + private void cancelAlarmManager() { + Log.d(TAG, "cancelAlarmManager"); + + Context context = getBaseContext(); + Intent gpsTrackerIntent = new Intent(context, GpsTrackerAlarmReceiver.class); + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, gpsTrackerIntent, 0); + AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); + alarmManager.cancel(pendingIntent); + } + + // called when trackingButton is tapped + protected void trackLocation(View v) { + if (!saveUserSettings()) { + return; + } + + if (!checkIfGooglePlayEnabled()) { + return; + } + + if (currentlyTracking) { + stopTracking(); + } else { + startTracking(); + } + + setTrackingButtonState(); + } + + private void startTracking() { + SharedPreferences sharedPreferences = this.getSharedPreferences("com.websmithing.gpstracker.prefs", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreferences.edit(); + String sessionID = UUID.randomUUID().toString(); + editor.putString("sessionID", sessionID); + currentlyTracking = true; + editor.putBoolean("currentlyTracking", true); + editor.putFloat("totalDistanceInMeters", 0f); + editor.putBoolean("firstTimeGettingPosition", true); + + Date now = new Date(); + editor.putLong("startTime", now.getTime()); // in milliseconds + editor.commit(); + + getWordpressNonce(sessionID); + startAlarmManager(); + } + + private void stopTracking() { + SharedPreferences sharedPreferences = this.getSharedPreferences("com.websmithing.gpstracker.prefs", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreferences.edit(); + currentlyTracking = false; + editor.putBoolean("currentlyTracking", false); + editor.putString("sessionID", ""); + editor.putLong("startTime", 0); + editor.commit(); + + cancelAlarmManager(); + } + + private boolean saveUserSettings() { + if (textFieldsAreEmptyOrHaveSpaces()) { + return false; + } + + SharedPreferences sharedPreferences = this.getSharedPreferences("com.websmithing.gpstracker.prefs", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreferences.edit(); + + switch (intervalRadioGroup.getCheckedRadioButtonId()) { + case R.id.i1: + editor.putInt("intervalInMinutes", 1); + break; + case R.id.i5: + editor.putInt("intervalInMinutes", 5); + break; + case R.id.i15: + editor.putInt("intervalInMinutes", 15); + break; + } + + editor.putString("userName", txtUserName.getText().toString().trim()); + editor.putString("defaultUploadWebsite", txtWebsite.getText().toString().trim()); + + editor.commit(); + + return true; + } + + private boolean textFieldsAreEmptyOrHaveSpaces() { + String tempUserName = txtUserName.getText().toString().trim(); + String tempWebsite = txtWebsite.getText().toString().trim(); + + if (tempWebsite.length() == 0 || hasSpaces(tempWebsite) || tempUserName.length() == 0 || hasSpaces(tempUserName)) { + Toast.makeText(this, R.string.textfields_empty_or_spaces, Toast.LENGTH_LONG).show(); + return true; + } + + return false; + } + + private boolean hasSpaces(String str) { + return ((str.split(" ").length > 1) ? true : false); + } + + private void displayUserSettings() { + SharedPreferences sharedPreferences = this.getSharedPreferences("com.websmithing.gpstracker.prefs", Context.MODE_PRIVATE); + intervalInMinutes = sharedPreferences.getInt("intervalInMinutes", 1); + + switch (intervalInMinutes) { + case 1: + intervalRadioGroup.check(R.id.i1); + break; + case 5: + intervalRadioGroup.check(R.id.i5); + break; + case 15: + intervalRadioGroup.check(R.id.i15); + break; + } + + txtWebsite.setText(sharedPreferences.getString("defaultUploadWebsite", defaultUploadWebsite)); + txtUserName.setText(sharedPreferences.getString("userName", "")); + } + + private boolean checkIfGooglePlayEnabled() { + if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) { + return true; + } else { + Log.e(TAG, "unable to connect to google play services."); + Toast.makeText(getApplicationContext(), R.string.google_play_services_unavailable, Toast.LENGTH_LONG).show(); + return false; + } + } + + private void getWordpressNonce(String sessionID) { + SharedPreferences sharedPreferences = this.getSharedPreferences("com.websmithing.gpstracker.prefs", Context.MODE_PRIVATE); + final SharedPreferences.Editor editor = sharedPreferences.edit(); + + final RequestParams requestParams = new RequestParams(); + requestParams.put("gpstracker", "nonce"); + requestParams.put("sessionid", sessionID); // uuid + requestParams.put("phonenumber", sharedPreferences.getString("appID", "")); // uuid + + // http://codex.wordpress.org/Glossary#Nonce + + final String uploadWebsite = sharedPreferences.getString("defaultUploadWebsite", defaultUploadWebsite); + + LoopjHttpClient.get(uploadWebsite, requestParams, new AsyncHttpResponseHandler() { + @Override + public void onSuccess(int statusCode, cz.msebera.android.httpclient.Header[] headers, byte[] responseBody) { + String wordpressNonce = new String(responseBody); + + LoopjHttpClient.debugLoopJ(TAG, "getWordpressNonce - success", uploadWebsite, requestParams, responseBody, headers, statusCode, null); + + if (wordpressNonce.equals("0")) { + Toast.makeText(getApplicationContext(), R.string.security_token_error, Toast.LENGTH_LONG).show(); + editor.putString("wordpressNonce", "0"); + Log.e(TAG, "getWordpressNonce1: 0"); + + stopTracking(); + setTrackingButtonState(); + + } else { + editor.putString("wordpressNonce", wordpressNonce); + // Log.e(TAG, "getWordpressNonce2: " + wordpressNonce); + } + editor.commit(); + } + @Override + public void onFailure(int statusCode, cz.msebera.android.httpclient.Header[] headers, byte[] errorResponse, Throwable e) { + Toast.makeText(getApplicationContext(), R.string.reachability_error, Toast.LENGTH_LONG).show(); + LoopjHttpClient.debugLoopJ(TAG, "getWordpressNonce - failure", uploadWebsite, requestParams, errorResponse, headers, statusCode, e); + editor.putString("wordpressNonce", "0"); + editor.commit(); + } + }); + } + + private void setTrackingButtonState() { + if (currentlyTracking) { + trackingButton.setBackgroundResource(R.drawable.green_tracking_button); + trackingButton.setTextColor(Color.BLACK); + trackingButton.setText(R.string.tracking_is_on); + } else { + trackingButton.setBackgroundResource(R.drawable.red_tracking_button); + trackingButton.setTextColor(Color.WHITE); + trackingButton.setText(R.string.tracking_is_off); + } + } + + @Override + public void onResume() { + Log.d(TAG, "onResume"); + super.onResume(); // Always call the superclass method first + + displayUserSettings(); + setTrackingButtonState(); + } + +} diff --git a/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/GpsTrackerAlarmReceiver.java b/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/GpsTrackerAlarmReceiver.java new file mode 100644 index 0000000..121e410 --- /dev/null +++ b/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/GpsTrackerAlarmReceiver.java @@ -0,0 +1,14 @@ +package com.websmithing.wp.gpstracker; + +import android.content.Context; +import android.content.Intent; +import android.support.v4.content.WakefulBroadcastReceiver; + +// make sure we use a WakefulBroadcastReceiver so that we acquire a partial wakelock +public class GpsTrackerAlarmReceiver extends WakefulBroadcastReceiver { + private static final String TAG = "GpsTrackerAlarmReceiver"; + @Override + public void onReceive(Context context, Intent intent) { + context.startService(new Intent(context, LocationService.class)); + } +} diff --git a/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/GpsTrackerBootReceiver.java b/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/GpsTrackerBootReceiver.java new file mode 100644 index 0000000..65b51b7 --- /dev/null +++ b/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/GpsTrackerBootReceiver.java @@ -0,0 +1,32 @@ +package com.websmithing.wp.gpstracker; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.SystemClock; + +public class GpsTrackerBootReceiver extends BroadcastReceiver { + private static final String TAG = "GpsTrackerBootReceiver"; + @Override + public void onReceive(Context context, Intent intent) { + AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); + Intent gpsTrackerIntent = new Intent(context, GpsTrackerAlarmReceiver.class); + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, gpsTrackerIntent, 0); + + SharedPreferences sharedPreferences = context.getSharedPreferences("com.websmithing.gpstracker.prefs", Context.MODE_PRIVATE); + int intervalInMinutes = sharedPreferences.getInt("intervalInMinutes", 1); + Boolean currentlyTracking = sharedPreferences.getBoolean("currentlyTracking", false); + + if (currentlyTracking) { + alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime(), + intervalInMinutes * 60000, // 60000 = 1 minute, + pendingIntent); + } else { + alarmManager.cancel(pendingIntent); + } + } +} diff --git a/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/LocationService.java b/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/LocationService.java new file mode 100644 index 0000000..fc695d2 --- /dev/null +++ b/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/LocationService.java @@ -0,0 +1,232 @@ +package com.websmithing.wp.gpstracker; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.location.Location; +import android.os.Bundle; +import android.os.IBinder; +import android.util.Log; + +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GooglePlayServicesUtil; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.location.LocationListener; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationServices; +import com.loopj.android.http.AsyncHttpResponseHandler; +import com.loopj.android.http.RequestParams; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +public class LocationService extends Service implements + GoogleApiClient.ConnectionCallbacks, + GoogleApiClient.OnConnectionFailedListener, + LocationListener { + + private static final String TAG = "LocationService"; + + // use the websmithing defaultUploadWebsite for testing and then check your + // location with your browser here: https://www.websmithing.com/gpstracker/displaymap.php + private String defaultUploadWebsite; + + private boolean currentlyProcessingLocation = false; + private LocationRequest locationRequest; + private GoogleApiClient googleApiClient; + + @Override + public void onCreate() { + super.onCreate(); + + defaultUploadWebsite = getString(R.string.default_upload_website); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + // if we are currently trying to get a location and the alarm manager has called this again, + // no need to start processing a new location. + if (!currentlyProcessingLocation) { + currentlyProcessingLocation = true; + startTracking(); + } + + return START_NOT_STICKY; + } + + private void startTracking() { + Log.d(TAG, "startTracking"); + + SharedPreferences sharedPreferences = this.getSharedPreferences("com.websmithing.gpstracker.prefs", Context.MODE_PRIVATE); + String wordpressNonce = sharedPreferences.getString("wordpressNonce", "0"); + + if (wordpressNonce.equals("0")) { + Log.e(TAG, "startTracking wordpressNonce: 0"); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean("currentlyTracking", false); + editor.putString("sessionID", ""); + editor.commit(); + return; + } + + if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) { + + googleApiClient = new GoogleApiClient.Builder(this) + .addApi(LocationServices.API) + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .build(); + + if (!googleApiClient.isConnected() || !googleApiClient.isConnecting()) { + googleApiClient.connect(); + } + } else { + Log.e(TAG, "unable to connect to google play services."); + } + } + + protected void sendLocationDataToWebsite(Location location) { + // formatted for mysql datetime format + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getDefault()); + Date date = new Date(location.getTime()); + + SharedPreferences sharedPreferences = this.getSharedPreferences("com.websmithing.gpstracker.prefs", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreferences.edit(); + + float totalDistanceInMeters = sharedPreferences.getFloat("totalDistanceInMeters", 0f); + + boolean firstTimeGettingPosition = sharedPreferences.getBoolean("firstTimeGettingPosition", true); + + if (firstTimeGettingPosition) { + editor.putBoolean("firstTimeGettingPosition", false); + } else { + Location previousLocation = new Location(""); + previousLocation.setLatitude(sharedPreferences.getFloat("previousLatitude", 0f)); + previousLocation.setLongitude(sharedPreferences.getFloat("previousLongitude", 0f)); + + float distance = location.distanceTo(previousLocation); + totalDistanceInMeters += distance; + editor.putFloat("totalDistanceInMeters", totalDistanceInMeters); + } + + editor.putFloat("previousLatitude", (float)location.getLatitude()); + editor.putFloat("previousLongitude", (float)location.getLongitude()); + editor.commit(); + + final RequestParams requestParams = new RequestParams(); + requestParams.put("gpstracker", "location"); + requestParams.put("latitude", Double.toString(location.getLatitude())); + requestParams.put("longitude", Double.toString(location.getLongitude())); + requestParams.put("username", sharedPreferences.getString("userName", "")); + requestParams.put("phonenumber", sharedPreferences.getString("appID", "")); // uuid + requestParams.put("sessionid", sharedPreferences.getString("sessionID", "0")); // uuid + Double speedInMilesPerHour = location.getSpeed()* 2.2369; + requestParams.put("speed", Integer.toString(speedInMilesPerHour.intValue())); + Float direction = location.getBearing(); + requestParams.put("direction", Integer.toString(direction.intValue())); + + if (totalDistanceInMeters > 0) { + requestParams.put("distance", Float.toString(totalDistanceInMeters / 1609)); // in miles + } else { + requestParams.put("distance", 0); // in miles + } + + try { + requestParams.put("gpstime", URLEncoder.encode(dateFormat.format(date), "UTF-8")); + } catch (UnsupportedEncodingException e) {} + + requestParams.put("locationmethod", location.getProvider()); + Double accuracyInFeet = location.getAccuracy()* 3.28; + requestParams.put("accuracy", Integer.toString(accuracyInFeet.intValue())); + + Double altitudeInFeet = location.getAltitude() * 3.28; + requestParams.put("extrainfo", Integer.toString(altitudeInFeet.intValue())); + + requestParams.put("eventtype", "android-wp"); + requestParams.put("wpnonce", sharedPreferences.getString("wordpressNonce", "1")); + + final String uploadWebsite = sharedPreferences.getString("defaultUploadWebsite", defaultUploadWebsite); + + LoopjHttpClient.get(uploadWebsite, requestParams, new AsyncHttpResponseHandler() { + @Override + public void onSuccess(int statusCode, cz.msebera.android.httpclient.Header[] headers, byte[] responseBody) { + LoopjHttpClient.debugLoopJ(TAG, "sendLocationDataToWebsite - success", uploadWebsite, requestParams, responseBody, headers, statusCode, null); + stopSelf(); + } + @Override + public void onFailure(int statusCode, cz.msebera.android.httpclient.Header[] headers, byte[] errorResponse, Throwable e) { + LoopjHttpClient.debugLoopJ(TAG, "sendLocationDataToWebsite - failure", uploadWebsite, requestParams, errorResponse, headers, statusCode, e); + stopSelf(); + } + }); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onLocationChanged(Location location) { + Log.d(TAG, "onLocationChanged"); + + if (location != null) { + Log.e(TAG, "position: " + location.getLatitude() + ", " + location.getLongitude() + " accuracy: " + location.getAccuracy()); + + // we have our desired accuracy of 500 meters so lets quit this service, + // onDestroy will be called and stop our location updates + if (location.getAccuracy() < 500.0f) { + stopLocationUpdates(); + sendLocationDataToWebsite(location); + } + } + } + + private void stopLocationUpdates() { + if (googleApiClient != null && googleApiClient.isConnected()) { + googleApiClient.disconnect(); + } + } + + /** + * Called by Location Services when the request to connect the + * client finishes successfully. At this point, you can + * request the current location or start periodic updates + */ + @Override + public void onConnected(Bundle bundle) { + Log.d(TAG, "onConnected"); + + locationRequest = LocationRequest.create(); + locationRequest.setInterval(1000); // milliseconds + locationRequest.setFastestInterval(1000); // the fastest rate in milliseconds at which your app can handle location updates + locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); + + LocationServices.FusedLocationApi.requestLocationUpdates( + googleApiClient, locationRequest, this); + } + + @Override + public void onConnectionFailed(ConnectionResult connectionResult) { + Log.e(TAG, "onConnectionFailed"); + + stopLocationUpdates(); + stopSelf(); + } + + @Override + public void onConnectionSuspended(int i) { + Log.e(TAG, "GoogleApiClient connection has been suspend"); + } +} diff --git a/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/LoopjHttpClient.java b/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/LoopjHttpClient.java new file mode 100644 index 0000000..d95f332 --- /dev/null +++ b/phoneClients/android-wp/app/src/main/java/com/websmithing/wp/gpstracker/LoopjHttpClient.java @@ -0,0 +1,48 @@ +package com.websmithing.wp.gpstracker; + +import android.util.Log; + +import com.loopj.android.http.AsyncHttpClient; +import com.loopj.android.http.AsyncHttpResponseHandler; +import com.loopj.android.http.RequestParams; + +public class LoopjHttpClient { + private static AsyncHttpClient client = new AsyncHttpClient(); + + public static void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) { + //client.getHttpClient().getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true); + client.get(url, params, responseHandler); + } + + public static void post(String url, RequestParams requestParams, AsyncHttpResponseHandler responseHandler) { + client.post(url, requestParams, responseHandler); + } + + //public static void debugLoopJ(String TAG, String methodName, byte[] response, Header[] headers, int statusCode, Throwable t) { + public static void debugLoopJ(String TAG, String methodName,String url, RequestParams requestParams, byte[] response, cz.msebera.android.httpclient.Header[] headers, int statusCode, Throwable t) { + + Log.d(TAG, client.getUrlWithQueryString(false, url, requestParams)); + + if (headers != null) { + Log.e(TAG, methodName); + Log.d(TAG, "Return Headers:"); + /* + for (Header h : headers) { + String _h = String.format(Locale.US, "%s : %s", h.getName(), h.getValue()); + Log.d(TAG, _h); + } + */ + + if (t != null) { + Log.d(TAG, "Throwable:" + t); + } + + Log.e(TAG, "StatusCode: " + statusCode); + + if (response != null) { + Log.d(TAG, "Response: " + new String(response)); + } + + } + } +} diff --git a/phoneClients/android-wp/app/src/main/res/drawable-hdpi/ic_launcher.png b/phoneClients/android-wp/app/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100755 index 0000000..eb79cdb --- /dev/null +++ b/phoneClients/android-wp/app/src/main/res/drawable-hdpi/ic_launcher.png Binary files differ diff --git a/phoneClients/android-wp/app/src/main/res/drawable-mdpi/ic_launcher.png b/phoneClients/android-wp/app/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100755 index 0000000..bcd3176 --- /dev/null +++ b/phoneClients/android-wp/app/src/main/res/drawable-mdpi/ic_launcher.png Binary files differ diff --git a/phoneClients/android-wp/app/src/main/res/drawable-xhdpi/ic_launcher.png b/phoneClients/android-wp/app/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100755 index 0000000..fbe7386 --- /dev/null +++ b/phoneClients/android-wp/app/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differ diff --git a/phoneClients/android-wp/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/phoneClients/android-wp/app/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100755 index 0000000..8270c3d --- /dev/null +++ b/phoneClients/android-wp/app/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differ diff --git a/phoneClients/android-wp/app/src/main/res/drawable-xxxhdpi/ic_launcher.png b/phoneClients/android-wp/app/src/main/res/drawable-xxxhdpi/ic_launcher.png new file mode 100755 index 0000000..2cbd539 --- /dev/null +++ b/phoneClients/android-wp/app/src/main/res/drawable-xxxhdpi/ic_launcher.png Binary files differ diff --git a/phoneClients/android-wp/app/src/main/res/drawable/green_tracking_button.xml b/phoneClients/android-wp/app/src/main/res/drawable/green_tracking_button.xml new file mode 100644 index 0000000..d97efe0 --- /dev/null +++ b/phoneClients/android-wp/app/src/main/res/drawable/green_tracking_button.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/phoneClients/android-wp/app/src/main/res/drawable/red_tracking_button.xml b/phoneClients/android-wp/app/src/main/res/drawable/red_tracking_button.xml new file mode 100644 index 0000000..0a5089d --- /dev/null +++ b/phoneClients/android-wp/app/src/main/res/drawable/red_tracking_button.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/phoneClients/android-wp/app/src/main/res/layout/activity_gpstracker.xml b/phoneClients/android-wp/app/src/main/res/layout/activity_gpstracker.xml new file mode 100644 index 0000000..d8d005e --- /dev/null +++ b/phoneClients/android-wp/app/src/main/res/layout/activity_gpstracker.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + +