Skip to content

Instantly share code, notes, and snippets.

@markbratanov
Created November 24, 2014 21:57
Show Gist options
  • Save markbratanov/a94291edaf02b0b236d3 to your computer and use it in GitHub Desktop.
Save markbratanov/a94291edaf02b0b236d3 to your computer and use it in GitHub Desktop.
package com.starkenglish;
import android.app.Activity;
import android.app.ActionBar;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.support.v4.widget.DrawerLayout;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import com.firebase.client.AuthData;
import com.firebase.client.Firebase;
import com.firebase.client.FirebaseError;
import com.google.android.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.UserRecoverableAuthException;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.Scopes;
import com.google.android.gms.common.SignInButton;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.plus.Plus;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends FragmentActivity
implements NavigationDrawerFragment.NavigationDrawerCallbacks,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
/**
* Fragment managing the behaviors, interactions and presentation of the navigation drawer.
*/
private NavigationDrawerFragment mNavigationDrawerFragment;
/**
* Used to store the last screen title. For use in {@link #restoreActionBar()}.
*/
private CharSequence mTitle;
/***************************************
* GENERAL *
***************************************/
/* TextView that is used to display information about the logged in user */
private TextView mLoggedInStatusTextView;
/* A dialog that is presented until the Firebase authentication finished. */
private ProgressDialog mAuthProgressDialog;
/* A reference to the firebase */
private Firebase ref;
/* Data from the authenticated user */
private AuthData authData;
/* A tag that is used for logging statements */
private static final String TAG = "LoginDemo";
/***************************************
* GOOGLE *
***************************************/
/* Request code used to invoke sign in user interactions for Google+ */
public static final int RC_GOOGLE_LOGIN = 1;
/* Client used to interact with Google APIs. */
private GoogleApiClient mGoogleApiClient;
/* A flag indicating that a PendingIntent is in progress and prevents us from starting further intents. */
private boolean mGoogleIntentInProgress;
/* Track whether the sign-in button has been clicked so that we know to resolve all issues preventing sign-in
* without waiting. */
private boolean mGoogleLoginClicked;
/* Store the connection result from onConnectionFailed callbacks so that we can resolve them when the user clicks
* sign-in. */
private ConnectionResult mGoogleConnectionResult;
/* The login button for Google */
private SignInButton mGoogleLoginButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
//getSupportActionBar().setLogo(R.drawable.ic_action_starkenglish);
/***************************************
* GOOGLE *
***************************************/
/* Load the Google login button */
mGoogleLoginButton = (SignInButton)findViewById(R.id.login_with_google);
mGoogleLoginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mGoogleLoginClicked = true;
if (!mGoogleApiClient.isConnecting()) {
if (mGoogleConnectionResult != null) {
resolveSignInError();
} else if (mGoogleApiClient.isConnected()) {
getGoogleOAuthTokenAndLogin();
} else {
/* connect API now */
Log.d(TAG, "Trying to connect to Google API");
mGoogleApiClient.connect();
}
}
}
});
/* Setup the Google API object to allow Google+ logins */
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_LOGIN)
.build();
/***************************************
* GENERAL *
***************************************/
/* Create the SimpleLogin class that is used for all authentication with Firebase */
String firebaseUrl = getResources().getString(R.string.firebase_url);
Firebase.setAndroidContext(getApplicationContext());
ref = new Firebase(firebaseUrl);
/* Setup the progress dialog that is displayed later when authenticating with Firebase */
mAuthProgressDialog = new ProgressDialog(this);
mAuthProgressDialog.setTitle("Loading");
mAuthProgressDialog.setMessage("Authenticating");
mAuthProgressDialog.setCancelable(false);
mAuthProgressDialog.show();
/* Check if the user is authenticated with Firebase already. If this is the case we can set the authenticated
* user and hide hide any login buttons */
ref.addAuthStateListener(new Firebase.AuthStateListener() {
@Override
public void onAuthStateChanged(AuthData authData) {
mAuthProgressDialog.hide();
setAuthenticatedUser(authData);
}
});
// Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
// setSupportActionBar(toolbar);
}
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, PlaceholderFragment.newInstance(position + 1))
.commit();
}
public void onSectionAttached(int number) {
switch (number) {
case 1:
mTitle = getString(R.string.title_section1);
break;
case 2:
mTitle = getString(R.string.title_section2);
break;
case 3:
mTitle = getString(R.string.title_section3);
break;
}
}
public void restoreActionBar() {
ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(mTitle);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((MainActivity) activity).onSectionAttached(
getArguments().getInt(ARG_SECTION_NUMBER));
}
}
/**
* This method fires when any startActivityForResult finishes. The requestCode maps to
* the value passed into startActivityForResult.
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Map<String, String> options = new HashMap<String, String>();
if (requestCode == RC_GOOGLE_LOGIN) {
/* This was a request by the Google API */
if (resultCode != RESULT_OK) {
mGoogleLoginClicked = false;
}
mGoogleIntentInProgress = false;
if (!mGoogleApiClient.isConnecting()) {
mGoogleApiClient.connect();
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
/* If a user is currently authenticated, display a logout menu */
if (this.authData != null) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
} else {
return false;
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_logout) {
logout();
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Unauthenticate from Firebase and from providers where necessary.
*/
private void logout() {
if (this.authData != null) {
/* logout of Firebase */
ref.unauth();
/* Logout of any of the Frameworks. This step is optional, but ensures the user is not logged into
* Facebook/Google+ after logging out of Firebase. */
if (this.authData.getProvider().equals("google")) {
/* Logout from Google+ */
if (mGoogleApiClient.isConnected()) {
Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
mGoogleApiClient.disconnect();
}
}
/* Update authenticated user and show login buttons */
setAuthenticatedUser(null);
}
}
/**
* Once a user is logged in, take the authData provided from Firebase and "use" it.
*/
private void setAuthenticatedUser(AuthData authData) {
if (authData != null) {
/* Hide all the login buttons */
mGoogleLoginButton.setVisibility(View.GONE);
//card_view
//Intent intent = new Intent(this, LessonView.class);
//startActivity(intent);
/* show a provider specific status text */
String name = null;
if (authData.getProvider().equals("facebook")
|| authData.getProvider().equals("google")
|| authData.getProvider().equals("twitter")) {
name = (String)authData.getProviderData().get("displayName");
} else if (authData.getProvider().equals("anonymous")
|| authData.getProvider().equals("password")) {
name = authData.getUid();
} else {
Log.e(TAG, "Invalid provider: " + authData.getProvider());
}
if (name != null) {
mLoggedInStatusTextView.setText("Logged in as " + name + " (" + authData.getProvider() + ")");
}
} else {
/* No authenticated user show all the login buttons */
mGoogleLoginButton.setVisibility(View.VISIBLE);
}
this.authData = authData;
/* invalidate options menu to hide/show the logout button */
invalidateOptionsMenu();
}
/**
* Show errors to users
*/
private void showErrorDialog(String message) {
new AlertDialog.Builder(this)
.setTitle("Error")
.setMessage(message)
.setPositiveButton(android.R.string.ok, null)
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
/**
* Utility class for authentication results
*/
private class AuthResultHandler implements Firebase.AuthResultHandler {
private final String provider;
public AuthResultHandler(String provider) {
this.provider = provider;
}
@Override
public void onAuthenticated(AuthData authData) {
mAuthProgressDialog.hide();
Log.i(TAG, provider + " auth successful");
setAuthenticatedUser(authData);
}
@Override
public void onAuthenticationError(FirebaseError firebaseError) {
mAuthProgressDialog.hide();
showErrorDialog(firebaseError.toString());
}
}
/***************************************
* GOOGLE *
***************************************/
/* A helper method to resolve the current ConnectionResult error. */
private void resolveSignInError() {
if (mGoogleConnectionResult.hasResolution()) {
try {
mGoogleIntentInProgress = true;
mGoogleConnectionResult.startResolutionForResult(this, RC_GOOGLE_LOGIN);
} catch (IntentSender.SendIntentException e) {
// The intent was canceled before it was sent. Return to the default
// state and attempt to connect to get an updated ConnectionResult.
mGoogleIntentInProgress = false;
mGoogleApiClient.connect();
}
}
}
private void getGoogleOAuthTokenAndLogin() {
mAuthProgressDialog.show();
/* Get OAuth token in Background */
AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
String errorMessage = null;
@Override
protected String doInBackground(Void... params) {
String token = null;
try {
String scope = String.format("oauth2:%s", Scopes.PLUS_LOGIN);
token = GoogleAuthUtil.getToken(MainActivity.this, Plus.AccountApi.getAccountName(mGoogleApiClient), scope);
} catch (IOException transientEx) {
/* Network or server error */
Log.e(TAG, "Error authenticating with Google: " + transientEx);
errorMessage = "Network error: " + transientEx.getMessage();
} catch (UserRecoverableAuthException e) {
Log.w(TAG, "Recoverable Google OAuth error: " + e.toString());
/* We probably need to ask for permissions, so start the intent if there is none pending */
if (!mGoogleIntentInProgress) {
mGoogleIntentInProgress = true;
Intent recover = e.getIntent();
startActivityForResult(recover, RC_GOOGLE_LOGIN);
}
} catch (GoogleAuthException authEx) {
/* The call is not ever expected to succeed assuming you have already verified that
* Google Play services is installed. */
Log.e(TAG, "Error authenticating with Google: " + authEx.getMessage(), authEx);
errorMessage = "Error authenticating with Google: " + authEx.getMessage();
}
return token;
}
@Override
protected void onPostExecute(String token) {
mGoogleLoginClicked = false;
if (token != null) {
/* Successfully got OAuth token, now login with Google */
ref.authWithOAuthToken("google", token, new AuthResultHandler("google"));
} else if (errorMessage != null) {
mAuthProgressDialog.hide();
showErrorDialog(errorMessage);
}
}
};
task.execute();
}
@Override
public void onConnected(final Bundle bundle) {
/* Connected with Google API, use this to authenticate with Firebase */
getGoogleOAuthTokenAndLogin();
}
@Override
public void onConnectionFailed(ConnectionResult result) {
if (!mGoogleIntentInProgress) {
/* Store the ConnectionResult so that we can use it later when the user clicks on the Google+ login button */
mGoogleConnectionResult = result;
if (mGoogleLoginClicked) {
/* The user has already clicked login so we attempt to resolve all errors until the user is signed in,
* or they cancel. */
resolveSignInError();
} else {
Log.e(TAG, result.toString());
}
}
}
@Override
public void onConnectionSuspended(int i) {
// ignore
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment