@@ -0,0 +1,58 @@
package soilsmart.soilsmartapp;

import android.content.Context;
import android.content.SharedPreferences;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.ArrayList;

/**
* SoilSmartApp
* Created by Ricardo Morones on 2/27/16.
*/
public class UserLocalStore {
final static public String SP_NAME = "userDetails";
final SharedPreferences userLocalDatabase;
final Gson gson;

public UserLocalStore(Context context) {
userLocalDatabase = context.getSharedPreferences(SP_NAME, 0);
gson = new Gson();
}

public void storeUserData(User user) {
SharedPreferences.Editor spEditor = userLocalDatabase.edit();
spEditor.putString("email", user.getEmail());
spEditor.putString("password", user.getPasswordHash());
spEditor.putString("nodes", gson.toJson(user.getNodes()));
spEditor.apply();
}

public User getLoggedInUser() {
final String email = userLocalDatabase.getString("email", "");
final String password = userLocalDatabase.getString("password", "");
final String nodesJson = userLocalDatabase.getString("nodes", "");
final Type type = new TypeToken<ArrayList<SoilSmartNode>>() {}.getType();
ArrayList<SoilSmartNode> nodes = gson.fromJson(nodesJson, type);
return new User(email, password, nodes);
}

public void setUserLoggedIn(boolean loggedIn) {
SharedPreferences.Editor spEditor = userLocalDatabase.edit();
spEditor.putBoolean("loggedIn", loggedIn);
spEditor.apply();
}

public boolean getUserLoggedIn() {
return userLocalDatabase.getBoolean("loggedIn", false);
}

public void clearUserData() {
SharedPreferences.Editor spEditor = userLocalDatabase.edit();
spEditor.clear();
spEditor.apply();
}
}
@@ -0,0 +1,390 @@
package soilsmart.soilsmartapp.views;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.app.LoaderManager.LoaderCallbacks;

import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;

import android.os.Build;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

import soilsmart.soilsmartapp.R;
import soilsmart.soilsmartapp.SoilSmartService;
import soilsmart.soilsmartapp.User;
import soilsmart.soilsmartapp.UserLocalStore;

import static android.Manifest.permission.READ_CONTACTS;

/**
* A login screen that offers login via email/password.
*/
public class LoginActivity extends AppCompatActivity implements LoaderCallbacks<Cursor> {

/**
* Id to identity READ_CONTACTS permission request.
*/
private static final int REQUEST_READ_CONTACTS = 0;

/**
* Keep track of the login task to ensure we can cancel it if requested.
*/
private UserLoginTask mAuthTask = null;
private UserLocalStore userLocalStore;

// UI references.
private AutoCompleteTextView mEmailView;
private EditText mPasswordView;
private View mProgressView;
private View mLoginFormView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// Set up the login form.
mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
mEmailView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event) {
if (isEmailValid(v.getText().toString())) {
mPasswordView.requestFocus();
return true;
} else {
mEmailView.setError(getString(R.string.error_invalid_email));
}
return false;
}
});
populateAutoComplete();

mPasswordView = (EditText) findViewById(R.id.password);
mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(final TextView textView, final int id, final KeyEvent keyEvent) {
if (id == R.id.login || id == EditorInfo.IME_NULL) {
attemptLogin();
return true;
}
return false;
}
});

final Button mEmailSignInButton = (Button) findViewById(R.id.login_button);
mEmailSignInButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
attemptLogin();
}
});

final TextView register = (TextView) findViewById(R.id.create_account_msg);
register.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
launchActivity(RegisterActivity.class);
finish();
}
});

mLoginFormView = findViewById(R.id.login_form);
mProgressView = findViewById(R.id.login_progress);
userLocalStore = new UserLocalStore(this);
}

@Override
protected void onStart() {
super.onStart();
if (userLocalStore.getUserLoggedIn()) {
final User user = userLocalStore.getLoggedInUser();
Toast.makeText(this,
"Logged in as: " + user.getEmail(),
Toast.LENGTH_LONG).show();
launchActivity(NodeLocationsActivity.class);
finish();
}
}

private void populateAutoComplete() {
if (!mayRequestContacts()) {
return;
}

getLoaderManager().initLoader(0, null, this);
}

private boolean mayRequestContacts() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
return true;
}
if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
Snackbar.make(mEmailView, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
.setAction(android.R.string.ok, new View.OnClickListener() {
@Override
@TargetApi(Build.VERSION_CODES.M)
public void onClick(View v) {
requestPermissions(new String[] { READ_CONTACTS }, REQUEST_READ_CONTACTS);
}
});
} else {
requestPermissions(new String[] { READ_CONTACTS }, REQUEST_READ_CONTACTS);
}
return false;
}

/**
* Callback received when a permissions request has been completed.
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == REQUEST_READ_CONTACTS) {
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
populateAutoComplete();
}
}
}

/**
* Attempts to sign in or register the account specified by the login form.
* If there are form errors (invalid email, missing fields, etc.), the
* errors are presented and no actual login attempt is made.
*/
private void attemptLogin() {
if (mAuthTask != null) {
return;
}

// Reset errors.
mEmailView.setError(null);
mPasswordView.setError(null);

// Store values at the time of the login attempt.
final String email = mEmailView.getText().toString();
final String password = mPasswordView.getText().toString();

boolean cancel = false;
View focusView = null;

// Check for a valid email address.
if (TextUtils.isEmpty(email)) {
mEmailView.setError(getString(R.string.error_field_required));
focusView = mEmailView;
cancel = true;
} else if (!isEmailValid(email)) {
mEmailView.setError(getString(R.string.error_invalid_email));
focusView = mEmailView;
cancel = true;
}

// Check for a valid password, if the user entered one.
if (TextUtils.isEmpty(password)) {
mPasswordView.setError(getString(R.string.error_field_required));
focusView = mPasswordView;
cancel = true;
}

if (!isPasswordValid(password) && !cancel) {
showProgress(true);
mPasswordView.setError(getString(R.string.error_incorrect_password));
mEmailView.setError(getString(R.string.error_incorrect_password));
mEmailView.requestFocus();
showProgress(false);
return;
}

if (cancel) {
// There was an error; don't attempt login and focus the first
// form field with an error.
focusView.requestFocus();
} else {
// Show a progress spinner, and kick off a background task to
// perform the user login attempt.
showProgress(true);

mAuthTask = new UserLoginTask(new User(email, password));
mAuthTask.execute((Void) null);
}
}

private boolean isEmailValid(String email) {
return email.matches(getString(R.string.email_regex));
}

private boolean isPasswordValid(String password) {
return password.matches(getString(R.string.password_regex));
}

/**
* Shows the progress UI and hides the login form.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
private void showProgress(final boolean show) {
// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
// for very easy animations. If available, use these APIs to fade-in
// the progress spinner.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);

mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
mLoginFormView.animate().setDuration(shortAnimTime).alpha(
show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
});

mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mProgressView.animate().setDuration(shortAnimTime).alpha(
show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
}
});
} else {
// The ViewPropertyAnimator APIs are not available, so simply show
// and hide the relevant UI components.
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
}

@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return new CursorLoader(this,
// Retrieve data rows for the device user's 'profile' contact.
Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI,
ContactsContract.Contacts.Data.CONTENT_DIRECTORY), ProfileQuery.PROJECTION,

// Select only email addresses.
ContactsContract.Contacts.Data.MIMETYPE +
" = ?", new String[]{ContactsContract.CommonDataKinds.Email
.CONTENT_ITEM_TYPE},

// Show primary email addresses first. Note that there won't be
// a primary email address if the user hasn't specified one.
ContactsContract.Contacts.Data.IS_PRIMARY + " DESC");
}

@Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
List<String> emails = new ArrayList<>();
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
emails.add(cursor.getString(ProfileQuery.ADDRESS));
cursor.moveToNext();
}

addEmailsToAutoComplete(emails);
}

@Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {

}

private void addEmailsToAutoComplete(List<String> emailAddressCollection) {
//Create adapter to tell the AutoCompleteTextView what to show in its dropdown list.
ArrayAdapter<String> adapter =
new ArrayAdapter<>(LoginActivity.this,
android.R.layout.simple_dropdown_item_1line, emailAddressCollection);

mEmailView.setAdapter(adapter);
}


private interface ProfileQuery {
String[] PROJECTION = {
ContactsContract.CommonDataKinds.Email.ADDRESS,
ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
};

int ADDRESS = 0;
int IS_PRIMARY = 1;
}

private void launchActivity(Class clazz) {
startActivity(new Intent(this, clazz));
}

/**
* Represents an asynchronous login/registration task used to authenticate
* the user.
*/
public class UserLoginTask extends AsyncTask<Void, Void, User> {

private final User user;

UserLoginTask(User user) {
this.user = user;
}

@Override
protected User doInBackground(Void... params) {
// TODO: attempt authentication against a network service.
final SoilSmartService soilSmartService = SoilSmartService.getInstance();
try {
if (soilSmartService.authenticate(user)) {
return user;
}
} catch (Exception e) {
return null;
}
return null;
}

@Override
protected void onPostExecute(final User user) {
mAuthTask = null;
showProgress(false);

if (user != null) {
userLocalStore.storeUserData(user);
userLocalStore.setUserLoggedIn(true);
launchActivity(NodeLocationsActivity.class);
finish();
} else {
mPasswordView.setError(getString(R.string.error_incorrect_password));
mEmailView.setError(getString(R.string.error_incorrect_password));
mEmailView.requestFocus();
}
}

@Override
protected void onCancelled() {
mAuthTask = null;
showProgress(false);
}
}
}

@@ -0,0 +1,126 @@
package soilsmart.soilsmartapp.views;

<<<<<<< HEAD:SoilSmartApp/app/src/main/java/soilsmart/soilsmartapp/views/NodeLocationsActivity.java
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
=======
import android.content.ComponentName;
import android.content.Intent;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;
>>>>>>> Commit/push before merge from master:SoilSmartApp/app/src/main/java/soilsmart/soilsmartapp/NodeLocationsActivity.java

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

<<<<<<< HEAD:SoilSmartApp/app/src/main/java/soilsmart/soilsmartapp/views/NodeLocationsActivity.java
import soilsmart.soilsmartapp.R;
import soilsmart.soilsmartapp.UserLocalStore;

/**
*
*/
public class NodeLocationsActivity extends AppCompatActivity implements OnMapReadyCallback {
=======
import java.sql.Struct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class NodeLocationsActivity extends FragmentActivity implements OnMapReadyCallback {
>>>>>>> Commit/push before merge from master:SoilSmartApp/app/src/main/java/soilsmart/soilsmartapp/NodeLocationsActivity.java

private GoogleMap mMap;
private UserLocalStore userLocalStore;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_node_locations);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
userLocalStore = new UserLocalStore(this);
}


/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;

// Add a marker in Sydney and move the camera
<<<<<<< HEAD:SoilSmartApp/app/src/main/java/soilsmart/soilsmartapp/views/NodeLocationsActivity.java
final LatLng sydney = new LatLng(-34, 151);
mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
=======
LatLng sydney = new LatLng(-34, 151);
mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
mMap.addMarker(new MarkerOptions().position(sydney).icon(BitmapDescriptorFactory.fromResource(R.drawable.tree_drop_pin)));
>>>>>>> Commit/push before merge from master:SoilSmartApp/app/src/main/java/soilsmart/soilsmartapp/NodeLocationsActivity.java
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));

// Setup ClickListener to start new activity for individual sensor module data page
mMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
@Override
public void onInfoWindowClick(Marker marker) {
Intent newIntent = new Intent(getApplicationContext(), test.class);
startActivity(newIntent);

}
});

// Implement custom InfoWindowAdapter for popup after marker click
mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
@Override
public View getInfoWindow(Marker marker) {
return null;
}

@Override
public View getInfoContents(Marker marker) {
View v = getLayoutInflater().inflate(R.layout.custom_info_window,null);
LatLng latLng = marker.getPosition();

TextView tvLatLng = (TextView) v.findViewById(R.id.tv_lat_lng);
TextView tvID = (TextView) v.findViewById(R.id.tv_ID);
tvLatLng.setText("(Lat,Long): ("+latLng.latitude+","+latLng.longitude+")");

return v;
}
});
}

<<<<<<< HEAD:SoilSmartApp/app/src/main/java/soilsmart/soilsmartapp/views/NodeLocationsActivity.java
@Override
protected void onStart() {
super.onStart();
if (!userLocalStore.getUserLoggedIn()) {
startActivity(new Intent(this, LoginActivity.class));
finish();
}
}
=======

>>>>>>> Commit/push before merge from master:SoilSmartApp/app/src/main/java/soilsmart/soilsmartapp/NodeLocationsActivity.java
}
@@ -0,0 +1,282 @@
package soilsmart.soilsmartapp.views;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import soilsmart.soilsmartapp.R;
import soilsmart.soilsmartapp.SoilSmartService;
import soilsmart.soilsmartapp.User;
import soilsmart.soilsmartapp.views.LoginActivity;

public class RegisterActivity extends AppCompatActivity {

UserRegisterTask mAuthTask = null;

AutoCompleteTextView mEmailView;
EditText mPasswordView;
EditText mProductkeyView;
private View mProgressView;
private View mRegisterFormView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);

final Button blogin = (Button) findViewById(R.id.register_button);
final Button breturn = (Button) findViewById(R.id.back_to_login_button);
mEmailView = (AutoCompleteTextView) findViewById(R.id.email);
mPasswordView = (EditText) findViewById(R.id.password);
mProductkeyView = (EditText) findViewById(R.id.product_key);

blogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
attemptRegister();
}
});

breturn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
launchActivity(LoginActivity.class);
finish();
}
});

mProgressView = findViewById(R.id.login_progress);
mRegisterFormView = findViewById(R.id.registration_form);

mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(final TextView v, final int id, final KeyEvent keyEvent) {
if (isPasswordValid(v.getText().toString())) {
mProductkeyView.requestFocus();
return true;
} else {
mPasswordView.setError(getString(R.string.error_invalid_password));
}
return false;
}
});

mEmailView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event) {
if (isEmailValid(v.getText().toString())) {
mPasswordView.requestFocus();
return true;
} else {
mEmailView.setError(getString(R.string.error_invalid_email));
}
return false;
}
});

mProductkeyView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(final TextView v, final int id, final KeyEvent keyEvent) {
if (isValidKey(v.getText().toString())) {
blogin.requestFocus();
return true;
}
return false;
}
});
}

private boolean isEmailValid(String email) {
return email.matches(getString(R.string.email_regex));
}

private boolean isPasswordValid(String password) {
return password.matches(getString(R.string.password_regex));
}

private boolean isValidKey(String key) {
return key.length() > 10;
}

private void attemptRegister() {
if (mAuthTask != null)
return;

// Reset errors.
mEmailView.setError(null);
mPasswordView.setError(null);

// Store values at the time of the registration attempt.
final String email = mEmailView.getText().toString();
final String password = mPasswordView.getText().toString();
final String productKey = mProductkeyView.getText().toString();

boolean cancel = false;
View focusView = null;

// Check for a valid email address.
if (TextUtils.isEmpty(email)) {
mEmailView.setError(getString(R.string.error_field_required));
focusView = mEmailView;
cancel = true;
} else if (!isEmailValid(email)) {
mEmailView.setError(getString(R.string.error_invalid_email));
focusView = mEmailView;
cancel = true;
}

// Check for a valid password, if the user entered one.
if (!isPasswordValid(password)) {
mPasswordView.setError(getString(R.string.error_invalid_password));
focusView = mPasswordView;
cancel = true;
}

if (TextUtils.isEmpty(password)) {
mPasswordView.setError(getString(R.string.error_field_required));
focusView = mPasswordView;
cancel = true;
}

// Check for a valid product key, if the user entered one.
if (TextUtils.isEmpty(productKey)) {
mProductkeyView.setError(getString(R.string.error_field_required));
focusView = mProductkeyView;
cancel = true;
}

if (!isValidKey(productKey)) {
showMessage(null);
cancel = true;
}

if (cancel) {
// There was an error; don't attempt login and focus the first
// form field with an error.
if (focusView != null)
focusView.requestFocus();
} else {
// Show a progress spinner, and kick off a background task to
// perform the user login attempt.
showProgress(true);

mAuthTask = new UserRegisterTask(new User(email, password), productKey);
mAuthTask.execute((Void) null);
}
}

private void launchActivity(Class clazz) {
startActivity(new Intent(this, clazz));
}

/**
* Shows the progress UI and hides the login form.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
private void showProgress(final boolean show) {
// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
// for very easy animations. If available, use these APIs to fade-in
// the progress spinner.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);

mRegisterFormView.setVisibility(show ? View.GONE : View.VISIBLE);
mRegisterFormView.animate().setDuration(shortAnimTime).alpha(
show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mRegisterFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
});

mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mProgressView.animate().setDuration(shortAnimTime).alpha(
show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
}
});
} else {
// The ViewPropertyAnimator APIs are not available, so simply show
// and hide the relevant UI components.
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mRegisterFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
}

void showMessage(Object obj) {
if (obj != null)
Toast.makeText(this,
R.string.register_success,
Toast.LENGTH_LONG).show();
else
Snackbar.make(mRegisterFormView,
getString(R.string.registration_failed),
Snackbar.LENGTH_LONG).show();
}

/**
* Represents an asynchronous registration task used to authenticate
* the user.
*/
public class UserRegisterTask extends AsyncTask<Void, Void, User> {

private final User user;
private final String key;

UserRegisterTask(User user, String key) {
this.user = user;
this.key = key;
}

@Override
protected User doInBackground(Void... params) {
// TODO: attempt authentication against a network service.
final SoilSmartService soilSmartService = SoilSmartService.getInstance();
try {
if (soilSmartService.registerUser(user, key)) {
return user;
}
} catch (Exception e) {
return null;
}
return null;
}

@Override
protected void onPostExecute(final User user) {
mAuthTask = null;
showProgress(false);

if (user != null) {
showMessage(user);
launchActivity(LoginActivity.class);
finish();
} else {
showMessage(null);
}
}

@Override
protected void onCancelled() {
mAuthTask = null;
showProgress(false);
}
}

}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,109 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:fitsSystemWindows="true"
android:background="#cdc5bf"
tools:context=".views.LoginActivity">

<!-- Login progress -->
<ProgressBar
android:id="@+id/login_progress"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:visibility="gone" />

<RelativeLayout
android:id="@+id/soilsmart_logo_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.4">

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/logo_description"
android:id="@+id/soilsmart_logo"
android:src="@drawable/soilsmart_logo"
android:layout_centerHorizontal="true" />

</RelativeLayout>

<RelativeLayout
android:id="@+id/login_form"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.6">

<android.support.design.widget.TextInputLayout
android:id="@+id/email_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<AutoCompleteTextView
android:id="@+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_email"
android:inputType="textEmailAddress"
android:maxLines="1"
android:singleLine="true"
android:textColorHint="#00c71b"
android:textColorHighlight="#9aeffd" />

</android.support.design.widget.TextInputLayout>

<android.support.design.widget.TextInputLayout
android:id="@+id/password_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/email_container">

<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_password"
android:imeActionId="@+id/login"
android:imeActionLabel="@string/action_sign_in_short"
android:imeOptions="actionUnspecified"
android:inputType="textPassword"
android:maxLines="1"
android:singleLine="true"
android:textColorHighlight="#9aeffd"
android:textColorHint="#00c71b" />

</android.support.design.widget.TextInputLayout>

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/login"
android:id="@+id/login_button"
android:layout_below="@+id/password_container" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:textSize="12sp"
android:text="@string/create_account_msg"
android:contextClickable="false"
android:textColor="#4577e4"
android:textStyle="italic"
android:id="@+id/create_account_msg"
android:layout_below="@+id/login_button"
android:layout_centerHorizontal="true"
android:textAlignment="center"/>

</RelativeLayout>

</LinearLayout>
@@ -1,8 +1,9 @@
<fragment android:id="@+id/map"
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="soilsmart.soilsmartapp.NodeLocationsActivity" />
tools:context=".views.NodeLocationsActivity" />
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:fitsSystemWindows="true"
android:background="#cdc5bf"
tools:context=".views.RegisterActivity">

<!-- Login progress -->
<ProgressBar
android:id="@+id/login_progress"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:visibility="gone" />

<RelativeLayout
android:id="@+id/soilsmart_logo_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.2">

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/logo_description"
android:id="@+id/soilsmart_logo"
android:src="@drawable/soilsmart_logo"
android:layout_centerHorizontal="true" />

</RelativeLayout>

<RelativeLayout
android:id="@+id/registration_form"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.8">

<android.support.design.widget.TextInputLayout
android:id="@+id/email_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<AutoCompleteTextView
android:id="@+id/email"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_email"
android:inputType="textEmailAddress"
android:maxLines="1"
android:singleLine="true"
android:textColorHint="#00c71b"
android:textColorHighlight="#9aeffd" />

</android.support.design.widget.TextInputLayout>

<android.support.design.widget.TextInputLayout
android:id="@+id/password_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/email_container">

<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_password"
android:inputType="textPassword"
android:maxLines="1"
android:singleLine="true"
android:textColorHighlight="#9aeffd"
android:textColorHint="#00c71b" />

</android.support.design.widget.TextInputLayout>


<android.support.design.widget.TextInputLayout
android:id="@+id/product_key_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/password_container">

<EditText
android:id="@+id/product_key"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_product_key"
android:inputType="textVisiblePassword"
android:maxLines="1"
android:singleLine="true"
android:textColorHint="#00c71b"
android:textColorHighlight="#9aeffd" />

</android.support.design.widget.TextInputLayout>

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/register"
android:id="@+id/register_button"
android:layout_below="@+id/product_key_container" />

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/back_to_login"
android:id="@+id/back_to_login_button"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />

</RelativeLayout>

</LinearLayout>
@@ -1,5 +1,19 @@
<resources>>

<<<<<<< HEAD
<<<<<<< HEAD
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="windowActionBar">true</item>
</style>

=======
>>>>>>> Commit/push before merge from master
=======
>>>>>>> d25de068e290cac8931e0938380c1311bbce5cbb
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="colorPrimary">#00CC00</color>
<color name="colorPrimaryDark">#008000</color>
<color name="colorAccent">#C9A47F</color>
</resources>
@@ -1,7 +1,38 @@
<resources>
<string name="app_name">SoilSmartApp</string>
<string name="company_name">SoilSmart</string>

<!-- Strings related to login -->
<string name="logo_description">SoilSmart</string>
<string name="login">Sign In</string>
<string name="create_account_msg">Don\'t have an account?\nRegister here.</string>
<string name="prompt_email">Email</string>
<string name="prompt_password">Password</string>
<string name="action_sign_in">Sign in or register</string>
<string name="action_sign_in_short">Sign in</string>
<string name="error_invalid_email">This email address is invalid</string>
<string name="error_invalid_password">This password must be at least 7 characters long and contain at least one of each of the following:\n* a–z\n* A–Z\n* 0–9</string>
<string name="error_incorrect_password">Invalid credentials</string>
<string name="error_field_required">This field is required</string>
<string name="permission_rationale">"Contacts permissions are needed for providing email completions."</string>

<!-- Strings related to register -->
<string name="register">Register</string>
<string name="back_to_login">Back to Login</string>
<string name="prompt_product_key">Product Key (Included in purchase)</string>

<!-- Strings related to Locations -->
<string name="title_activity_node_locations">Locations</string>
<string name="google_maps_key">AIzaSyD_kQpy75hRLZLDl7Td_gfKIXkhKfjbhSo</string>
<string name="google_app_id">752907188352</string>

<!-- Miscellaneous -->
<string name="password_regex">^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{7,}$</string>
<string name="email_regex">^\\w+([-+.\']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$</string>
<string name="register_success">Registration Successful!</string>
<string name="registration_failed">Registration failed.\nDid you use the right product key?\nAlready have an account? Just login and add your product key through our \'Settings\' tab.</string>


<string name="title_activity_test">test</string>

</resources>
@@ -1,11 +1,12 @@
<resources>

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="windowActionBar">true</item>
</style>

<style name="AppTheme.NoActionBar">
@@ -15,6 +16,20 @@

<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />

<<<<<<< HEAD
<style name="AppTheme.PopupOverlay" parent="AppTheme">

</style>

<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>

<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />

=======
>>>>>>> d25de068e290cac8931e0938380c1311bbce5cbb
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

</resources>