/*
* Catroid: An on-device visual programming system for Android devices
* Copyright (C) 2010-2016 The Catrobat Team
* (<http://developer.catrobat.org/credits>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* An additional term exception under section 7 of the GNU Affero
* General Public License, version 3, is available at
* http://developer.catrobat.org/license_additional_term
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.catrobat.catroid.ui.dialogs;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import com.facebook.AccessToken;
import com.facebook.login.LoginManager;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.auth.api.signin.GoogleSignInResult;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import org.catrobat.catroid.ProjectManager;
import org.catrobat.catroid.R;
import org.catrobat.catroid.common.Constants;
import org.catrobat.catroid.transfers.CheckEmailAvailableTask;
import org.catrobat.catroid.transfers.CheckOAuthTokenTask;
import org.catrobat.catroid.transfers.FacebookExchangeTokenTask;
import org.catrobat.catroid.transfers.FacebookLogInTask;
import org.catrobat.catroid.transfers.GetFacebookUserInfoTask;
import org.catrobat.catroid.transfers.GoogleExchangeCodeTask;
import org.catrobat.catroid.transfers.GoogleLogInTask;
import org.catrobat.catroid.ui.MainMenuActivity;
import org.catrobat.catroid.ui.ProjectActivity;
import org.catrobat.catroid.utils.ToastUtil;
import org.catrobat.catroid.utils.UtilDeviceInfo;
import org.catrobat.catroid.utils.Utils;
import org.catrobat.catroid.web.ServerCalls;
import java.util.Arrays;
import java.util.Collection;
public class SignInDialog extends DialogFragment implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
GoogleExchangeCodeTask.OnFacebookExchangeCodeCompleteListener,
GoogleLogInTask.OnGoogleServerLogInCompleteListener,
FacebookExchangeTokenTask.OnFacebookExchangeTokenCompleteListener,
FacebookLogInTask.OnFacebookLogInCompleteListener,
CheckOAuthTokenTask.OnCheckOAuthTokenCompleteListener,
CheckEmailAvailableTask.OnCheckEmailAvailableCompleteListener,
GetFacebookUserInfoTask.OnGetFacebookUserInfoTaskCompleteListener {
private static final String TAG = SignInDialog.class.getSimpleName();
public static final String DIALOG_FRAGMENT_TAG = "dialog_sign_in";
private static final int GPLUS_REQUEST_CODE_SIGN_IN = 0;
private static final Integer RESULT_CODE_AUTH_CODE = 1;
private static final String FACEBOOK_PROFILE_PERMISSION = "public_profile";
private static final String FACEBOOK_EMAIL_PERMISSION = "email";
private static final java.lang.String GOOGLE_PLUS_CATROWEB_SERVER_CLIENT_ID = "427226922034-r016ige5kb30q9vflqbt1h0i3arng8u1.apps.googleusercontent.com";
private ProgressDialog connectionProgressDialog;
private GoogleApiClient googleApiClient;
private boolean shouldResolveErrors = false;
private boolean isResolving = false;
private boolean triggerGPlusLogin = false;
@Override
public Dialog onCreateDialog(Bundle bundle) {
if (getActivity() instanceof MainMenuActivity) {
((MainMenuActivity) getActivity()).setSignInDialog(this);
} else if (getActivity() instanceof ProjectActivity) {
((ProjectActivity) getActivity()).setSignInDialog(this);
}
initializeGooglePlus();
View rootView = LayoutInflater.from(getActivity()).inflate(R.layout.dialog_sign_in, null);
final Button loginButton = (Button) rootView.findViewById(R.id.dialog_sign_in_login);
final Button registerButton = (Button) rootView.findViewById(R.id.dialog_sign_in_register);
final Button facebookLoginButton = (Button) rootView.findViewById(R.id.dialog_sign_in_facebook_login_button);
Button gplusLoginButton = (Button) rootView.findViewById(R.id.dialog_sign_in_gplus_login_button);
TextView termsOfUseLinkTextView = (TextView) rootView.findViewById(R.id.register_terms_link);
facebookLoginButton.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int width = facebookLoginButton.getWidth();
if (width > 0) {
loginButton.getLayoutParams().width = width;
registerButton.getLayoutParams().width = width;
facebookLoginButton.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});
String termsOfUseUrl = getString(R.string.about_link_template, Constants.CATROBAT_TERMS_OF_USE_URL,
getString(R.string.register_pocketcode_terms_of_use_text));
termsOfUseLinkTextView.setMovementMethod(LinkMovementMethod.getInstance());
termsOfUseLinkTextView.setText(Html.fromHtml(termsOfUseUrl));
final AlertDialog signInDialog = new AlertDialog.Builder(getActivity()).setView(rootView)
.setTitle(R.string.sign_in_dialog_title).create();
signInDialog.setCanceledOnTouchOutside(true);
signInDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
loginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
handleLoginButtonClick();
}
});
registerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
handleRegisterButtonClick();
}
});
LoginManager.getInstance().setLoginBehavior(ServerCalls.getInstance().getLoginBehavior());
facebookLoginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (Utils.isNetworkAvailable(getActivity())) {
Collection<String> permissions = Arrays.asList(FACEBOOK_PROFILE_PERMISSION, FACEBOOK_EMAIL_PERMISSION);
LoginManager.getInstance().logInWithReadPermissions(getActivity(), permissions);
} else {
Utils.isNetworkAvailable(getActivity(), true);
}
}
});
gplusLoginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (Utils.isNetworkAvailable(getActivity())) {
handleGooglePlusLoginButtonClick(view);
} else {
Utils.isNetworkAvailable(getActivity(), true);
}
}
});
return signInDialog;
}
private void initializeGooglePlus() {
GoogleSignInOptions googleSignInOptions = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestServerAuthCode(GOOGLE_PLUS_CATROWEB_SERVER_CLIENT_ID, false)
.requestIdToken(GOOGLE_PLUS_CATROWEB_SERVER_CLIENT_ID)
.build();
googleApiClient = new GoogleApiClient.Builder(getActivity())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Auth.GOOGLE_SIGN_IN_API, googleSignInOptions)
.build();
connectionProgressDialog = new ProgressDialog(getActivity());
connectionProgressDialog.setMessage("Trying to sign in to Google+");
}
private void handleGooglePlusLoginButtonClick(View view) {
if (view.getId() == R.id.dialog_sign_in_gplus_login_button) {
if (!googleApiClient.isConnected()) {
shouldResolveErrors = true;
googleApiClient.connect();
triggerGPlusLogin = true;
} else {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient);
startActivityForResult(signInIntent, MainMenuActivity.REQUEST_CODE_GOOGLE_PLUS_SIGNIN);
}
}
}
public void onGoogleLogInComplete(GoogleSignInAccount account) {
String id = account.getId();
String personName = account.getDisplayName();
String email = account.getEmail();
String locale = UtilDeviceInfo.getUserCountryCode();
String idToken = account.getIdToken();
String code = account.getServerAuthCode();
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
sharedPreferences.edit().putString(Constants.GOOGLE_ID, id).commit();
sharedPreferences.edit().putString(Constants.GOOGLE_USERNAME, personName).commit();
sharedPreferences.edit().putString(Constants.GOOGLE_EMAIL, email).commit();
sharedPreferences.edit().putString(Constants.GOOGLE_LOCALE, locale).commit();
sharedPreferences.edit().putString(Constants.GOOGLE_ID_TOKEN, idToken).commit();
sharedPreferences.edit().putString(Constants.GOOGLE_EXCHANGE_CODE, code).commit();
CheckOAuthTokenTask checkOAuthTokenTask = new CheckOAuthTokenTask(getActivity(), id, Constants.GOOGLE_PLUS);
checkOAuthTokenTask.setOnCheckOAuthTokenCompleteListener(this);
checkOAuthTokenTask.execute();
}
@Override
public void onStart() {
super.onStart();
googleApiClient.connect();
}
@Override
public void onStop() {
super.onStop();
googleApiClient.disconnect();
}
private void handleLoginButtonClick() {
if (!Utils.isNetworkAvailable(getActivity(), true)) {
return;
}
LogInDialog logInDialog = new LogInDialog();
logInDialog.show(getActivity().getFragmentManager(), LogInDialog.DIALOG_FRAGMENT_TAG);
dismiss();
}
private void handleRegisterButtonClick() {
if (!Utils.isNetworkAvailable(getActivity(), true)) {
return;
}
RegistrationDialog registrationDialog = new RegistrationDialog();
registrationDialog.show(getActivity().getFragmentManager(), RegistrationDialog.DIALOG_FRAGMENT_TAG);
dismiss();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GPLUS_REQUEST_CODE_SIGN_IN) {
// If the error resolution was not successful we should not resolve further.
if (resultCode != Activity.RESULT_OK) {
shouldResolveErrors = false;
}
isResolving = false;
googleApiClient.connect();
} else if (requestCode == RESULT_CODE_AUTH_CODE) {
Log.d(DIALOG_FRAGMENT_TAG, "offline access approved?");
} else if (requestCode == MainMenuActivity.REQUEST_CODE_GOOGLE_PLUS_SIGNIN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
triggerGPlusLogin(result);
}
}
private void triggerGPlusLogin(GoogleSignInResult result) {
if (result.isSuccess()) {
GoogleSignInAccount account = result.getSignInAccount();
onGoogleLogInComplete(account);
} else {
ToastUtil.showError(getActivity(), "There was a problem during Google+ Signin. Status: "
+ result.getStatus());
}
}
@Override
public void onConnected(Bundle bundle) {
connectionProgressDialog.dismiss();
shouldResolveErrors = false;
if (triggerGPlusLogin) {
triggerGPlusLogin = false;
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient);
startActivityForResult(signInIntent, MainMenuActivity.REQUEST_CODE_GOOGLE_PLUS_SIGNIN);
}
}
@Override
public void onConnectionSuspended(int i) {
Log.d(DIALOG_FRAGMENT_TAG, "onConnectionSuspended:" + i);
googleApiClient.connect();
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// Could not connect to Google Play Services. The user needs to select an account,
// grant permissions or resolve an error in order to sign in.
Log.d(DIALOG_FRAGMENT_TAG, "onConnectionFailed:" + connectionResult);
if (shouldResolveErrors && !isResolving) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(getActivity(), GPLUS_REQUEST_CODE_SIGN_IN);
isResolving = true;
} catch (IntentSender.SendIntentException e) {
Log.e(DIALOG_FRAGMENT_TAG, "Could not resolve ConnectionResult.", e);
isResolving = false;
googleApiClient.connect();
}
} else {
new AlertDialog.Builder(getActivity()).setTitle(R.string.error)
.setMessage(R.string.sign_in_error).setPositiveButton(R.string.ok, null).show();
}
}
}
@Override
public void onCheckOAuthTokenComplete(Boolean tokenAvailable, String provider) {
if (provider.equals(Constants.FACEBOOK)) {
checkOAuthTokenFacebookComplete(tokenAvailable);
} else if (provider.equals(Constants.GOOGLE_PLUS)) {
checkOAuthTokenGoogleComplete(tokenAvailable);
}
}
private void checkOAuthTokenFacebookComplete(boolean tokenAvailable) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
if (tokenAvailable) {
FacebookLogInTask facebookLogInTask = new FacebookLogInTask(getActivity(),
sharedPreferences.getString(Constants.FACEBOOK_EMAIL, Constants.NO_FACEBOOK_EMAIL),
sharedPreferences.getString(Constants.FACEBOOK_USERNAME, Constants.NO_FACEBOOK_USERNAME),
sharedPreferences.getString(Constants.FACEBOOK_ID, Constants.NO_FACEBOOK_ID),
sharedPreferences.getString(Constants.FACEBOOK_LOCALE, Constants.NO_FACEBOOK_LOCALE)
);
facebookLogInTask.setOnFacebookLogInCompleteListener(this);
facebookLogInTask.execute();
} else {
CheckEmailAvailableTask checkEmailAvailableTask = new CheckEmailAvailableTask(getActivity(),
sharedPreferences.getString(Constants.FACEBOOK_EMAIL, Constants.NO_FACEBOOK_EMAIL), Constants.FACEBOOK);
checkEmailAvailableTask.setOnCheckEmailAvailableCompleteListener(this);
checkEmailAvailableTask.execute();
}
}
private void checkOAuthTokenGoogleComplete(boolean tokenAvailable) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
if (tokenAvailable) {
GoogleLogInTask googleLogInTask = new GoogleLogInTask(getActivity(),
sharedPreferences.getString(Constants.GOOGLE_EMAIL, Constants.NO_GOOGLE_EMAIL),
sharedPreferences.getString(Constants.GOOGLE_USERNAME, Constants.NO_GOOGLE_USERNAME),
sharedPreferences.getString(Constants.GOOGLE_ID, Constants.NO_GOOGLE_ID),
sharedPreferences.getString(Constants.GOOGLE_LOCALE, Constants.NO_GOOGLE_LOCALE));
googleLogInTask.setOnGoogleServerLogInCompleteListener(this);
googleLogInTask.execute();
} else {
String email = sharedPreferences.getString(Constants.GOOGLE_EMAIL, Constants.NO_GOOGLE_EMAIL);
CheckEmailAvailableTask checkEmailAvailableTask = new CheckEmailAvailableTask(getActivity(),
email, Constants.GOOGLE_PLUS);
checkEmailAvailableTask.setOnCheckEmailAvailableCompleteListener(this);
checkEmailAvailableTask.execute();
}
}
@Override
public void onCheckEmailAvailableComplete(Boolean emailAvailable, String provider) {
if (provider.equals(Constants.FACEBOOK)) {
checkEmailAvailableCompleteFacebook(emailAvailable);
} else if (provider.equals(Constants.GOOGLE_PLUS)) {
checkEmailAvailableCompleteGoogle(emailAvailable);
}
}
private void checkEmailAvailableCompleteFacebook(boolean emailAvailable) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
if (emailAvailable) {
FacebookExchangeTokenTask facebookExchangeTokenTask = new FacebookExchangeTokenTask(getActivity(),
AccessToken.getCurrentAccessToken().getToken(),
sharedPreferences.getString(Constants.FACEBOOK_EMAIL, Constants.NO_FACEBOOK_EMAIL),
sharedPreferences.getString(Constants.FACEBOOK_USERNAME, Constants.NO_FACEBOOK_USERNAME),
sharedPreferences.getString(Constants.FACEBOOK_ID, Constants.NO_FACEBOOK_ID),
sharedPreferences.getString(Constants.FACEBOOK_LOCALE, Constants.NO_FACEBOOK_LOCALE)
);
facebookExchangeTokenTask.setOnFacebookExchangeTokenCompleteListener(this);
facebookExchangeTokenTask.execute();
} else {
showOauthUserNameDialog(Constants.FACEBOOK);
}
}
private void checkEmailAvailableCompleteGoogle(boolean emailAvailable) {
if (emailAvailable) {
exchangeGoogleAuthorizationCode();
} else {
showOauthUserNameDialog(Constants.GOOGLE_PLUS);
}
}
public void exchangeGoogleAuthorizationCode() {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
GoogleExchangeCodeTask googleExchangeCodeTask = new GoogleExchangeCodeTask(getActivity(),
sharedPreferences.getString(Constants.GOOGLE_EXCHANGE_CODE, Constants.NO_GOOGLE_EXCHANGE_CODE),
sharedPreferences.getString(Constants.GOOGLE_EMAIL, Constants.NO_GOOGLE_EMAIL),
sharedPreferences.getString(Constants.GOOGLE_USERNAME, Constants.NO_GOOGLE_USERNAME),
sharedPreferences.getString(Constants.GOOGLE_ID, Constants.NO_GOOGLE_ID),
sharedPreferences.getString(Constants.GOOGLE_LOCALE, Constants.NO_GOOGLE_LOCALE),
sharedPreferences.getString(Constants.GOOGLE_ID_TOKEN, Constants.NO_GOOGLE_ID_TOKEN));
googleExchangeCodeTask.setOnGoogleExchangeCodeCompleteListener(this);
googleExchangeCodeTask.execute();
}
private void showOauthUserNameDialog(String provider) {
OAuthUsernameDialog oAuthUsernameDialog = new OAuthUsernameDialog();
Bundle bundle = new Bundle();
bundle.putString(Constants.CURRENT_OAUTH_PROVIDER, provider);
oAuthUsernameDialog.setArguments(bundle);
oAuthUsernameDialog.show(getActivity().getFragmentManager(), OAuthUsernameDialog.DIALOG_FRAGMENT_TAG);
dismiss();
}
@Override
public void onFacebookExchangeTokenComplete(Activity activity) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
FacebookLogInTask facebookLogInTask = new FacebookLogInTask(getActivity(),
sharedPreferences.getString(Constants.FACEBOOK_EMAIL, Constants.NO_FACEBOOK_EMAIL),
sharedPreferences.getString(Constants.FACEBOOK_USERNAME, Constants.NO_FACEBOOK_USERNAME),
sharedPreferences.getString(Constants.FACEBOOK_ID, Constants.NO_FACEBOOK_ID),
sharedPreferences.getString(Constants.FACEBOOK_LOCALE, Constants.NO_FACEBOOK_LOCALE)
);
facebookLogInTask.setOnFacebookLogInCompleteListener(this);
facebookLogInTask.execute();
}
@Override
public void onFacebookLogInComplete() {
dismiss();
Bundle bundle = new Bundle();
bundle.putString(Constants.CURRENT_OAUTH_PROVIDER, Constants.FACEBOOK);
ProjectManager.getInstance().signInFinished(getFragmentManager(), bundle);
}
@Override
public void onGoogleServerLogInComplete() {
dismiss();
Bundle bundle = new Bundle();
bundle.putString(Constants.CURRENT_OAUTH_PROVIDER, Constants.GOOGLE_PLUS);
ProjectManager.getInstance().signInFinished(getFragmentManager(), bundle);
}
@Override
public void onGoogleExchangeCodeComplete() {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
GoogleLogInTask googleLogInTask = new GoogleLogInTask(getActivity(),
sharedPreferences.getString(Constants.GOOGLE_EMAIL, Constants.NO_GOOGLE_EMAIL),
sharedPreferences.getString(Constants.GOOGLE_USERNAME, Constants.NO_GOOGLE_USERNAME),
sharedPreferences.getString(Constants.GOOGLE_ID, Constants.NO_GOOGLE_ID),
sharedPreferences.getString(Constants.GOOGLE_LOCALE, Constants.NO_GOOGLE_LOCALE));
googleLogInTask.setOnGoogleServerLogInCompleteListener(this);
googleLogInTask.execute();
}
@Override
public void onGetFacebookUserInfoTaskComplete(String id, String name, String locale, String email) {
Log.d(TAG, "FB User Info complete");
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
sharedPreferences.edit().putString(Constants.FACEBOOK_ID, id).commit();
sharedPreferences.edit().putString(Constants.FACEBOOK_USERNAME, name).commit();
sharedPreferences.edit().putString(Constants.FACEBOOK_LOCALE, locale).commit();
//if user has approved email permission, fb-email address is taken, else device email address
if (email != null) {
sharedPreferences.edit().putString(Constants.FACEBOOK_EMAIL, email).commit();
} else {
sharedPreferences.edit().putString(Constants.FACEBOOK_EMAIL, UtilDeviceInfo.getUserEmail(getActivity()))
.commit();
}
CheckOAuthTokenTask checkOAuthTokenTask = new CheckOAuthTokenTask(getActivity(), id, Constants.FACEBOOK);
checkOAuthTokenTask.setOnCheckOAuthTokenCompleteListener(this);
checkOAuthTokenTask.execute();
}
@Override
public void forceSignIn() {
SignInDialog signInDialog = new SignInDialog();
signInDialog.show(getActivity().getFragmentManager(), SignInDialog.DIALOG_FRAGMENT_TAG);
}
}