diff --git a/app/src/main/java/com/firebase/uidemo/RecyclerViewDemoActivity.java b/app/src/main/java/com/firebase/uidemo/RecyclerViewDemoActivity.java
index ce203ad..811c7d2 100644
--- a/app/src/main/java/com/firebase/uidemo/RecyclerViewDemoActivity.java
+++ b/app/src/main/java/com/firebase/uidemo/RecyclerViewDemoActivity.java
@@ -21,7 +21,7 @@
 import com.firebase.client.FirebaseError;
 import com.firebase.client.Query;
 import com.firebase.ui.auth.core.FirebaseLoginBaseActivity;
-import com.firebase.ui.FirebaseRecyclerViewAdapter;
+import com.firebase.ui.FirebaseRecyclerAdapter;
 import com.firebase.ui.auth.core.FirebaseLoginError;
 import com.firebase.ui.auth.core.SocialProvider;
 
@@ -37,7 +37,7 @@
     private EditText mMessageEdit;
 
     private RecyclerView mMessages;
-    private FirebaseRecyclerViewAdapter<Chat, ChatHolder> mRecycleViewAdapter;
+    private FirebaseRecyclerAdapter<Chat, ChatHolder> mRecycleViewAdapter;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -81,7 +81,7 @@ public void onComplete(FirebaseError firebaseError, Firebase firebase) {
         mMessages.setHasFixedSize(false);
         mMessages.setLayoutManager(manager);
 
-        mRecycleViewAdapter = new FirebaseRecyclerViewAdapter<Chat, ChatHolder>(Chat.class, R.layout.message, ChatHolder.class, mChatRef) {
+        mRecycleViewAdapter = new FirebaseRecyclerAdapter<Chat, ChatHolder>(Chat.class, R.layout.message, ChatHolder.class, mChatRef) {
             @Override
             public void populateViewHolder(ChatHolder chatView, Chat chat) {
                 chatView.setName(chat.getName());
@@ -208,7 +208,7 @@ public String getText() {
     }
 
     public static class ChatHolder extends RecyclerView.ViewHolder {
-        public View mView;
+        View mView;
 
         public ChatHolder(View itemView) {
             super(itemView);
diff --git a/build.gradle b/build.gradle
index 1e9b0c1..9e3388a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,7 +6,7 @@ buildscript {
     }
     dependencies {
         classpath 'com.android.tools.build:gradle:1.2.3'
-        classpath 'com.google.gms:google-services:1.5.0-beta2'
+        classpath 'com.google.gms:google-services:1.5.0'
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
     }
diff --git a/library/pom.xml b/library/pom.xml
index 94fb0e8..bf36e00 100644
--- a/library/pom.xml
+++ b/library/pom.xml
@@ -6,7 +6,7 @@
   <name>FirebaseUI-Android</name>
   <description>FirebaseUI library for Android applications</description>
   <url>https://github.com/firebase/FirebaseUI-Android</url>
-  <version>0.2.2</version>
+  <version>0.3.0</version>
   <packaging>aar</packaging>
   <scm>
     <url>scm:git@github.com/firebase/FirebaseUI-Android</url>
diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml
index 69af9e6..c7c9924 100644
--- a/library/src/main/AndroidManifest.xml
+++ b/library/src/main/AndroidManifest.xml
@@ -1,9 +1,4 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.firebase.ui">
-
-    <uses-permission android:name="android.permission.INTERNET" />
-
     <application android:allowBackup="true" android:label="@string/app_name">
-
     </application>
-
 </manifest>
diff --git a/library/src/main/java/com/firebase/ui/FirebaseListAdapter.java b/library/src/main/java/com/firebase/ui/FirebaseListAdapter.java
index 2697981..1d214ae 100644
--- a/library/src/main/java/com/firebase/ui/FirebaseListAdapter.java
+++ b/library/src/main/java/com/firebase/ui/FirebaseListAdapter.java
@@ -162,6 +162,7 @@ protected void populateView(View v, T model, int position) {
      * @param v         The view to populate
      * @param model     The object containing the data used to populate the view
      */
+    @Deprecated
     protected void populateView(View v, T model) {
 
     }
diff --git a/library/src/main/java/com/firebase/ui/FirebaseRecyclerAdapter.java b/library/src/main/java/com/firebase/ui/FirebaseRecyclerAdapter.java
new file mode 100644
index 0000000..4706279
--- /dev/null
+++ b/library/src/main/java/com/firebase/ui/FirebaseRecyclerAdapter.java
@@ -0,0 +1,214 @@
+/*
+ * Firebase UI Bindings Android Library
+ *
+ * Copyright © 2015 Firebase - All Rights Reserved
+ * https://www.firebase.com
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binaryform must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.firebase.ui;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.firebase.client.Firebase;
+import com.firebase.client.Query;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * This class is a generic way of backing an RecyclerView with a Firebase location.
+ * It handles all of the child events at the given Firebase location. It marshals received data into the given
+ * class type.
+ *
+ * To use this class in your app, subclass it passing in all required parameters and implement the
+ * populateViewHolder method.
+ *
+ * <blockquote><pre>
+ * {@code
+ *     private static class ChatMessageViewHolder extends RecyclerView.ViewHolder {
+ *         TextView messageText;
+ *         TextView nameText;
+ *
+ *         public ChatMessageViewHolder(View itemView) {
+ *             super(itemView);
+ *             nameText = (TextView)itemView.findViewById(android.R.id.text1);
+ *             messageText = (TextView) itemView.findViewById(android.R.id.text2);
+ *         }
+ *     }
+ *
+ *     FirebaseRecyclerAdapter<ChatMessage, ChatMessageViewHolder> adapter;
+ *     ref = new Firebase("https://<yourapp>.firebaseio.com");
+ *
+ *     RecyclerView recycler = (RecyclerView) findViewById(R.id.messages_recycler);
+ *     recycler.setHasFixedSize(true);
+ *     recycler.setLayoutManager(new LinearLayoutManager(this));
+ *
+ *     adapter = new FirebaseRecyclerAdapter<ChatMessage, ChatMessageViewHolder>(ChatMessage.class, android.R.layout.two_line_list_item, ChatMessageViewHolder.class, mRef) {
+ *         public void populateViewHolder(ChatMessageViewHolder chatMessageViewHolder, ChatMessage chatMessage) {
+ *             chatMessageViewHolder.nameText.setText(chatMessage.getName());
+ *             chatMessageViewHolder.messageText.setText(chatMessage.getMessage());
+ *         }
+ *     };
+ *     recycler.setAdapter(mAdapter);
+ * }
+ * </pre></blockquote>
+ *
+ * @param <T> The Java class that maps to the type of objects stored in the Firebase location.
+ * @param <VH> The ViewHolder class that contains the Views in the layout that is shown for each object.
+ */
+public abstract class FirebaseRecyclerAdapter<T, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
+
+    Class<T> mModelClass;
+    protected int mModelLayout;
+    Class<VH> mViewHolderClass;
+    FirebaseArray mSnapshots;
+
+    /**
+     * @param modelClass Firebase will marshall the data at a location into an instance of a class that you provide
+     * @param modelLayout This is the layout used to represent a single item in the list. You will be responsible for populating an
+     *                    instance of the corresponding view with the data from an instance of modelClass.
+     * @param viewHolderClass The class that hold references to all sub-views in an instance modelLayout.
+     * @param ref        The Firebase location to watch for data changes. Can also be a slice of a location, using some
+     *                   combination of <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code>
+     */
+    public FirebaseRecyclerAdapter(Class<T> modelClass, int modelLayout, Class<VH> viewHolderClass, Query ref) {
+        mModelClass = modelClass;
+        mModelLayout = modelLayout;
+        mViewHolderClass = viewHolderClass;
+        mSnapshots = new FirebaseArray(ref);
+
+        mSnapshots.setOnChangedListener(new FirebaseArray.OnChangedListener() {
+            @Override
+            public void onChanged(EventType type, int index, int oldIndex) {
+                switch (type) {
+                    case Added:
+                        notifyItemInserted(index);
+                        break;
+                    case Changed:
+                        notifyItemChanged(index);
+                        break;
+                    case Removed:
+                        notifyItemRemoved(index);
+                        break;
+                    case Moved:
+                        notifyItemMoved(oldIndex, index);
+                        break;
+                    default:
+                        throw new IllegalStateException("Incomplete case statement");
+                }
+            }
+        });
+    }
+
+    /**
+     * @param modelClass Firebase will marshall the data at a location into an instance of a class that you provide
+     * @param modelLayout This is the layout used to represent a single item in the list. You will be responsible for populating an
+     *                    instance of the corresponding view with the data from an instance of modelClass.
+     * @param viewHolderClass The class that hold references to all sub-views in an instance modelLayout.
+     * @param ref        The Firebase location to watch for data changes. Can also be a slice of a location, using some
+     *                   combination of <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code>
+     */
+    public FirebaseRecyclerAdapter(Class<T> modelClass, int modelLayout, Class<VH> viewHolderClass, Firebase ref) {
+        this(modelClass, modelLayout, viewHolderClass, (Query) ref);
+    }
+
+
+    public void cleanup() {
+        mSnapshots.cleanup();
+    }
+
+    @Override
+    public int getItemCount() {
+        return mSnapshots.getCount();
+    }
+
+    public T getItem(int position) {
+        return mSnapshots.getItem(position).getValue(mModelClass);
+    }
+
+    public Firebase getRef(int position) { return mSnapshots.getItem(position).getRef(); }
+
+    @Override
+    public long getItemId(int position) {
+        // http://stackoverflow.com/questions/5100071/whats-the-purpose-of-item-ids-in-android-listview-adapter
+        return mSnapshots.getItem(position).getKey().hashCode();
+    }
+
+    @Override
+    public VH onCreateViewHolder(ViewGroup parent, int viewType) {
+        ViewGroup view = (ViewGroup) LayoutInflater.from(parent.getContext()).inflate(mModelLayout, parent, false);
+        try {
+            Constructor<VH> constructor = mViewHolderClass.getConstructor(View.class);
+            return constructor.newInstance(view);
+        } catch (NoSuchMethodException e) {
+            throw new RuntimeException(e);
+        } catch (InvocationTargetException e) {
+            throw new RuntimeException(e);
+        } catch (InstantiationException e) {
+            throw new RuntimeException(e);
+        } catch (IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    @Override
+    public void onBindViewHolder(VH viewHolder, int position) {
+        T model = getItem(position);
+        populateViewHolder(viewHolder, model, position);
+    }
+
+    /**
+     * Each time the data at the given Firebase location changes, this method will be called for each item that needs
+     * to be displayed. The first two arguments correspond to the mLayout and mModelClass given to the constructor of
+     * this class. The third argument is the item's position in the list.
+     * <p>
+     * Your implementation should populate the view using the data contained in the model.
+     * You should implement either this method or the other FirebaseRecyclerAdapter#populateViewHolder(VH, Object) method
+     * but not both.
+     *
+     * @param viewHolder The view to populate
+     * @param model      The object containing the data used to populate the view
+     * @param position  The position in the list of the view being populated
+     */
+    protected void populateViewHolder(VH viewHolder, T model, int position) {
+        populateViewHolder(viewHolder, model);
+    };
+    /**
+     * This is a backwards compatible version of populateViewHolder.
+     * <p>
+     * You should implement either this method or the other FirebaseRecyclerAdapter#populateViewHolder(VH, T, int) method
+     * but not both.
+     *
+     * @see FirebaseListAdapter#populateView(View, Object, int)
+     *
+     * @param viewHolder The view to populate
+     * @param model      The object containing the data used to populate the view
+     */
+    @Deprecated
+    protected void populateViewHolder(VH viewHolder, T model) {
+    };
+
+}
diff --git a/library/src/main/java/com/firebase/ui/FirebaseRecyclerViewAdapter.java b/library/src/main/java/com/firebase/ui/FirebaseRecyclerViewAdapter.java
deleted file mode 100644
index 4d8e7b6..0000000
--- a/library/src/main/java/com/firebase/ui/FirebaseRecyclerViewAdapter.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Firebase UI Bindings Android Library
- *
- * Copyright © 2015 Firebase - All Rights Reserved
- * https://www.firebase.com
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binaryform must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY FIREBASE AS IS AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL FIREBASE BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package com.firebase.ui;
-
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.firebase.client.Firebase;
-import com.firebase.client.Query;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * This class is a generic way of backing an RecyclerView with a Firebase location.
- * It handles all of the child events at the given Firebase location. It marshals received data into the given
- * class type.
- *
- * To use this class in your app, subclass it passing in all required parameters and implement the
- * populateViewHolder method.
- *
- * <blockquote><pre>
- * {@code
- *     private static class ChatMessageViewHolder extends RecyclerView.ViewHolder {
- *         TextView messageText;
- *         TextView nameText;
- *
- *         public ChatMessageViewHolder(View itemView) {
- *             super(itemView);
- *             nameText = (TextView)itemView.findViewById(android.R.id.text1);
- *             messageText = (TextView) itemView.findViewById(android.R.id.text2);
- *         }
- *     }
- *
- *     FirebaseRecyclerViewAdapter<ChatMessage, ChatMessageViewHolder> adapter;
- *     ref = new Firebase("https://<yourapp>.firebaseio.com");
- *
- *     RecyclerView recycler = (RecyclerView) findViewById(R.id.messages_recycler);
- *     recycler.setHasFixedSize(true);
- *     recycler.setLayoutManager(new LinearLayoutManager(this));
- *
- *     adapter = new FirebaseRecyclerViewAdapter<ChatMessage, ChatMessageViewHolder>(ChatMessage.class, android.R.layout.two_line_list_item, ChatMessageViewHolder.class, mRef) {
- *         public void populateViewHolder(ChatMessageViewHolder chatMessageViewHolder, ChatMessage chatMessage) {
- *             chatMessageViewHolder.nameText.setText(chatMessage.getName());
- *             chatMessageViewHolder.messageText.setText(chatMessage.getMessage());
- *         }
- *     };
- *     recycler.setAdapter(mAdapter);
- * }
- * </pre></blockquote>
- *
- * @param <T> The Java class that maps to the type of objects stored in the Firebase location.
- * @param <VH> The ViewHolder class that contains the Views in the layout that is shown for each object.
- */
-public abstract class FirebaseRecyclerViewAdapter<T, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
-
-    Class<T> mModelClass;
-    protected int mModelLayout;
-    Class<VH> mViewHolderClass;
-    FirebaseArray mSnapshots;
-
-    /**
-     * @param modelClass Firebase will marshall the data at a location into an instance of a class that you provide
-     * @param modelLayout This is the layout used to represent a single item in the list. You will be responsible for populating an
-     *                    instance of the corresponding view with the data from an instance of modelClass.
-     * @param viewHolderClass The class that hold references to all sub-views in an instance modelLayout.
-     * @param ref        The Firebase location to watch for data changes. Can also be a slice of a location, using some
-     *                   combination of <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code>
-     */
-    public FirebaseRecyclerViewAdapter(Class<T> modelClass, int modelLayout, Class<VH> viewHolderClass, Query ref) {
-        mModelClass = modelClass;
-        mModelLayout = modelLayout;
-        mViewHolderClass = viewHolderClass;
-        mSnapshots = new FirebaseArray(ref);
-
-        mSnapshots.setOnChangedListener(new FirebaseArray.OnChangedListener() {
-            @Override
-            public void onChanged(EventType type, int index, int oldIndex) {
-                switch (type) {
-                    case Added:
-                        notifyItemInserted(index);
-                        break;
-                    case Changed:
-                        notifyItemChanged(index);
-                        break;
-                    case Removed:
-                        notifyItemRemoved(index);
-                        break;
-                    case Moved:
-                        notifyItemMoved(oldIndex, index);
-                        break;
-                    default:
-                        throw new IllegalStateException("Incomplete case statement");
-                }
-            }
-        });
-    }
-
-    /**
-     * @param modelClass Firebase will marshall the data at a location into an instance of a class that you provide
-     * @param modelLayout This is the layout used to represent a single item in the list. You will be responsible for populating an
-     *                    instance of the corresponding view with the data from an instance of modelClass.
-     * @param viewHolderClass The class that hold references to all sub-views in an instance modelLayout.
-     * @param ref        The Firebase location to watch for data changes. Can also be a slice of a location, using some
-     *                   combination of <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code>
-     */
-    public FirebaseRecyclerViewAdapter(Class<T> modelClass, int modelLayout, Class<VH> viewHolderClass, Firebase ref) {
-        this(modelClass, modelLayout, viewHolderClass, (Query) ref);
-    }
-
-
-    public void cleanup() {
-        mSnapshots.cleanup();
-    }
-
-    @Override
-    public int getItemCount() {
-        return mSnapshots.getCount();
-    }
-
-    public T getItem(int position) {
-        return mSnapshots.getItem(position).getValue(mModelClass);
-    }
-
-    public Firebase getRef(int position) { return mSnapshots.getItem(position).getRef(); }
-
-    @Override
-    public long getItemId(int position) {
-        // http://stackoverflow.com/questions/5100071/whats-the-purpose-of-item-ids-in-android-listview-adapter
-        return mSnapshots.getItem(position).getKey().hashCode();
-    }
-
-    @Override
-    public VH onCreateViewHolder(ViewGroup parent, int viewType) {
-        ViewGroup view = (ViewGroup) LayoutInflater.from(parent.getContext()).inflate(mModelLayout, parent, false);
-        try {
-            Constructor<VH> constructor = mViewHolderClass.getConstructor(View.class);
-            return constructor.newInstance(view);
-        } catch (NoSuchMethodException e) {
-            throw new RuntimeException(e);
-        } catch (InvocationTargetException e) {
-            throw new RuntimeException(e);
-        } catch (InstantiationException e) {
-            throw new RuntimeException(e);
-        } catch (IllegalAccessException e) {
-            throw new RuntimeException(e);
-        }
-    }
-    @Override
-    public void onBindViewHolder(VH viewHolder, int position) {
-        T model = getItem(position);
-        populateViewHolder(viewHolder, model, position);
-    }
-
-    /**
-     * Each time the data at the given Firebase location changes, this method will be called for each item that needs
-     * to be displayed. The first two arguments correspond to the mLayout and mModelClass given to the constructor of
-     * this class. The third argument is the item's position in the list.
-     * <p>
-     * Your implementation should populate the view using the data contained in the model.
-     * You should implement either this method or the other FirebaseRecyclerViewAdapter#populateViewHolder(VH, Object) method
-     * but not both.
-     *
-     * @param viewHolder The view to populate
-     * @param model      The object containing the data used to populate the view
-     * @param position  The position in the list of the view being populated
-     */
-    protected void populateViewHolder(VH viewHolder, T model, int position) {
-        populateViewHolder(viewHolder, model);
-    };
-    /**
-     * This is a backwards compatible version of populateViewHolder.
-     * <p>
-     * You should implement either this method or the other FirebaseRecyclerViewAdapter#populateViewHolder(VH, T, int) method
-     * but not both.
-     *
-     * @see FirebaseListAdapter#populateView(View, Object, int)
-     *
-     * @param viewHolder The view to populate
-     * @param model      The object containing the data used to populate the view
-     */
-    protected void populateViewHolder(VH viewHolder, T model) {
-    };
-
-}
diff --git a/library/src/main/java/com/firebase/ui/auth/core/FirebaseAuthHelper.java b/library/src/main/java/com/firebase/ui/auth/core/FirebaseAuthHelper.java
deleted file mode 100644
index 4424642..0000000
--- a/library/src/main/java/com/firebase/ui/auth/core/FirebaseAuthHelper.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.firebase.ui.auth.core;
-
-import android.util.Log;
-
-import com.firebase.client.AuthData;
-import com.firebase.client.Firebase;
-import com.firebase.client.FirebaseError;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public abstract class FirebaseAuthHelper {
-    public abstract void logout();
-    public abstract String getProviderName();
-    public abstract Firebase getFirebaseRef();
-
-    public void login() {
-        Log.d("FirebaseAuthHelper", "Login() is not supported for provider type " + getProviderName());
-    };
-    public void login(String email, String password) {
-        Log.d("FirebaseAuthHelper", "Login(String email, String password) is not supported for provider type " + getProviderName());
-    };
-
-    public void onFirebaseTokenReceived(FirebaseOAuthToken token, TokenAuthHandler handler) {
-        authenticateRefWithOAuthFirebasetoken(token, handler);
-    }
-
-    private void authenticateRefWithOAuthFirebasetoken(FirebaseOAuthToken token, final TokenAuthHandler handler) {
-        Log.d("Got a token", token.token);
-        Firebase.AuthResultHandler authResultHandler = new Firebase.AuthResultHandler() {
-            @Override
-            public void onAuthenticated(AuthData authData) {
-                handler.onSuccess(authData);
-            }
-
-            @Override
-            public void onAuthenticationError(FirebaseError firebaseError) {
-                handler.onProviderError(new FirebaseLoginError(FirebaseResponse.PROVIDER_NOT_ENABLED, "Make sure " + getProviderName() + " login is enabled and configured in your Firebase."));
-            }
-        };
-
-        if (token.mode == FirebaseOAuthToken.SIMPLE) {
-            // Simple mode is used for Facebook and Google auth
-            getFirebaseRef().authWithOAuthToken(token.provider, token.token, authResultHandler);
-        } else if (token.mode == FirebaseOAuthToken.COMPLEX) {
-            // Complex mode is used for Twitter auth
-            Map<String, String> options = new HashMap<>();
-            options.put("oauth_token", token.token);
-            options.put("oauth_token_secret", token.secret);
-            options.put("user_id", token.uid);
-
-            getFirebaseRef().authWithOAuthToken(token.provider, options, authResultHandler);
-        }
-    }
-}
diff --git a/library/src/main/java/com/firebase/ui/auth/core/FirebaseAuthProvider.java b/library/src/main/java/com/firebase/ui/auth/core/FirebaseAuthProvider.java
new file mode 100644
index 0000000..7db7eae
--- /dev/null
+++ b/library/src/main/java/com/firebase/ui/auth/core/FirebaseAuthProvider.java
@@ -0,0 +1,55 @@
+package com.firebase.ui.auth.core;
+
+import android.util.Log;
+
+import com.firebase.client.AuthData;
+import com.firebase.client.Firebase;
+import com.firebase.client.FirebaseError;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class FirebaseAuthProvider {
+    public abstract void logout();
+    public abstract String getProviderName();
+    public abstract Firebase getFirebaseRef();
+    public abstract SocialProvider getProviderType();
+
+    public void login() {
+        Log.d("FirebaseAuthProvider", "Login() is not supported for provider type " + getProviderName());
+    };
+    public void login(String email, String password) {
+        Log.d("FirebaseAuthProvider", "Login(String email, String password) is not supported for provider type " + getProviderName());
+    };
+
+    public void onFirebaseTokenReceived(FirebaseOAuthToken token, TokenAuthHandler handler) {
+        authenticateRefWithOAuthFirebasetoken(token, handler);
+    }
+
+    private void authenticateRefWithOAuthFirebasetoken(FirebaseOAuthToken token, final TokenAuthHandler handler) {
+        Firebase.AuthResultHandler authResultHandler = new Firebase.AuthResultHandler() {
+            @Override
+            public void onAuthenticated(AuthData authData) {
+                handler.onSuccess(authData);
+            }
+
+            @Override
+            public void onAuthenticationError(FirebaseError firebaseError) {
+                handler.onProviderError(new FirebaseLoginError(FirebaseResponse.PROVIDER_NOT_ENABLED, "Make sure " + getProviderName() + " login is enabled and configured in your Firebase."));
+            }
+        };
+
+        if (token.mode == FirebaseOAuthToken.SIMPLE) {
+            // Simple mode is used for Facebook and Google auth
+            getFirebaseRef().authWithOAuthToken(token.provider, token.token, authResultHandler);
+        } else if (token.mode == FirebaseOAuthToken.COMPLEX) {
+            // Complex mode is used for Twitter auth
+            Map<String, String> options = new HashMap<>();
+            options.put("oauth_token", token.token);
+            options.put("oauth_token_secret", token.secret);
+            options.put("user_id", token.uid);
+
+            getFirebaseRef().authWithOAuthToken(token.provider, options, authResultHandler);
+        }
+    }
+}
diff --git a/library/src/main/java/com/firebase/ui/auth/core/FirebaseLoginBaseActivity.java b/library/src/main/java/com/firebase/ui/auth/core/FirebaseLoginBaseActivity.java
index d107699..0e79d77 100644
--- a/library/src/main/java/com/firebase/ui/auth/core/FirebaseLoginBaseActivity.java
+++ b/library/src/main/java/com/firebase/ui/auth/core/FirebaseLoginBaseActivity.java
@@ -14,13 +14,34 @@
     private FirebaseLoginDialog mDialog;
     private TokenAuthHandler mHandler;
 
-    /* Abstract methods for Login Events */
+    /**
+     * Subclasses of this activity may implement this method to handle when a user logs in.
+     *
+     * @return void
+     */
     protected abstract void onFirebaseLoggedIn(AuthData authData);
 
+    /**
+     * Subclasses of this activity may implement this method to handle when a user logs out.
+     *
+     * @return void
+     */
     protected abstract void onFirebaseLoggedOut();
 
+    /**
+     * Subclasses of this activity may implement this method to handle any potential provider errors
+     * like OAuth or other internal errors.
+     *
+     * @return void
+     */
     protected abstract void onFirebaseLoginProviderError(FirebaseLoginError firebaseError);
 
+    /**
+     * Subclasses of this activity may implement this method to handle any potential user errors
+     * like entering an incorrect password or closing the login dialog.
+     *
+     * @return void
+     */
     protected abstract void onFirebaseLoginUserError(FirebaseLoginError firebaseError);
 
     /**
@@ -93,7 +114,7 @@ public void onAuthStateChanged(AuthData authData) {
     }
 
     public void setEnabledAuthProvider(SocialProvider provider) {
-        mDialog.setProviderEnabled(provider);
+        mDialog.setEnabledProvider(provider);
     }
 
     protected void onStop() {
diff --git a/library/src/main/java/com/firebase/ui/auth/core/FirebaseLoginDialog.java b/library/src/main/java/com/firebase/ui/auth/core/FirebaseLoginDialog.java
index 491625d..83f0042 100644
--- a/library/src/main/java/com/firebase/ui/auth/core/FirebaseLoginDialog.java
+++ b/library/src/main/java/com/firebase/ui/auth/core/FirebaseLoginDialog.java
@@ -25,6 +25,7 @@
     GoogleAuthProvider mGoogleAuthProvider;
     PasswordAuthProvider mPasswordAuthProvider;
     TokenAuthHandler mHandler;
+    SocialProvider mActiveProvider;
     Firebase mRef;
     Context mContext;
     View mView;
@@ -34,6 +35,12 @@ public void onStart() {
         if (mGoogleAuthProvider != null) mGoogleAuthProvider.onStart();
     }
 
+
+    /*
+    We need to be extra aggressive about building / destroying mGoogleauthProviders so we don't
+    end up with two clients connected at the same time.
+     */
+
     public void onStop() {
         super.onStop();
         if (mGoogleAuthProvider != null) mGoogleAuthProvider.onStop();
@@ -45,15 +52,15 @@ public void onDestroy() {
     }
 
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (mFacebookAuthProvider != null) {
+        if (mFacebookAuthProvider != null && mActiveProvider == SocialProvider.facebook) {
             mFacebookAuthProvider.mCallbackManager.onActivityResult(requestCode, resultCode, data);
         }
 
-        if (mTwitterAuthProvider != null) {
+        if (mTwitterAuthProvider != null && mActiveProvider == SocialProvider.twitter) {
             mTwitterAuthProvider.onActivityResult(requestCode, resultCode, data);
         }
 
-        if (mGoogleAuthProvider != null) {
+        if (mGoogleAuthProvider != null && mActiveProvider == SocialProvider.google) {
             mGoogleAuthProvider.onActivityResult(requestCode, resultCode, data);
         }
     }
@@ -103,10 +110,20 @@ public void reset() {
     }
 
     public void logout() {
-        if (mFacebookAuthProvider != null) mFacebookAuthProvider.logout();
-        if (mGoogleAuthProvider != null) mGoogleAuthProvider.logout();
-        if (mTwitterAuthProvider != null) mTwitterAuthProvider.logout();
-        if (mPasswordAuthProvider != null) mPasswordAuthProvider.logout();
+        switch (mActiveProvider) {
+            case twitter:
+                mTwitterAuthProvider.logout();
+                break;
+            case facebook:
+                mFacebookAuthProvider.logout();
+                break;
+            case google:
+                mGoogleAuthProvider.logout();
+                break;
+            case password:
+                mPasswordAuthProvider.logout();
+                break;
+        }
         mRef.unauth();
     }
 
@@ -133,7 +150,7 @@ public void onProviderError(FirebaseLoginError err) {
         return this;
     }
 
-    public FirebaseLoginDialog setProviderEnabled(SocialProvider provider) {
+    public FirebaseLoginDialog setEnabledProvider(SocialProvider provider) {
         switch (provider) {
             case facebook:
                 if (mFacebookAuthProvider == null)
@@ -156,11 +173,11 @@ public FirebaseLoginDialog setProviderEnabled(SocialProvider provider) {
         return this;
     }
 
-    private void showLoginOption(final FirebaseAuthHelper helper, int id) {
+    private void showLoginOption(final FirebaseAuthProvider helper, int id) {
         mView.findViewById(id).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View view) {
-                if (helper.getProviderName().equals("password")) {
+                if (helper.getProviderType() == SocialProvider.password) {
                     EditText emailText = (EditText) mView.findViewById(R.id.email);
                     EditText passwordText = (EditText) mView.findViewById(R.id.password);
                     helper.login(emailText.getText().toString(), passwordText.getText().toString());
@@ -169,6 +186,7 @@ public void onClick(View view) {
                 } else {
                     helper.login();
                 }
+                mActiveProvider = helper.getProviderType();
                 mView.findViewById(R.id.login_section).setVisibility(View.GONE);
                 mView.findViewById(R.id.loading_section).setVisibility(View.VISIBLE);
             }
diff --git a/library/src/main/java/com/firebase/ui/auth/facebook/FacebookAuthProvider.java b/library/src/main/java/com/firebase/ui/auth/facebook/FacebookAuthProvider.java
index be55220..0283339 100644
--- a/library/src/main/java/com/firebase/ui/auth/facebook/FacebookAuthProvider.java
+++ b/library/src/main/java/com/firebase/ui/auth/facebook/FacebookAuthProvider.java
@@ -15,18 +15,20 @@
 import com.facebook.login.LoginManager;
 import com.facebook.login.LoginResult;
 import com.firebase.client.Firebase;
-import com.firebase.ui.auth.core.FirebaseAuthHelper;
+import com.firebase.ui.auth.core.FirebaseAuthProvider;
 import com.firebase.ui.auth.core.FirebaseResponse;
 import com.firebase.ui.auth.core.FirebaseLoginError;
 import com.firebase.ui.auth.core.FirebaseOAuthToken;
+import com.firebase.ui.auth.core.SocialProvider;
 import com.firebase.ui.auth.core.TokenAuthHandler;
 
 import java.util.Arrays;
 import java.util.Collection;
 
-public class FacebookAuthProvider extends FirebaseAuthHelper {
+public class FacebookAuthProvider extends FirebaseAuthProvider {
 
     public static final String PROVIDER_NAME = "facebook";
+    public static final SocialProvider PROVIDER_TYPE = SocialProvider.facebook;
     private final String TAG = "FacebookAuthProvider";
     public CallbackManager mCallbackManager;
     private LoginManager mLoginManager;
@@ -102,10 +104,8 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
         mCallbackManager.onActivityResult(requestCode, resultCode, data);
     }
 
-    public String getProviderName() {
-        return PROVIDER_NAME;
-    }
-
+    public String getProviderName() { return PROVIDER_NAME; }
+    public SocialProvider getProviderType() { return PROVIDER_TYPE; };
     public Firebase getFirebaseRef() {return mRef; }
 
     public void logout() {
diff --git a/library/src/main/java/com/firebase/ui/auth/google/GoogleAuthProvider.java b/library/src/main/java/com/firebase/ui/auth/google/GoogleAuthProvider.java
index 8ee1baa..3235351 100644
--- a/library/src/main/java/com/firebase/ui/auth/google/GoogleAuthProvider.java
+++ b/library/src/main/java/com/firebase/ui/auth/google/GoogleAuthProvider.java
@@ -7,13 +7,13 @@
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.support.v4.app.FragmentActivity;
-import android.util.Log;
 
 import com.firebase.client.Firebase;
-import com.firebase.ui.auth.core.FirebaseAuthHelper;
+import com.firebase.ui.auth.core.FirebaseAuthProvider;
 import com.firebase.ui.auth.core.FirebaseLoginError;
 import com.firebase.ui.auth.core.FirebaseOAuthToken;
 import com.firebase.ui.auth.core.FirebaseResponse;
+import com.firebase.ui.auth.core.SocialProvider;
 import com.firebase.ui.auth.core.TokenAuthHandler;
 import com.google.android.gms.auth.api.Auth;
 import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
@@ -24,11 +24,12 @@
 import com.google.android.gms.common.api.ResultCallback;
 import com.google.android.gms.common.api.Status;
 
-public class GoogleAuthProvider extends FirebaseAuthHelper implements
+public class GoogleAuthProvider extends FirebaseAuthProvider implements
         GoogleApiClient.OnConnectionFailedListener,
         GoogleOAuthTaskHandler {
 
     public final static String PROVIDER_NAME = "google";
+    public static final SocialProvider PROVIDER_TYPE = SocialProvider.google;
     private static final int RC_SIGN_IN = 9001;
     private final String TAG = "GoogleAuthProvider";
     private GoogleApiClient mGoogleApiClient;
@@ -79,6 +80,7 @@ public GoogleAuthProvider(Context context, Firebase ref, TokenAuthHandler handle
 
     public String getProviderName() { return PROVIDER_NAME; }
     public Firebase getFirebaseRef() { return mRef; }
+    public SocialProvider getProviderType() { return PROVIDER_TYPE; };
 
     public void logout() {
         Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
diff --git a/library/src/main/java/com/firebase/ui/auth/password/PasswordAuthProvider.java b/library/src/main/java/com/firebase/ui/auth/password/PasswordAuthProvider.java
index b6cd907..72cfdea 100644
--- a/library/src/main/java/com/firebase/ui/auth/password/PasswordAuthProvider.java
+++ b/library/src/main/java/com/firebase/ui/auth/password/PasswordAuthProvider.java
@@ -6,16 +6,18 @@
 import com.firebase.client.AuthData;
 import com.firebase.client.Firebase;
 import com.firebase.client.FirebaseError;
-import com.firebase.ui.auth.core.FirebaseAuthHelper;
+import com.firebase.ui.auth.core.FirebaseAuthProvider;
 import com.firebase.ui.auth.core.FirebaseResponse;
 import com.firebase.ui.auth.core.FirebaseLoginError;
+import com.firebase.ui.auth.core.SocialProvider;
 import com.firebase.ui.auth.core.TokenAuthHandler;
 
-public class PasswordAuthProvider extends FirebaseAuthHelper {
+public class PasswordAuthProvider extends FirebaseAuthProvider {
 
     private final String LOG_TAG = "PasswordAuthProvider";
 
     public final static String PROVIDER_NAME = "password";
+    public final static SocialProvider PROVIDER_TYPE = SocialProvider.password;
 
     private TokenAuthHandler mHandler;
     private Activity mActivity;
@@ -42,5 +44,6 @@ public void onAuthenticationError(FirebaseError firebaseError) {
 
     public String getProviderName() { return PROVIDER_NAME; }
     public Firebase getFirebaseRef() { return mRef; }
+    public SocialProvider getProviderType() { return PROVIDER_TYPE; };
     public void logout() {}
 }
diff --git a/library/src/main/java/com/firebase/ui/auth/twitter/TwitterAuthProvider.java b/library/src/main/java/com/firebase/ui/auth/twitter/TwitterAuthProvider.java
index 5c6fdd3..8d21ed3 100644
--- a/library/src/main/java/com/firebase/ui/auth/twitter/TwitterAuthProvider.java
+++ b/library/src/main/java/com/firebase/ui/auth/twitter/TwitterAuthProvider.java
@@ -5,15 +5,17 @@
 import android.content.Intent;
 
 import com.firebase.client.Firebase;
-import com.firebase.ui.auth.core.FirebaseAuthHelper;
+import com.firebase.ui.auth.core.FirebaseAuthProvider;
 import com.firebase.ui.auth.core.FirebaseLoginError;
 import com.firebase.ui.auth.core.FirebaseOAuthToken;
+import com.firebase.ui.auth.core.SocialProvider;
 import com.firebase.ui.auth.core.TokenAuthHandler;
 
-public class TwitterAuthProvider extends FirebaseAuthHelper {
+public class TwitterAuthProvider extends FirebaseAuthProvider {
 
     public static final String TAG = "TwitterAuthProvider";
     public static final String PROVIDER_NAME = "twitter";
+    public static final SocialProvider PROVIDER_TYPE = SocialProvider.twitter;
 
     private Activity mActivity;
     private TokenAuthHandler mHandler;
@@ -35,6 +37,7 @@ public void logout() {
 
     public String getProviderName() { return PROVIDER_NAME; }
     public Firebase getFirebaseRef() { return mRef; }
+    public SocialProvider getProviderType() { return PROVIDER_TYPE; };
 
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (resultCode == TwitterActions.SUCCESS) {
