package com.aptoide.amethyst; import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountManagerCallback; import android.accounts.AccountManagerFuture; import android.content.ContentResolver; import android.content.Intent; import android.content.IntentSender; import android.content.SharedPreferences; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.support.v7.widget.Toolbar; import android.text.SpannableString; import android.text.method.PasswordTransformationMethod; import android.text.style.UnderlineSpan; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import com.aptoide.amethyst.analytics.Analytics; import com.aptoide.amethyst.configuration.AptoideConfiguration; import com.aptoide.amethyst.dialogs.AptoideDialog; import com.aptoide.amethyst.events.BusProvider; import com.aptoide.amethyst.events.OttoEvents; import com.aptoide.amethyst.model.json.CheckUserCredentialsJson; import com.aptoide.amethyst.model.json.OAuth; import com.aptoide.amethyst.preferences.Preferences; import com.aptoide.amethyst.preferences.SecurePreferences; import com.aptoide.amethyst.services.RabbitMqService; import com.aptoide.amethyst.utils.AptoideUtils; import com.aptoide.amethyst.utils.Configs; import com.aptoide.amethyst.utils.Logger; import com.aptoide.amethyst.webservices.CheckUserCredentialsRequest; import com.aptoide.amethyst.webservices.Errors; import com.aptoide.amethyst.webservices.OAuth2AuthenticationRequest; import com.aptoide.dataprovider.AptoideSpiceHttpsService; import com.aptoide.dataprovider.webservices.models.Constants; import com.aptoide.dataprovider.webservices.models.ErrorResponse; import com.facebook.Request; import com.facebook.Response; import com.facebook.Session; import com.facebook.SessionState; import com.facebook.UiLifecycleHelper; import com.facebook.model.GraphUser; import com.facebook.widget.LoginButton; 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.GoogleApiAvailability; import com.google.android.gms.common.api.GoogleApiClient; import com.octo.android.robospice.SpiceManager; import com.octo.android.robospice.persistence.exception.SpiceException; import com.octo.android.robospice.request.listener.RequestListener; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import retrofit.RetrofitError; /** * Created by brutus on 09-12-2013. */ public class LoginActivity extends AccountAuthenticatorActivity implements GoogleApiClient.OnConnectionFailedListener { private static final String TAG = LoginActivity.class.getSimpleName(); private static final String TAG_PROGRESS = "progressDialog"; private static final int REQUEST_CODE_RESOLVE_ERR = 9000; private CheckBox registerDevice; private boolean hasQueue; private CheckUserCredentialsRequest request; private boolean fromPreviousAptoideVersion; private Class signupClass = Aptoide.getConfiguration().getSignUpActivityClass(); private boolean removeAccount; /* A flag indicating that a PendingIntent is in progress and prevents * us from starting further intents. */ private boolean mIntentInProgress; /* Store the connection result from onConnectionFailed callbacks so that we can * resolve them when the user clicks sign-in. */ private ConnectionResult mConnectionResult; private EditText emailBox; public enum Mode {APTOIDE, GOOGLE, FACEBOOK} public final static String ARG_OPTIONS_BUNDLE = "BE"; public final static String OPTIONS_LOGOUT_BOOL = "OLOUT"; public final static String OPTIONS_FASTBOOK_BOOL = "OFASTBOOK"; public final static String OPTIONS_EMAIL_STRING = "OEMAIL"; public final static String OPTIONS_TOKEN_STRING = "OTOKEN"; public final static String ARG_ACCOUNT_TYPE = "ACCOUNT_TYPE"; public final static String ARG_AUTH_TYPE = "AUTH_TYPE"; public final static String ARG_ACCOUNT_NAME = "ACCOUNT_NAME"; public final static String ARG_IS_ADDING_NEW_ACCOUNT = "IS_ADDING_ACCOUNT"; public static final String KEY_ERROR_MESSAGE = "ERR_MSG"; public final static String PARAM_USER_PASS = "USER_PASS"; public final static String PARAM_USER_AVATAR = "USER_AVATAR"; private final int REQ_SIGNUP = 1; private final int REQ_SIGN_IN_GOOGLE = 2; private AccountManager mAccountManager; private String mAuthTokenType; private SpiceManager spiceManager = new SpiceManager(AptoideSpiceHttpsService.class); EditText password_box; CheckBox checkShowPass; private UiLifecycleHelper uiLifecycleHelper; private Session.StatusCallback statusCallback = new Session.StatusCallback() { @Override public void call(final Session session, SessionState state, Exception exception) { if (!state.isOpened()) { return; } AptoideDialog.pleaseWaitDialog().show(getSupportFragmentManager(), "pleaseWaitDialog"); Request request = Request.newMeRequest(session, new Request.GraphUserCallback() { @Override public void onCompleted(final GraphUser user, Response response) { if (session == Session.getActiveSession() && user != null) { try { if (removeAccount && mAccountManager.getAccountsByType(Aptoide.getConfiguration().getAccountType()).length > 0) { mAccountManager.removeAccount(mAccountManager.getAccountsByType(Aptoide.getConfiguration().getAccountType())[0], new AccountManagerCallback<Boolean>() { @Override public void run(AccountManagerFuture<Boolean> future) { submit(Mode.FACEBOOK, user.getProperty("email").toString(), session.getAccessToken(), null); } }, new Handler(Looper.getMainLooper())); } else { //TODO show denied permissions // Toast.makeText(LoginActivity.this, session.getDeclinedPermissions().toString(), Toast.LENGTH_SHORT).show(); submit(Mode.FACEBOOK, user.getProperty("email").toString(), session.getAccessToken(), null); } } catch (Exception e) { Logger.printException(e); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(Aptoide.getContext(), R.string.error_occured, Toast.LENGTH_LONG).show(); android.support.v4.app.DialogFragment pd = (android.support.v4.app.DialogFragment) getSupportFragmentManager().findFragmentByTag("pleaseWaitDialog"); if (pd != null) { pd.dismissAllowingStateLoss(); } } }); session.closeAndClearTokenInformation(); } } else { session.closeAndClearTokenInformation(); } } }); request.executeAsync(); } }; @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (AptoideUtils.AccountUtils.isLoggedIn(this)) { finish(); Toast.makeText(this, R.string.one_account_allowed, Toast.LENGTH_SHORT).show(); return; } Aptoide.getThemePicker().setAptoideTheme(this); final String activityTitle; final Bundle options = getIntent().getBundleExtra(ARG_OPTIONS_BUNDLE); if (options != null && options.getBoolean(OPTIONS_FASTBOOK_BOOL, false)) { activityTitle = getString(R.string.social_timeline); if (options.getBoolean(OPTIONS_LOGOUT_BOOL, false)) { setContentView(R.layout.page_timeline_logout_and_login); removeAccount = true; } else { setContentView(R.layout.page_timeline_not_logged_in); } } else { activityTitle = getString(R.string.login_or_register); setContentView(R.layout.form_login); setUpLogin(); setUpGoogle(); } setUpFacebook(savedInstanceState); final Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(mToolbar); getSupportActionBar().setHomeButtonEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayShowTitleEnabled(true); getSupportActionBar().setTitle(activityTitle); mAccountManager = AccountManager.get(getBaseContext()); mAuthTokenType = getIntent().getStringExtra(ARG_AUTH_TYPE); if (mAuthTokenType == null) { mAuthTokenType = AptoideConfiguration.AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS; } spiceManager.start(this); } private void setUpLogin() { String accountName = getIntent().getStringExtra(ARG_ACCOUNT_NAME); emailBox = (EditText) findViewById(R.id.username); if (accountName != null) { emailBox.setText(accountName); } if (PreferenceManager.getDefaultSharedPreferences(this).contains(Constants.LOGIN_USER_LOGIN)) { emailBox.setText(PreferenceManager.getDefaultSharedPreferences(this).getString(Constants.LOGIN_USER_LOGIN, "")); fromPreviousAptoideVersion = true; } password_box = (EditText) findViewById(R.id.password); password_box.setTransformationMethod(new PasswordTransformationMethod()); Button button = (Button) findViewById(R.id.btn_show_hide_pass); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final int cursorPosition = password_box.getSelectionStart(); final boolean passwordShown = password_box.getTransformationMethod() == null; v.setBackgroundResource(passwordShown ? R.drawable.icon_closed_eye : R.drawable.icon_open_eye); password_box.setTransformationMethod(passwordShown ? new PasswordTransformationMethod() : null); password_box.setSelection(cursorPosition); } }); findViewById(R.id.button_login).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String username = ((EditText) findViewById(R.id.username)).getText().toString(); String password = ((EditText) findViewById(R.id.password)).getText().toString(); if (username.length() == 0 || password.length() == 0) { Toast.makeText(getApplicationContext(), R.string.fields_cannot_empty, Toast.LENGTH_LONG).show(); return; } submit(Mode.APTOIDE, username, password, null); } }); Button registerButton = (Button) findViewById(R.id.button_register); registerButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent signup = new Intent(LoginActivity.this, signupClass); startActivityForResult(signup, REQ_SIGNUP); } }); registerDevice = (CheckBox) findViewById(R.id.link_my_device); TextView forgot_password = (TextView) findViewById(R.id.forgot_password); SpannableString forgetString = new SpannableString(getString(R.string.forgot_passwd)); forgetString.setSpan(new UnderlineSpan(), 0, forgetString.length(), 0); forgot_password.setText(forgetString); forgot_password.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent passwordRecovery = new Intent(Intent.ACTION_VIEW, Uri.parse("http://m.aptoide.com/account/password-recovery")); startActivity(passwordRecovery); } }); } private void setUpFacebook(final Bundle savedInstanceState) { uiLifecycleHelper = new UiLifecycleHelper(this, statusCallback); uiLifecycleHelper.onCreate(savedInstanceState); LoginButton fbButton = (LoginButton) findViewById(R.id.fb_login_button); fbButton.setReadPermissions(Arrays.asList("email", "user_friends")); } private void setUpGoogle() { final View googleSignIn = findViewById(R.id.g_sign_in_button); final int connectionResult = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this); final Collection<Integer> badResults = Arrays.asList(ConnectionResult.SERVICE_MISSING, ConnectionResult.SERVICE_DISABLED); final boolean gmsAvailable = BuildConfig.GMS_CONFIGURED && !badResults.contains(connectionResult); if (!gmsAvailable) { googleSignIn.setVisibility(View.GONE); return; } final GoogleSignInOptions gso = new GoogleSignInOptions .Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestEmail() .requestServerAuthCode(BuildConfig.GMS_SERVER_ID) .build(); final GoogleApiClient client = new GoogleApiClient.Builder(this) .enableAutoManage(this, this) .addApi(Auth.GOOGLE_SIGN_IN_API, gso) .build(); googleSignIn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(client); startActivityForResult(signInIntent, REQ_SIGN_IN_GOOGLE); } }); } // Google @Override public void onConnectionFailed(@NonNull ConnectionResult result) { if (result.hasResolution()) { try { result.startResolutionForResult(this, REQUEST_CODE_RESOLVE_ERR); } catch (IntentSender.SendIntentException ignore) { // The intent was canceled before it was sent. } } } @Override public boolean onOptionsItemSelected(MenuItem item) { int i = item.getItemId(); if (i == android.R.id.home || i == R.id.home) { finish(); } return super.onOptionsItemSelected(item); } @Override protected void onStart() { super.onStart(); } @Override protected void onResume() { super.onResume(); uiLifecycleHelper.onResume(); } @Override protected void onPause() { super.onPause(); uiLifecycleHelper.onPause(); } @Override protected void onStop() { super.onStop(); uiLifecycleHelper.onStop(); } @Override public void onDestroy() { super.onDestroy(); if (uiLifecycleHelper != null) { uiLifecycleHelper.onDestroy(); } } @Override protected void onActivityResult(int requestCode, int resultCode, final Intent data) { super.onActivityResult(requestCode, resultCode, data); uiLifecycleHelper.onActivityResult(requestCode, resultCode, data); if (requestCode == REQ_SIGN_IN_GOOGLE) { final GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); handleSignInResult(result); } else if (requestCode == REQ_SIGNUP && resultCode == RESULT_OK) { hasQueue = true; finishLogin(data); } } public void handleSignInResult(GoogleSignInResult result) { Log.d(TAG, "GoogleSignInResult. status: " + result.getStatus()); final GoogleSignInAccount account; if (result.isSuccess() && (account = result.getSignInAccount()) != null) { final String userName = account.getEmail(); final String token = account.getServerAuthCode(); final String name = account.getDisplayName(); submit(Mode.GOOGLE, userName, token, name); } else { Toast.makeText(Aptoide.getContext(), R.string.error_occured, Toast.LENGTH_SHORT).show(); } } public void setShowProgress(final boolean showProgress) { final DialogFragment progress = (DialogFragment) getSupportFragmentManager().findFragmentByTag(TAG_PROGRESS); if (progress == null && showProgress) { try { AptoideDialog.pleaseWaitDialog().show(getSupportFragmentManager(), TAG_PROGRESS); // https://code.google.com/p/android/issues/detail?id=23761 } catch (IllegalStateException ignore) { } } else if (progress != null && !showProgress) { progress.dismissAllowingStateLoss(); } } public void submit(final Mode mode, final String userName, final String passwordOrToken, final String nameForGoogle) { Log.d(TAG, "Submitting. mode: " + mode.name() +", userName: " + userName + ", nameForGoogle: " + nameForGoogle); final String accountType = getIntent().getStringExtra(ARG_ACCOUNT_TYPE); OAuth2AuthenticationRequest oAuth2AuthenticationRequest = new OAuth2AuthenticationRequest(); oAuth2AuthenticationRequest.setPassword(passwordOrToken); oAuth2AuthenticationRequest.setUsername(userName); oAuth2AuthenticationRequest.setMode(mode); oAuth2AuthenticationRequest.setNameForGoogle(nameForGoogle); setShowProgress(true); spiceManager.execute(oAuth2AuthenticationRequest, new RequestListener<OAuth>() { @Override public void onRequestFailure(SpiceException spiceException) { Log.d(TAG, "OAuth filed: " + spiceException.getMessage()); final Throwable cause = spiceException.getCause(); if (cause != null) { final String error; if (cause instanceof RetrofitError) { final RetrofitError retrofitError = (RetrofitError) cause; final retrofit.client.Response response = retrofitError.getResponse(); if (response != null && (response.getStatus() == 400 || response.getStatus() == 401)) { error = getString(R.string.error_AUTH_1); } else { error = getString(R.string.error_occured); } } else { error = getString(R.string.error_occured); } Toast.makeText(getBaseContext(), error, Toast.LENGTH_SHORT).show(); } setShowProgress(false); } @Override public void onRequestSuccess(final OAuth oAuth) { if (oAuth.getStatus() != null && oAuth.getStatus().equals("FAIL")) { Log.d(TAG, "OAuth filed: " + oAuth.getError_description()); AptoideUtils.UI.toastError(oAuth.getError()); setShowProgress(false); } else { getUserInfo(oAuth, userName, mode, accountType, passwordOrToken); Analytics.Login.login(userName, mode); } } }); } private void getUserInfo(final OAuth oAuth, final String userName, final Mode mode, final String accountType, final String passwordOrToken) { Log.d(TAG, "Loading user info."); request = CheckUserCredentialsRequest.buildDefaultRequest(this, oAuth.getAccess_token()); request.setRegisterDevice(registerDevice != null && registerDevice.isChecked()); setShowProgress(true); spiceManager.execute(request, new RequestListener<CheckUserCredentialsJson>() { @Override public void onRequestFailure(SpiceException e) { Log.d(TAG, "Loading user info failed. " + e.getMessage()); Toast.makeText(getBaseContext(), R.string.error_occured, Toast.LENGTH_SHORT).show(); setShowProgress(false); } @Override public void onRequestSuccess(CheckUserCredentialsJson checkUserCredentialsJson) { Log.d(TAG, "User info loaded. status: " + checkUserCredentialsJson.getStatus() + ", userName: " + checkUserCredentialsJson.getUsername()); if ("OK".equals(checkUserCredentialsJson.getStatus())) { updatePreferences(checkUserCredentialsJson, userName, mode.name(), oAuth.getAccess_token()); if (null != checkUserCredentialsJson.getQueue()) { hasQueue = true; } Bundle data = new Bundle(); data.putString(AccountManager.KEY_ACCOUNT_NAME, userName); data.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType); data.putString(AccountManager.KEY_AUTHTOKEN, oAuth.getRefreshToken()); data.putString(PARAM_USER_PASS, passwordOrToken); final Intent res = new Intent(); res.putExtras(data); finishLogin(res); } else { final HashMap<String, Integer> errorsMapConversion = Errors.getErrorsMap(); Integer stringId; String message; for (ErrorResponse error : checkUserCredentialsJson.getErrors()) { stringId = errorsMapConversion.get(error.code); if (stringId != null) { message = getString(stringId); } else { message = error.msg; } Toast.makeText(getBaseContext(), message, Toast.LENGTH_SHORT).show(); } } setShowProgress(false); } }); } private void finishLogin(Intent intent) { Log.d("aptoide", TAG + "> finishLogin"); String accountName = intent.getStringExtra(AccountManager.KEY_ACCOUNT_NAME); String accountPassword = intent.getStringExtra(PARAM_USER_PASS); final String accountType = intent.hasExtra(ARG_ACCOUNT_TYPE) ? intent.getStringExtra(ARG_ACCOUNT_TYPE) : Aptoide.getConfiguration().getAccountType(); final Account account = new Account(accountName, accountType); if (getIntent().getBooleanExtra(ARG_IS_ADDING_NEW_ACCOUNT, false)) { Log.d("aptoide", TAG + "> finishLogin > addAccountExplicitly"); String authtoken = intent.getStringExtra(AccountManager.KEY_AUTHTOKEN); String authtokenType = mAuthTokenType; // Creating the account on the device and setting the auth token we got // (Not setting the auth token will cause another call to the server to authenticate the user) mAccountManager.addAccountExplicitly(account, accountPassword, null); mAccountManager.setAuthToken(account, authtokenType, authtoken); } else { Log.d("aptoide", TAG + "> finishLogin > setPassword"); mAccountManager.setPassword(account, accountPassword); } setAccountAuthenticatorResult(intent.getExtras()); setResult(RESULT_OK, intent); if (fromPreviousAptoideVersion) { PreferenceManager.getDefaultSharedPreferences(this).edit().remove(Constants.LOGIN_USER_LOGIN).commit(); } finish(); if (registerDevice != null && registerDevice.isChecked() && hasQueue) startService(new Intent(this, RabbitMqService.class)); ContentResolver.setSyncAutomatically(account, Aptoide.getConfiguration().getUpdatesSyncAdapterAuthority(), true); if (Build.VERSION.SDK_INT >= 8) ContentResolver.addPeriodicSync(account, Aptoide.getConfiguration().getUpdatesSyncAdapterAuthority(), new Bundle(), 43200); ContentResolver.setSyncAutomatically(account, Aptoide.getConfiguration().getAutoUpdatesSyncAdapterAuthority(), true); } public static void updatePreferences(CheckUserCredentialsJson checkUserCredentialsJson, String username, String modeName, String token) { SharedPreferences.Editor preferences = PreferenceManager.getDefaultSharedPreferences(Aptoide.getContext()).edit(); if (null != (checkUserCredentialsJson.getQueue())) { //hasQueue = true; preferences.putString("queueName", checkUserCredentialsJson.getQueue()); } if (null != (checkUserCredentialsJson.getAvatar()) && !checkUserCredentialsJson.getAvatar().equals("")) { preferences.putString(Constants.USER_AVATAR, checkUserCredentialsJson.getAvatar()); } if (null != (checkUserCredentialsJson.getRepo())) { preferences.putString("userRepo", checkUserCredentialsJson.getRepo()); } if (null != (checkUserCredentialsJson.getUsername())) { preferences.putString("username", checkUserCredentialsJson.getUsername()); } if (checkUserCredentialsJson.getSettings() != null) { boolean timeline = checkUserCredentialsJson.getSettings().getTimeline().equals("active"); preferences.putBoolean(Preferences.TIMELINE_ACEPTED_BOOL, timeline); boolean matureswitch = checkUserCredentialsJson.getSettings().getMatureswitch().equals("active"); preferences.putBoolean(Constants.MATURE_CHECK_BOX, matureswitch); } preferences.putString(Configs.LOGIN_USER_LOGIN, username); preferences.putString("loginType", modeName); preferences.apply(); SharedPreferences.Editor securePreferences = SecurePreferences.getInstance().edit(); securePreferences.putString("access_token", token); securePreferences.putInt("User_ID", checkUserCredentialsJson.getId()); Log.d("pois", "updatePreferences, setting user id to " + checkUserCredentialsJson.getId()); securePreferences.putString("devtoken", checkUserCredentialsJson.getToken()); securePreferences.apply(); BusProvider.getInstance().post(new OttoEvents.RedrawNavigationDrawer()); } }