/*
* Copyright (C) 2014 barter.li
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.barter.fragments;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.android.volley.Request.Method;
import com.facebook.LoggingBehavior;
import com.facebook.Session;
import com.facebook.Session.StatusCallback;
import com.facebook.SessionState;
import com.facebook.Settings;
import com.google.android.gms.analytics.HitBuilders.EventBuilder;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import li.barter.BarterLiApplication;
import li.barter.R;
import li.barter.activities.AbstractBarterLiActivity.AlertStyle;
import li.barter.activities.AuthActivity;
import li.barter.activities.PasswordResetActivity;
import li.barter.activities.SelectPreferredLocationActivity;
import li.barter.analytics.AnalyticsConstants.Actions;
import li.barter.analytics.AnalyticsConstants.Categories;
import li.barter.analytics.AnalyticsConstants.ParamKeys;
import li.barter.analytics.AnalyticsConstants.ParamValues;
import li.barter.analytics.AnalyticsConstants.Screens;
import li.barter.analytics.GoogleAnalyticsManager;
import li.barter.fragments.dialogs.AddSingleEditTextDialogFragment;
import li.barter.http.BlRequest;
import li.barter.http.HttpConstants;
import li.barter.http.HttpConstants.ApiEndpoints;
import li.barter.http.HttpConstants.RequestId;
import li.barter.http.IBlRequestContract;
import li.barter.http.ResponseInfo;
import li.barter.utils.AppConstants;
import li.barter.utils.AppConstants.FragmentTags;
import li.barter.utils.AppConstants.Keys;
import li.barter.utils.AppConstants.UserInfo;
import li.barter.utils.Logger;
import li.barter.utils.Utils;
@FragmentTransition(enterAnimation = R.anim.slide_in_from_right, exitAnimation = R.anim.zoom_out,
popEnterAnimation = R.anim.zoom_in,
popExitAnimation = R.anim.slide_out_to_right)
public class LoginFragment extends AbstractBarterLiFragment implements
OnClickListener, StatusCallback {
private static final String TAG = "LoginFragment";
/**
* Minimum length of the entered password
*/
private final int mMinPasswordLength = 8;
private Button mFacebookLoginButton;
private Button mGoogleLoginButton;
private Button mSubmitButton;
private EditText mEmailEditText;
private EditText mPasswordEditText;
private TextView mForgotPassword;
private AddSingleEditTextDialogFragment mAddSingleEditTextDialogFragment;
private String mEmailForPasswordChange;
@Override
public View onCreateView(final LayoutInflater inflater,
final ViewGroup container, final Bundle savedInstanceState) {
init(container, savedInstanceState);
final View view = inflater.inflate(R.layout.fragment_login, null);
mFacebookLoginButton = (Button) view
.findViewById(R.id.button_facebook_login);
mGoogleLoginButton = (Button) view
.findViewById(R.id.button_google_login);
mSubmitButton = (Button) view.findViewById(R.id.button_submit);
mEmailEditText = (EditText) view.findViewById(R.id.edit_text_email);
mPasswordEditText = (EditText) view
.findViewById(R.id.edit_text_password);
mForgotPassword = (TextView) view.findViewById(R.id.forgot_password);
mForgotPassword.setOnClickListener(this);
Settings.addLoggingBehavior(LoggingBehavior.INCLUDE_ACCESS_TOKENS);
Session session = Session.getActiveSession();
if (session == null) {
if (savedInstanceState != null) {
session = Session
.restoreSession(getActivity(), null, this, savedInstanceState);
}
if (session == null) {
session = new Session(getActivity());
}
Session.setActiveSession(session);
}
mFacebookLoginButton.setOnClickListener(this);
mGoogleLoginButton.setOnClickListener(this);
mSubmitButton.setOnClickListener(this);
return view;
}
@Override
public void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
final Session session = Session.getActiveSession();
Session.saveSession(session, outState);
}
@Override
protected Object getTaskTag() {
return hashCode();
}
@Override
public void onActivityResult(final int requestCode, final int resultCode,
final Intent data) {
if (requestCode == AppConstants.RequestCodes.RESET_PASSWORD && resultCode ==
ActionBarActivity.RESULT_OK) {
getActivity().setResult(ActionBarActivity.RESULT_OK, data);
getActivity().finish();
} else {
super.onActivityResult(requestCode, resultCode, data);
}
Session.getActiveSession()
.onActivityResult(getActivity(), requestCode, resultCode, data);
}
@Override
public void onClick(final View v) {
switch (v.getId()) {
case R.id.button_facebook_login: {
GoogleAnalyticsManager
.getInstance()
.sendEvent(new EventBuilder(Categories.CONVERSION, Actions.SIGN_IN_ATTEMPT)
.set(ParamKeys.TYPE, ParamValues.FACEBOOK));
final Session session = Session.getActiveSession();
if (!session.isOpened() && !session.isClosed()) {
session.openForRead(new Session.OpenRequest(this)
.setPermissions(Arrays
.asList(AppConstants
.FBPERMISSIONS))
.setCallback(this));
} else {
Session.openActiveSession(getActivity(), this, true, this);
}
break;
}
case R.id.button_google_login: {
GoogleAnalyticsManager
.getInstance()
.sendEvent(new EventBuilder(Categories.CONVERSION, Actions.SIGN_IN_ATTEMPT)
.set(ParamKeys.TYPE, ParamValues.GOOGLE));
((AuthActivity) getActivity()).getPlusManager().login();
break;
}
case R.id.button_submit: {
if (isInputValid()) {
GoogleAnalyticsManager
.getInstance()
.sendEvent(
new EventBuilder(Categories.CONVERSION, Actions.SIGN_IN_ATTEMPT)
.set(ParamKeys.TYPE, ParamValues.EMAIL)
);
login(mEmailEditText.getText().toString(), mPasswordEditText
.getText().toString());
}
break;
}
case R.id.forgot_password: {
showForgotPasswordDialog();
}
}
}
/**
* Show the dialog for the user to enter his email address
*/
private void showForgotPasswordDialog() {
mAddSingleEditTextDialogFragment = new AddSingleEditTextDialogFragment();
mAddSingleEditTextDialogFragment
.show(AlertDialog.THEME_HOLO_LIGHT, 0, R.string.forgot_password, R.string.submit,
R.string.cancel, 0, R.string.email_label, getFragmentManager(), true,
FragmentTags.DIALOG_FORGOT_PASSWORD);
}
@Override
public boolean willHandleDialog(final DialogInterface dialog) {
if ((mAddSingleEditTextDialogFragment != null)
&& mAddSingleEditTextDialogFragment.getDialog()
.equals(dialog)) {
return true;
}
return false;
}
@Override
public void onDialogClick(final DialogInterface dialog, final int which) {
if ((mAddSingleEditTextDialogFragment != null)
&& mAddSingleEditTextDialogFragment.getDialog()
.equals(dialog)) {
if (which == DialogInterface.BUTTON_POSITIVE) {
callForgotPassword(mAddSingleEditTextDialogFragment.getName());
}
}
}
/**
* Call the password_reset Api
*
* @param email The entered email
*/
private void callForgotPassword(String email) {
final BlRequest request = new BlRequest(Method.GET, HttpConstants.getApiBaseUrl()
+ ApiEndpoints.PASSWORD_RESET, null, mVolleyCallbacks);
request.setRequestId(RequestId.REQUEST_RESET_TOKEN);
mEmailForPasswordChange = email;
final Map<String, String> params = new HashMap<String, String>(1);
params.put(HttpConstants.EMAIL, email);
request.setParams(params);
addRequestToQueue(request, true, 0, true);
}
/**
* Call the login Api
*
* @param email The entered email
* @param password The entered password
*/
private void login(final String email, final String password) {
final JSONObject requestObject = new JSONObject();
try {
requestObject.put(HttpConstants.PROVIDER, AppConstants.MANUAL);
requestObject.put(HttpConstants.EMAIL, email);
requestObject.put(HttpConstants.PASSWORD, password);
requestObject.put(HttpConstants.DEVICE_ID, UserInfo.INSTANCE
.getDeviceId());
final BlRequest request = new BlRequest(Method.POST, HttpConstants.getApiBaseUrl()
+ ApiEndpoints.CREATE_USER, requestObject.toString(), mVolleyCallbacks);
request.setRequestId(RequestId.CREATE_USER);
addRequestToQueue(request, true, 0, true);
} catch (final JSONException e) {
// Should never happen
Logger.e(TAG, e, "Error building create user json");
}
}
/**
* Call the login Api
*
* @param token oath token we get from providers
* @param provider facebook or google in our case
*/
private void loginWithProvider(final String token, final String provider) {
final JSONObject requestObject = new JSONObject();
try {
requestObject.put(HttpConstants.PROVIDER, provider);
requestObject.put(HttpConstants.ACCESS_TOKEN, token);
requestObject.put(HttpConstants.DEVICE_ID, UserInfo.INSTANCE
.getDeviceId());
final BlRequest request = new BlRequest(Method.POST, HttpConstants.getApiBaseUrl()
+ ApiEndpoints.CREATE_USER, requestObject.toString(), mVolleyCallbacks);
request.setRequestId(RequestId.CREATE_USER);
addRequestToQueue(request, true, 0, true);
} catch (final JSONException e) {
// Should never happen
Logger.e(TAG, e, "Error building create user json");
}
}
/**
* Validates the text fields for creating a user. Automatically sets the error messages for the
* text fields
*
* @return <code>true</code> If the input is valid, <code>false</code> otherwise
*/
private boolean isInputValid() {
final String email = mEmailEditText.getText().toString();
boolean isValid = !TextUtils.isEmpty(email);
if (!isValid) {
mEmailEditText.setError(getString(R.string.error_enter_email));
} else {
//Using a regex for email comparison is pointless
isValid &= email.contains("@");
if (!isValid) {
mEmailEditText.setError(getString(R.string.error_invalid_email));
}
}
if (isValid) {
final String password = mPasswordEditText.getText().toString();
isValid &= !TextUtils.isEmpty(password);
if (!isValid) {
mPasswordEditText
.setError(getString(R.string.error_enter_password));
} else {
isValid &= (password.length() >= mMinPasswordLength);
if (!isValid) {
mPasswordEditText
.setError(getString(R.string.error_password_minimum_length,
mMinPasswordLength));
}
}
}
return isValid;
}
@Override
public void onSuccess(final int requestId,
final IBlRequestContract request,
final ResponseInfo response) {
if (requestId == RequestId.CREATE_USER) {
final Bundle userInfo = response.responseBundle;
Utils.updateUserInfoFromBundle(userInfo, true);
BarterLiApplication.startChatService();
final String locationId = userInfo
.getString(HttpConstants.LOCATION);
Intent returnIntent = getDefaultOnwardIntent();
if (TextUtils.isEmpty(locationId)) {
returnIntent = new Intent(getActivity(), SelectPreferredLocationActivity.class);
returnIntent.putExtra(Keys.ONWARD_INTENT, getDefaultOnwardIntent());
}
final Intent data = new Intent();
data.putExtra(Keys.ONWARD_INTENT, returnIntent);
getActivity().setResult(Activity.RESULT_OK, returnIntent);
getActivity().finish();
} else if (requestId == RequestId.REQUEST_RESET_TOKEN) {
final Intent resetPasswordIntent = new Intent(getActivity(),
PasswordResetActivity.class);
resetPasswordIntent.putExtra(Keys.EMAIL, mEmailForPasswordChange);
if(getArguments() != null) {
resetPasswordIntent.putExtras(getArguments());
}
startActivityForResult(resetPasswordIntent, AppConstants.RequestCodes.RESET_PASSWORD);
}
}
@Override
public void onBadRequestError(final int requestId,
final IBlRequestContract request, final int errorCode,
final String errorMessage, final Bundle errorResponseBundle) {
if (requestId == RequestId.CREATE_USER) {
showCrouton(errorMessage, AlertStyle.ERROR);
}
}
@Override
public void call(final Session session, final SessionState state,
final Exception exception) {
// TODO session returns the user_token
Logger.e(TAG, session.getAccessToken() + " token" + state.toString());
//exception.printStackTrace();
if (!session.getAccessToken().equals("")) {
loginWithProvider(session.getAccessToken(), AppConstants.FACEBOOK);
}
}
/**
* Method called when google login completes
*/
public void onGoogleLogin() {
final String googleAccessToken = ((AuthActivity) getActivity())
.getPlusManager().getAccessToken();
Logger.v(TAG, "Google Access Token: %s", googleAccessToken);
if (!TextUtils.isEmpty(googleAccessToken)) {
loginWithProvider(googleAccessToken, AppConstants.GOOGLE);
}
}
/**
* Method called when there is an error while google login
*
* @param error The {@link Exception} that occured
*/
public void onGoogleLoginError(final Exception error) {
showCrouton(R.string.error_unable_to_login, AlertStyle.ERROR);
}
/**
* Method called when google logout happens
*/
public void onGoogleLogout() {
}
@Override
protected String getAnalyticsScreenName() {
return Screens.LOGIN;
}
/**
* If an onward intent has been specified, provides that.
* <p/>
* Otherwise, just creates a default intent to open the user's profile
*/
private Intent getDefaultOnwardIntent() {
final Bundle extras = getArguments();
if (extras != null && extras.containsKey(Keys.ONWARD_INTENT)) {
return extras.getParcelable(Keys.ONWARD_INTENT);
} else {
return null;
}
}
}