├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── google-services.json ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── ezhome │ │ └── rxfirebasedemo │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── ezhome │ │ │ └── rxfirebasedemo │ │ │ ├── BaseApplication.java │ │ │ ├── BlogPostViewHolder.java │ │ │ ├── BlogPostsAdapter.java │ │ │ ├── MainActivity.java │ │ │ ├── PostsFragment.java │ │ │ └── model │ │ │ └── BlogPostEntity.java │ └── res │ │ ├── layout │ │ ├── activity_layout.xml │ │ ├── fragment_posts.xml │ │ └── row_post.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── ezhome │ └── rxfirebasedemo │ └── ExampleUnitTest.java ├── build.gradle ├── circle.yml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── rxfirebase ├── .gitignore ├── build.gradle ├── buildsystem │ ├── dependencies.gradle │ ├── publish.gradle │ └── version.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── ezhome │ │ └── rxfirebase2 │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── ezhome │ │ └── rxfirebase2 │ │ ├── FirebaseChildEvent.java │ │ ├── FirebaseDatabaseNodes.java │ │ ├── auth │ │ ├── FirebaseAuthErrorFactory.java │ │ └── RxFirebaseAuth.java │ │ ├── database │ │ ├── FirebaseDatabaseErrorFactory.java │ │ └── RxFirebaseDatabase.java │ │ └── exception │ │ ├── FirebaseAuthProviderDisabledException.java │ │ ├── FirebaseDisconnectedException.java │ │ ├── FirebaseExpiredTokenException.java │ │ ├── FirebaseGeneralException.java │ │ ├── FirebaseInvalidTokenException.java │ │ ├── FirebaseNetworkErrorException.java │ │ ├── FirebaseOperationFailedException.java │ │ ├── FirebasePermissionDeniedException.java │ │ ├── FirebaseSignInException.java │ │ └── FirebaseSignOutException.java │ └── test │ └── java │ └── com │ └── ezhome │ └── rxfirebase2 │ ├── ApplicationStub.java │ ├── ApplicationTestCase.java │ ├── RxFirebaseAuthTest.java │ └── RxFirebaseDatabaseTest.java ├── server ├── database.rules.json └── sample-data.json └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](http://www.apache.org/licenses/LICENSE-2.0) [![Platform](https://img.shields.io/badge/platform-android-green.svg)](http://developer.android.com/index.html) 2 | [ ![Download](https://api.bintray.com/packages/ezhome/maven/rxfirebase/images/download.svg) ](https://bintray.com/ezhome/maven/rxfirebase/_latestVersion) 3 | [![CircleCI](https://circleci.com/gh/ezhome/Android-RxFirebase.svg?style=shield)](https://circleci.com/gh/ezhome/Android-RxFirebase) 4 | 5 | # RxFirebase 6 | 7 | RxJava implementation by ezhome for the Android [Firebase client](https://www.firebase.com/docs/android/). 8 | 9 | ---- 10 | Contents 11 | -------- 12 | - [Usage](#usage) 13 | - [Download](#download) 14 | - [Tests](#tests) 15 | - [Code style](#code-style) 16 | - [License](#license) 17 | 18 | Usage 19 | ----- 20 | 21 | Currently library supports for new Google Firebase the followings: 22 | - Firebase Authentication `RxFirebaseAuth` 23 | - Firebase Database `RxFirebaseDatabase` 24 | 25 | #### Use the project with your own Firebase instance 26 | 27 | 1. Clone this repository. 28 | - Create a new project in the [Firebase console](https://console.firebase.google.com/). 29 | - Click *Add Firebase to your Android app* 30 | * provide a **unique package name** 31 | * use the same package name for the **applicationId** in your `build.gradle` 32 | * insert SHA-1 fingerprint of your debug certificate, otherwise you won't be able to log in 33 | - Copy the generated *google-services.json* to the `app` folder of your project which will replace the mock google services json file. 34 | - You should be able to successfully sync the project now. 35 | - Copy contents of the `./server/database.rules.json` into your *Firebase -> Database -> Rules* and publish them. 36 | - Import data `./server/sample-data.json` into your *Firebase -> Database* 37 | - Change the *Firebase URL path* in this [file](https://github.com/ezhome/Android-RxFirebase/blob/master/app/src/main/java/com/ezhome/rxfirebasedemo/PostsFragment.java#L30) 38 | - Build and run the app. 39 | 40 | #### Example 41 | 42 | ```java 43 | final Firebase firebaseRef = new Firebase("https://docs-examples.firebaseio.com/web/saving-data/fireblog/posts"); 44 | RxFirebaseDatabase.getInstance().observeValueEvent(firebaseRef).subscribe(new GetPostsSubscriber()); 45 | 46 | private final class GetPostsSubscriber extends Subscriber { 47 | @Override public void onCompleted() { 48 | PostsFragment.this.showProgress(false); 49 | } 50 | 51 | @Override public void onError(Throwable e) { 52 | PostsFragment.this.showProgress(false); 53 | PostsFragment.this.showError(e.getMessage()); 54 | } 55 | 56 | @SuppressWarnings("unchecked") @Override public void onNext(DataSnapshot dataSnapshot) { 57 | List blogPostEntities = new ArrayList<>(); 58 | for (DataSnapshot childDataSnapshot : dataSnapshot.getChildren()) { 59 | blogPostEntities.add(childDataSnapshot.getValue(BlogPostEntity.class)); 60 | } 61 | PostsFragment.this.renderBlogPosts(blogPostEntities); 62 | } 63 | } 64 | ``` 65 | 66 | Check the example application [here](https://github.com/ezhome/Android-RxFirebase/tree/master/app) 67 | 68 | You can change scheduler for observing values in a different thread 69 | 70 | #### Example 71 | ``` 72 | RxFirebaseDatabase.getInstance().observeOn(Schedulers.io()); 73 | ``` 74 | Download 75 | -------- 76 | The project is available on jCenter. In your app build.gradle (or explicit module) you must add this: 77 | ``` 78 | dependencies { 79 | compile 'com.ezhome:rxfirebase:2.2.0' 80 | } 81 | ``` 82 | 83 | 84 | Tests 85 | ----- 86 | 87 | Tests are available in `rxfirebase/src/test/java/` directory and can be executed from Android Studio or CLI with the following command: 88 | 89 | ``` 90 | ./gradlew test 91 | ``` 92 | 93 | Code style 94 | ---------- 95 | 96 | Code style used in the project is called `SquareAndroid` from Java Code Styles repository by Square available at: https://github.com/square/java-code-styles. 97 | 98 | 99 | License 100 | ------- 101 | 102 | Copyright 2016 Ezhome Inc. 103 | 104 | Licensed under the Apache License, Version 2.0 (the "License"); 105 | you may not use this file except in compliance with the License. 106 | You may obtain a copy of the License at 107 | 108 | http://www.apache.org/licenses/LICENSE-2.0 109 | 110 | Unless required by applicable law or agreed to in writing, software 111 | distributed under the License is distributed on an "AS IS" BASIS, 112 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 113 | See the License for the specific language governing permissions and 114 | limitations under the License. -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .idea -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'android-apt' 3 | 4 | android { 5 | 6 | packagingOptions { 7 | exclude 'META-INF/rxjava.properties' 8 | } 9 | compileSdkVersion 25 10 | buildToolsVersion "25.0.3" 11 | 12 | defaultConfig { 13 | applicationId "com.ezhome.rxfirebasedemo" 14 | minSdkVersion 16 15 | targetSdkVersion 25 16 | versionCode 1 17 | versionName "1.0" 18 | 19 | multiDexEnabled true 20 | } 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | lintOptions { 28 | abortOnError false 29 | } 30 | } 31 | 32 | dependencies { 33 | compile 'com.android.support:appcompat-v7:25.3.1' 34 | //butterknife 35 | compile 'com.jakewharton:butterknife:8.4.0' 36 | apt 'com.jakewharton:butterknife-compiler:8.4.0' 37 | //recyclerview 38 | compile 'com.android.support:recyclerview-v7:25.3.1' 39 | compile 'com.android.support:multidex:1.0.1' 40 | compile 'com.google.firebase:firebase-core:11.0.0' 41 | 42 | compile project(':rxfirebase') 43 | 44 | testCompile 'junit:junit:4.12' 45 | } 46 | 47 | apply plugin: 'com.google.gms.google-services' 48 | -------------------------------------------------------------------------------- /app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "262311498471", 4 | "firebase_url": "https://fir-quickstarts-a6494.firebaseio.com", 5 | "project_id": "fir-quickstarts-a6494", 6 | "storage_bucket": "fir-quickstarts-a6494.appspot.com" 7 | }, 8 | "client": [ 9 | { 10 | "client_info": { 11 | "mobilesdk_app_id": "1:262311498471:android:c0c5789ae7945b59", 12 | "android_client_info": { 13 | "package_name": "com.ezhome.rxfirebasedemo" 14 | } 15 | }, 16 | "oauth_client": [ 17 | { 18 | "client_id": "262311498471-hu6pjbbkammkje369mpsslg849jtgmkq.apps.googleusercontent.com", 19 | "client_type": 3 20 | } 21 | ], 22 | "api_key": [ 23 | { 24 | "current_key": "AIzaSyCAWOuIzhXl9WHsIQkDMO537Xn7moH_ICg" 25 | } 26 | ], 27 | "services": { 28 | "analytics_service": { 29 | "status": 1 30 | }, 31 | "appinvite_service": { 32 | "status": 1, 33 | "other_platform_oauth_client": [] 34 | }, 35 | "ads_service": { 36 | "status": 2 37 | } 38 | } 39 | } 40 | ], 41 | "configuration_version": "1" 42 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/admin/Work/devtools/adt-bundle-mac-x86_64-20140624/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/ezhome/rxfirebasedemo/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.ezhome.rxfirebasedemo; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/ezhome/rxfirebasedemo/BaseApplication.java: -------------------------------------------------------------------------------- 1 | package com.ezhome.rxfirebasedemo; 2 | 3 | import android.support.multidex.MultiDexApplication; 4 | import com.google.firebase.database.FirebaseDatabase; 5 | 6 | /** 7 | * Base application 8 | */ 9 | public class BaseApplication extends MultiDexApplication { 10 | 11 | @Override public void onCreate() { 12 | super.onCreate(); 13 | FirebaseDatabase.getInstance().setPersistenceEnabled(true); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/ezhome/rxfirebasedemo/BlogPostViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.ezhome.rxfirebasedemo; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.ViewGroup; 5 | import android.widget.TextView; 6 | import butterknife.BindView; 7 | import butterknife.ButterKnife; 8 | import com.ezhome.rxfirebasedemo.model.BlogPostEntity; 9 | 10 | import static android.view.View.inflate; 11 | 12 | /** 13 | * The view holder for an item 14 | */ 15 | public class BlogPostViewHolder extends RecyclerView.ViewHolder { 16 | 17 | @BindView(R.id.postsTitle) TextView postsTitle; 18 | @BindView(R.id.postsAuthor) TextView postsAuthor; 19 | 20 | public BlogPostViewHolder(ViewGroup parent) { 21 | super(inflate(parent.getContext(), R.layout.row_post, null)); 22 | ButterKnife.bind(this, itemView); 23 | } 24 | 25 | public void bindModel(BlogPostEntity entity) { 26 | if (entity == null) { 27 | throw new IllegalArgumentException("Entity cannot be null"); 28 | } 29 | this.postsTitle.setText(entity.getTitle()); 30 | this.postsAuthor.setText(entity.getAuthor()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/ezhome/rxfirebasedemo/BlogPostsAdapter.java: -------------------------------------------------------------------------------- 1 | package com.ezhome.rxfirebasedemo; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.ViewGroup; 5 | import com.ezhome.rxfirebasedemo.model.BlogPostEntity; 6 | import java.util.List; 7 | 8 | /** 9 | * The {@link RecyclerView.Adapter} with a {@link List} of {@link BlogPostEntity} 10 | */ 11 | class BlogPostsAdapter extends RecyclerView.Adapter { 12 | 13 | private List blogPostEntities; 14 | 15 | public BlogPostsAdapter(List blogPostEntities) { 16 | this.blogPostEntities = blogPostEntities; 17 | } 18 | 19 | @Override public BlogPostViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 20 | return new BlogPostViewHolder(parent); 21 | } 22 | 23 | @Override public void onBindViewHolder(BlogPostViewHolder holder, int position) { 24 | BlogPostEntity blogPostEntity = blogPostEntities.get(position); 25 | holder.bindModel(blogPostEntity); 26 | } 27 | 28 | @Override public int getItemCount() { 29 | return blogPostEntities.size(); 30 | } 31 | 32 | /** 33 | * Sets the data for adapter 34 | * 35 | * @param blogPostEntities a {@link List} of {@link BlogPostEntity} 36 | */ 37 | public void setData(List blogPostEntities) { 38 | this.validateData(blogPostEntities); 39 | this.blogPostEntities = blogPostEntities; 40 | this.notifyDataSetChanged(); 41 | } 42 | 43 | /** 44 | * Validates the data 45 | * 46 | * @param blogPostEntities a {@link List} of {@link BlogPostEntity} 47 | */ 48 | public void validateData(List blogPostEntities) { 49 | if (blogPostEntities == null) { 50 | throw new IllegalArgumentException("The list cannot be null"); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/ezhome/rxfirebasedemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.ezhome.rxfirebasedemo; 2 | 3 | import android.support.v4.app.FragmentTransaction; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | 7 | /** 8 | * The {@link AppCompatActivity} for the main screen 9 | */ 10 | public class MainActivity extends AppCompatActivity { 11 | 12 | @Override protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_layout); 15 | 16 | final FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); 17 | fragmentTransaction.add(R.id.fragmentContainer, PostsFragment.newInstance()); 18 | fragmentTransaction.commit(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/ezhome/rxfirebasedemo/PostsFragment.java: -------------------------------------------------------------------------------- 1 | package com.ezhome.rxfirebasedemo; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.ProgressBar; 12 | import android.widget.Toast; 13 | import butterknife.BindView; 14 | import butterknife.ButterKnife; 15 | import com.ezhome.rxfirebase2.database.RxFirebaseDatabase; 16 | import com.ezhome.rxfirebasedemo.model.BlogPostEntity; 17 | import com.google.firebase.database.DataSnapshot; 18 | import com.google.firebase.database.DatabaseReference; 19 | import com.google.firebase.database.FirebaseDatabase; 20 | import java.util.ArrayList; 21 | import java.util.Collections; 22 | import java.util.List; 23 | import rx.Subscriber; 24 | 25 | /** 26 | * The {@link Fragment} to show a list with posts 27 | */ 28 | public class PostsFragment extends Fragment { 29 | 30 | //For example purposes 31 | private final DatabaseReference firebaseRef = FirebaseDatabase.getInstance().getReference(); 32 | 33 | //Adapter 34 | private BlogPostsAdapter blogPostsAdapter; 35 | 36 | @BindView(R.id.rvPostsList) RecyclerView rvPostsList; 37 | @BindView(R.id.progressBar) ProgressBar progressBar; 38 | 39 | /** 40 | * Factory method to instantiate Fragment 41 | * 42 | * @return {@link PostsFragment} 43 | */ 44 | public static PostsFragment newInstance() { 45 | return new PostsFragment(); 46 | } 47 | 48 | @Nullable @Override 49 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, 50 | @Nullable Bundle savedInstanceState) { 51 | View fragmentView = inflater.inflate(R.layout.fragment_posts, container, false); 52 | ButterKnife.bind(this, fragmentView); 53 | return fragmentView; 54 | } 55 | 56 | @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 57 | super.onViewCreated(view, savedInstanceState); 58 | this.blogPostsAdapter = new BlogPostsAdapter(Collections.emptyList()); 59 | this.rvPostsList.setLayoutManager(new LinearLayoutManager(getContext())); 60 | this.rvPostsList.setAdapter(blogPostsAdapter); 61 | this.loadPosts(); 62 | } 63 | 64 | /** 65 | * Load the posts 66 | */ 67 | private void loadPosts() { 68 | PostsFragment.this.showProgress(true); 69 | RxFirebaseDatabase.getInstance().observeValueEvent(firebaseRef.child("fireblog")).subscribe(new GetPostsSubscriber()); 70 | } 71 | 72 | /** 73 | * Renders in UI the available {@link BlogPostEntity} 74 | * 75 | * @param blogPostEntities {@link List} of {@link BlogPostEntity} 76 | */ 77 | private void renderBlogPosts(List blogPostEntities) { 78 | this.showProgress(false); 79 | this.blogPostsAdapter.setData(blogPostEntities); 80 | } 81 | 82 | /** 83 | * Shows the progress bar 84 | * 85 | * @param isVisible {@link Boolean} VISIBLE: true | INVISIBLE: false 86 | */ 87 | private void showProgress(boolean isVisible) { 88 | this.progressBar.clearAnimation(); 89 | this.progressBar.setVisibility(isVisible ? View.VISIBLE : View.GONE); 90 | this.getActivity().setProgressBarIndeterminateVisibility(isVisible); 91 | } 92 | 93 | /** 94 | * Shows the error in UI 95 | * 96 | * @param message {@link String} the error message 97 | */ 98 | private void showError(String message) { 99 | Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show(); 100 | } 101 | 102 | /** 103 | * Subscriber for {@link RxFirebaseDatabase} query 104 | */ 105 | private final class GetPostsSubscriber extends Subscriber { 106 | @Override public void onCompleted() { 107 | PostsFragment.this.showProgress(false); 108 | } 109 | 110 | @Override public void onError(Throwable e) { 111 | PostsFragment.this.showProgress(false); 112 | PostsFragment.this.showError(e.getMessage()); 113 | } 114 | 115 | @SuppressWarnings("unchecked") @Override public void onNext(DataSnapshot dataSnapshot) { 116 | List blogPostEntities = new ArrayList<>(); 117 | for (DataSnapshot childDataSnapshot : dataSnapshot.getChildren()) { 118 | blogPostEntities.add(childDataSnapshot.getValue(BlogPostEntity.class)); 119 | } 120 | PostsFragment.this.renderBlogPosts(blogPostEntities); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/ezhome/rxfirebasedemo/model/BlogPostEntity.java: -------------------------------------------------------------------------------- 1 | package com.ezhome.rxfirebasedemo.model; 2 | 3 | /** 4 | * The entity for blog posts 5 | */ 6 | public class BlogPostEntity { 7 | 8 | private String author; 9 | 10 | private String title; 11 | 12 | public BlogPostEntity() { 13 | } 14 | 15 | public String getAuthor() { 16 | return author; 17 | } 18 | 19 | public void setAuthor(String author) { 20 | this.author = author; 21 | } 22 | 23 | public String getTitle() { 24 | return title; 25 | } 26 | 27 | public void setTitle(String title) { 28 | this.title = title; 29 | } 30 | 31 | @Override public String toString() { 32 | final StringBuilder sb = new StringBuilder("BlogPost{"); 33 | sb.append("author='"); 34 | sb.append(author).append('\''); 35 | sb.append(", title='"); 36 | sb.append(title); 37 | sb.append('\''); 38 | sb.append('}'); 39 | return sb.toString(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_posts.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 12 | 13 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/row_post.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezhome/Android-RxFirebase/c54e18928032359f2b4bc85fa437e4adfbc76b94/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezhome/Android-RxFirebase/c54e18928032359f2b4bc85fa437e4adfbc76b94/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezhome/Android-RxFirebase/c54e18928032359f2b4bc85fa437e4adfbc76b94/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezhome/Android-RxFirebase/c54e18928032359f2b4bc85fa437e4adfbc76b94/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezhome/Android-RxFirebase/c54e18928032359f2b4bc85fa437e4adfbc76b94/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Example 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/test/java/com/ezhome/rxfirebasedemo/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.ezhome.rxfirebasedemo; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test public void addition_isCorrect() throws Exception { 12 | assertEquals(4, 2 + 2); 13 | } 14 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | dependencies { 6 | classpath 'com.android.tools.build:gradle:2.3.3' 7 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' 8 | classpath 'com.google.gms:google-services:3.1.0' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | jcenter() 15 | } 16 | } 17 | 18 | task clean(type: Delete) { 19 | delete rootProject.buildDir 20 | } 21 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | java: 3 | version: oraclejdk8 4 | environment: 5 | ADB_INSTALL_TIMEOUT: "10" 6 | 7 | dependencies: 8 | pre: 9 | - echo y | android update sdk --no-ui --all --filter tools 10 | - echo y | android update sdk --no-ui --all --filter android-23,android-25,build-tools-25.0.3 11 | - echo y | android update sdk --no-ui --all --filter extra-google-m2repository,extra-android-m2repository 12 | - chmod +x gradlew 13 | 14 | test: 15 | override: 16 | - ./gradlew clean check 17 | - ./gradlew assembleRelease 18 | # run tests 19 | - ./gradlew test -PdisablePreDex 20 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezhome/Android-RxFirebase/c54e18928032359f2b4bc85fa437e4adfbc76b94/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 09 15:29:37 EEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /rxfirebase/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .idea -------------------------------------------------------------------------------- /rxfirebase/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | dependencies { 6 | classpath 'com.novoda:bintray-release:0.3.4' 7 | } 8 | } 9 | 10 | apply plugin: 'com.android.library' 11 | apply from: 'buildsystem/dependencies.gradle' 12 | apply from: 'buildsystem/version.gradle' 13 | apply plugin: 'com.novoda.bintray-release' 14 | apply from: 'buildsystem/publish.gradle' 15 | 16 | android { 17 | 18 | packagingOptions { 19 | exclude 'META-INF/LICENSE' 20 | exclude 'META-INF/LICENSE-FIREBASE.txt' 21 | exclude 'META-INF/NOTICE' 22 | exclude 'META-INF/rxjava.properties' 23 | } 24 | 25 | def globalConfiguration = project.extensions.getByName("ext") 26 | 27 | compileSdkVersion globalConfiguration.getAt("androidCompileSdkVersion") 28 | buildToolsVersion globalConfiguration.getAt("androidBuildToolsVersion") 29 | 30 | defaultConfig { 31 | minSdkVersion globalConfiguration.getAt("androidMinSdkVersion") 32 | targetSdkVersion globalConfiguration.getAt("androidTargetSdkVersion") 33 | versionCode globalConfiguration.getAt("versionCode") 34 | versionName globalConfiguration.getAt("versionName") 35 | } 36 | 37 | compileOptions { 38 | sourceCompatibility JavaVersion.VERSION_1_7 39 | targetCompatibility JavaVersion.VERSION_1_7 40 | } 41 | 42 | 43 | buildTypes { 44 | release { 45 | minifyEnabled false 46 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 47 | } 48 | } 49 | lintOptions { 50 | abortOnError false 51 | } 52 | } 53 | 54 | tasks.withType(Test) { 55 | testLogging { 56 | events "started", "passed", "skipped", "failed" 57 | } 58 | } 59 | 60 | dependencies { 61 | def libraryDependencies = project.ext.libraryDependencies 62 | def libraryTestDependencies = project.ext.libraryTestDependencies 63 | 64 | //Data 65 | compile libraryDependencies.firebaseDatabase 66 | compile libraryDependencies.firebaseAuth 67 | 68 | //Rx 69 | compile libraryDependencies.rxJava 70 | 71 | testCompile libraryTestDependencies.mockito 72 | testCompile libraryTestDependencies.junit 73 | testCompile libraryTestDependencies.robolectric 74 | testCompile libraryTestDependencies.assertj 75 | } 76 | -------------------------------------------------------------------------------- /rxfirebase/buildsystem/dependencies.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | // Android versions 3 | androidMinSdkVersion = 16 4 | androidTargetSdkVersion = 25 5 | androidCompileSdkVersion = 25 6 | androidBuildToolsVersion = '25.0.3' 7 | 8 | //Firebase 9 | firebaseVersion = '11.0.0' 10 | 11 | //RxJava 12 | rxJavaVersion = '1.3.3' 13 | 14 | //Test 15 | jUnitVersion = '4.12' 16 | robolectricVersion = '3.1.2' 17 | assertJVersion = '1.7.1' 18 | mockitoVersion = '1.9.5' 19 | 20 | libraryDependencies = [ 21 | firebaseDatabase: "com.google.firebase:firebase-database:${firebaseVersion}", 22 | firebaseAuth: "com.google.firebase:firebase-auth:${firebaseVersion}", 23 | rxJava: "io.reactivex:rxjava:${rxJavaVersion}", 24 | ] 25 | 26 | libraryTestDependencies = [ 27 | junit: "junit:junit:${jUnitVersion}", 28 | mockito: "org.mockito:mockito-core:${mockitoVersion}", 29 | assertj: "org.assertj:assertj-core:${assertJVersion}", 30 | robolectric: "org.robolectric:robolectric:${robolectricVersion}" 31 | ] 32 | 33 | } -------------------------------------------------------------------------------- /rxfirebase/buildsystem/publish.gradle: -------------------------------------------------------------------------------- 1 | publish { 2 | userOrg = 'ezhome' 3 | groupId = 'com.ezhome' 4 | artifactId = 'rxfirebase' 5 | publishVersion = '2.2.0' 6 | desc = 'An RxJava implementation for new Firebase Android client.' 7 | website = 'https://github.com/ezhome/Android-RxFirebase' 8 | } -------------------------------------------------------------------------------- /rxfirebase/buildsystem/version.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | versionName = "2.2.0" 3 | versionCode = 5 4 | } -------------------------------------------------------------------------------- /rxfirebase/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/admin/Work/devtools/adt-bundle-mac-x86_64-20140624/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /rxfirebase/src/androidTest/java/com/ezhome/rxfirebase2/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.ezhome.rxfirebase2; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /rxfirebase/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/FirebaseChildEvent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2; 17 | 18 | import com.google.firebase.database.DataSnapshot; 19 | 20 | /** 21 | * This class represents a firebase child event when we are 22 | * using the Child event listener 23 | */ 24 | public class FirebaseChildEvent { 25 | 26 | public enum EventType { 27 | ADDED, CHANGED, REMOVED, MOVED 28 | } 29 | 30 | /** 31 | * An {@link DataSnapshot} instance contains data from a Firebase location 32 | */ 33 | private DataSnapshot dataSnapshot; 34 | 35 | /** 36 | * The key name of sibling location ordered before the new child 37 | */ 38 | private String previousChildName; 39 | 40 | /** 41 | * Represents the type of the children event 42 | */ 43 | private EventType eventType; 44 | 45 | public FirebaseChildEvent(DataSnapshot dataSnapshot, String previousChildName, 46 | EventType eventType) { 47 | this.dataSnapshot = dataSnapshot; 48 | this.previousChildName = previousChildName; 49 | this.eventType = eventType; 50 | } 51 | 52 | public FirebaseChildEvent(DataSnapshot dataSnapshot, EventType eventType) { 53 | this.dataSnapshot = dataSnapshot; 54 | this.eventType = eventType; 55 | } 56 | 57 | public DataSnapshot getDataSnapshot() { 58 | return dataSnapshot; 59 | } 60 | 61 | public void setDataSnapshot(DataSnapshot dataSnapshot) { 62 | this.dataSnapshot = dataSnapshot; 63 | } 64 | 65 | public String getPreviousChildName() { 66 | return previousChildName; 67 | } 68 | 69 | public void setPreviousChildName(String previousChildName) { 70 | this.previousChildName = previousChildName; 71 | } 72 | 73 | public EventType getEventType() { 74 | return eventType; 75 | } 76 | 77 | public void setEventType(EventType eventType) { 78 | this.eventType = eventType; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/FirebaseDatabaseNodes.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2; 17 | 18 | /** 19 | * Standard firebase nodes 20 | */ 21 | public final class FirebaseDatabaseNodes { 22 | 23 | public static final String NODE_CONNECTED = "/.info/connected"; 24 | } 25 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/auth/FirebaseAuthErrorFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2.auth; 17 | 18 | import com.ezhome.rxfirebase2.database.RxFirebaseDatabase; 19 | import com.ezhome.rxfirebase2.exception.FirebaseSignInException; 20 | import com.ezhome.rxfirebase2.exception.FirebaseSignOutException; 21 | import rx.Subscriber; 22 | 23 | /** 24 | * An error factor for {@link RxFirebaseAuth} 25 | * and {@link RxFirebaseDatabase} 26 | */ 27 | public class FirebaseAuthErrorFactory { 28 | 29 | private FirebaseAuthErrorFactory() { 30 | //empty constructor prevent initialisation 31 | } 32 | 33 | /** 34 | * This method add to subscriber the proper error according to the 35 | * 36 | * @param subscriber {@link Subscriber} 37 | * @param exception {@link Exception} 38 | * @param generic subscriber 39 | */ 40 | static void buildError(Subscriber subscriber, Exception exception) { 41 | subscriber.onError(exception); 42 | } 43 | 44 | /** 45 | * This method adds to subscriber {@link FirebaseSignOutException} 46 | * 47 | * @param subscriber {@link Subscriber} 48 | * @param generic subscriber 49 | */ 50 | static void createSignOutError(Subscriber subscriber) { 51 | subscriber.onError(new FirebaseSignOutException("User didn't sign out successfully")); 52 | } 53 | 54 | /** 55 | * This method adds to subscriber {@link FirebaseSignOutException} 56 | * 57 | * @param subscriber {@link Subscriber} 58 | * @param generic subscriber 59 | */ 60 | static void createSignInError(Subscriber subscriber) { 61 | subscriber.onError(new FirebaseSignInException("User signed out")); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/auth/RxFirebaseAuth.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2.auth; 17 | 18 | import android.support.annotation.NonNull; 19 | import com.google.android.gms.tasks.OnCompleteListener; 20 | import com.google.android.gms.tasks.OnFailureListener; 21 | import com.google.android.gms.tasks.Task; 22 | import com.google.firebase.auth.AuthCredential; 23 | import com.google.firebase.auth.AuthResult; 24 | import com.google.firebase.auth.FirebaseAuth; 25 | import com.google.firebase.auth.FirebaseAuth.AuthStateListener; 26 | import com.google.firebase.auth.FirebaseUser; 27 | import rx.Observable; 28 | import rx.Subscriber; 29 | import rx.functions.Action0; 30 | import rx.subscriptions.Subscriptions; 31 | 32 | /** 33 | * The class is used as Decorator to 34 | * Firebase Authenticaiton functionality with RxJava 35 | */ 36 | public class RxFirebaseAuth { 37 | 38 | private final FirebaseAuth firebaseAuth; 39 | 40 | public static volatile RxFirebaseAuth instance; 41 | 42 | /** 43 | * Singleton pattern 44 | * 45 | * @param firebaseAuth {@link RxFirebaseAuth} 46 | * @return {@link RxFirebaseAuth} 47 | */ 48 | public static RxFirebaseAuth getInstance(FirebaseAuth firebaseAuth) { 49 | if (instance == null) { 50 | synchronized (RxFirebaseAuth.class) { 51 | if (instance == null) { 52 | instance = new RxFirebaseAuth(firebaseAuth); 53 | } 54 | } 55 | } 56 | return instance; 57 | } 58 | 59 | protected RxFirebaseAuth(FirebaseAuth firebaseAuth) { 60 | this.firebaseAuth = firebaseAuth; 61 | } 62 | 63 | /** 64 | * Attempts to authenticate to Firebase with {@link com.google.firebase.auth.AuthCredential} 65 | * 66 | * @param authCredential {@link com.google.firebase.auth.AuthCredential} this is the credential 67 | * we need to pass for login 68 | * @return an {@link rx.Observable} of {@link com.google.firebase.auth.FirebaseUser} to use 69 | */ 70 | public Observable observeSignIn(final AuthCredential authCredential) { 71 | return Observable.create(new Observable.OnSubscribe() { 72 | @Override public void call(final Subscriber subscriber) { 73 | final Task authResultTask = firebaseAuth.signInWithCredential(authCredential); 74 | attachListenSignIn(subscriber, authResultTask); 75 | } 76 | }); 77 | } 78 | 79 | /** 80 | * Attempts to authenticate to Firebase with {@link com.google.firebase.auth.AuthCredential} 81 | * 82 | * @param token {@link String} a custom token for login 83 | * @return an {@link rx.Observable} of {@link com.google.firebase.auth.FirebaseUser} to use 84 | */ 85 | public Observable observeSignIn(final String token) { 86 | return Observable.create(new Observable.OnSubscribe() { 87 | @Override public void call(final Subscriber subscriber) { 88 | final Task authResultTask = firebaseAuth.signInWithCustomToken(token); 89 | attachListenSignIn(subscriber, authResultTask); 90 | } 91 | }); 92 | } 93 | 94 | /** 95 | * Attempts to sign-out from Firebase 96 | * 97 | * @return an {@link rx.Observable} of {@link Boolean} 98 | */ 99 | public Observable observeSignOut() { 100 | return Observable.create(new Observable.OnSubscribe() { 101 | @Override public void call(final Subscriber subscriber) { 102 | firebaseAuth.signOut(); 103 | final AuthStateListener authStateListener = new AuthStateListener() { 104 | @Override public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 105 | if (firebaseAuth.getCurrentUser() == null) { 106 | subscriber.onNext(true); 107 | subscriber.onCompleted(); 108 | } else { 109 | FirebaseAuthErrorFactory.createSignOutError(subscriber); 110 | } 111 | } 112 | }; 113 | firebaseAuth.addAuthStateListener(authStateListener); 114 | subscriber.add(Subscriptions.create(new Action0() { 115 | @Override public void call() { 116 | firebaseAuth.removeAuthStateListener(authStateListener); 117 | } 118 | })); 119 | } 120 | }); 121 | } 122 | 123 | /** 124 | * Observes the authentication state for {@link com.google.firebase.auth.FirebaseAuth} 125 | * 126 | * @return {@link rx.Observable} of {@link com.google.firebase.auth.FirebaseUser} 127 | */ 128 | public Observable observeAuthState() { 129 | return Observable.create(new Observable.OnSubscribe() { 130 | @Override public void call(final Subscriber subscriber) { 131 | final AuthStateListener authStateListener = new AuthStateListener() { 132 | @Override public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 133 | FirebaseUser firebaseUser = firebaseAuth.getCurrentUser(); 134 | if (firebaseUser == null) { 135 | FirebaseAuthErrorFactory.createSignOutError(subscriber); 136 | } else { 137 | subscriber.onNext(firebaseUser); 138 | } 139 | } 140 | }; 141 | firebaseAuth.addAuthStateListener(authStateListener); 142 | subscriber.add(Subscriptions.create(new Action0() { 143 | @Override public void call() { 144 | firebaseAuth.removeAuthStateListener(authStateListener); 145 | } 146 | })); 147 | } 148 | }); 149 | } 150 | 151 | /** 152 | * Attaches the required listeners to observe the result 153 | * 154 | * @param subscriber {@link rx.Subscriber} of a {@link com.google.firebase.auth.FirebaseUser} 155 | * @param task {@link com.google.android.gms.tasks.Task} 156 | */ 157 | private void attachListenSignIn(final Subscriber subscriber, 158 | Task task) { 159 | task.addOnCompleteListener(new OnCompleteListener() { 160 | @Override public void onComplete(@NonNull Task task) { 161 | if (!task.isSuccessful()) { 162 | FirebaseAuthErrorFactory.createSignInError(subscriber); 163 | } else { 164 | subscriber.onNext(task.getResult().getUser()); 165 | } 166 | subscriber.onCompleted(); 167 | } 168 | }).addOnFailureListener(new OnFailureListener() { 169 | @Override public void onFailure(@NonNull Exception e) { 170 | FirebaseAuthErrorFactory.buildError(subscriber, e); 171 | } 172 | }); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/database/FirebaseDatabaseErrorFactory.java: -------------------------------------------------------------------------------- 1 | package com.ezhome.rxfirebase2.database; 2 | 3 | import com.ezhome.rxfirebase2.auth.RxFirebaseAuth; 4 | import com.ezhome.rxfirebase2.exception.FirebaseExpiredTokenException; 5 | import com.ezhome.rxfirebase2.exception.FirebaseGeneralException; 6 | import com.ezhome.rxfirebase2.exception.FirebaseInvalidTokenException; 7 | import com.ezhome.rxfirebase2.exception.FirebaseNetworkErrorException; 8 | import com.ezhome.rxfirebase2.exception.FirebaseOperationFailedException; 9 | import com.ezhome.rxfirebase2.exception.FirebasePermissionDeniedException; 10 | import com.google.firebase.database.DatabaseError; 11 | import rx.Emitter; 12 | import rx.Subscriber; 13 | 14 | /** 15 | * An error factor for {@link RxFirebaseAuth} 16 | * and {@link RxFirebaseDatabase} 17 | */ 18 | public class FirebaseDatabaseErrorFactory { 19 | 20 | private FirebaseDatabaseErrorFactory() { 21 | //empty constructor prevent initialisation 22 | } 23 | 24 | /** 25 | * This method add to emitter the proper error according to the 26 | * 27 | * @param emitter {@link rx.Emitter} 28 | * @param error {@link DatabaseError} 29 | * @param generic subscriber 30 | */ 31 | static void buildError(Emitter emitter, DatabaseError error) { 32 | switch (error.getCode()) { 33 | case DatabaseError.INVALID_TOKEN: 34 | emitter.onError(new FirebaseInvalidTokenException(error.getMessage())); 35 | break; 36 | case DatabaseError.EXPIRED_TOKEN: 37 | emitter.onError(new FirebaseExpiredTokenException(error.getMessage())); 38 | break; 39 | case DatabaseError.NETWORK_ERROR: 40 | emitter.onError(new FirebaseNetworkErrorException(error.getMessage())); 41 | break; 42 | case DatabaseError.PERMISSION_DENIED: 43 | emitter.onError(new FirebasePermissionDeniedException(error.getMessage())); 44 | break; 45 | case DatabaseError.OPERATION_FAILED: 46 | emitter.onError(new FirebaseOperationFailedException(error.getMessage())); 47 | break; 48 | default: 49 | emitter.onError(new FirebaseGeneralException(error.getMessage())); 50 | break; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/database/RxFirebaseDatabase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2.database; 17 | 18 | import com.ezhome.rxfirebase2.FirebaseChildEvent; 19 | import com.ezhome.rxfirebase2.FirebaseChildEvent.EventType; 20 | import com.google.firebase.database.ChildEventListener; 21 | import com.google.firebase.database.DataSnapshot; 22 | import com.google.firebase.database.DatabaseError; 23 | import com.google.firebase.database.DatabaseReference; 24 | import com.google.firebase.database.Query; 25 | import com.google.firebase.database.ValueEventListener; 26 | import java.util.Map; 27 | import rx.Emitter; 28 | import rx.Observable; 29 | import rx.Scheduler; 30 | import rx.functions.Action1; 31 | import rx.functions.Cancellable; 32 | import rx.functions.Func1; 33 | 34 | /** 35 | * The class is used as Decorator to 36 | * Firebase Database functionality with RxJava 37 | */ 38 | public class RxFirebaseDatabase { 39 | 40 | public static volatile RxFirebaseDatabase instance; 41 | 42 | /** 43 | * Observe Scheduler 44 | */ 45 | private Scheduler observeOnScheduler; 46 | 47 | /** 48 | * Singleton pattern 49 | * 50 | * @return {@link RxFirebaseDatabase} 51 | */ 52 | public static RxFirebaseDatabase getInstance() { 53 | if (instance == null) { 54 | synchronized (RxFirebaseDatabase.class) { 55 | if (instance == null) { 56 | instance = new RxFirebaseDatabase(); 57 | } 58 | } 59 | } 60 | return instance; 61 | } 62 | 63 | protected RxFirebaseDatabase() { 64 | //empty constructor, prevent initialisation 65 | } 66 | 67 | /** 68 | * This method will set specific Scheduler on what values will be Observed on 69 | * 70 | * @param observeOnScheduler {@link Scheduler} for observed on 71 | * @return {@link RxFirebaseDatabase} 72 | */ 73 | public RxFirebaseDatabase observeOn(Scheduler observeOnScheduler) { 74 | this.observeOnScheduler = observeOnScheduler; 75 | return this; 76 | } 77 | 78 | /** 79 | * This methods observes data saving with push in order to generate the key 80 | * automatically according to Firebase hashing key rules. 81 | * 82 | * @param reference {@link Query} this is reference of a Firebase Query 83 | * @param object {@link Object} whatever object we want to save 84 | * @return an {@link rx.Observable} of the generated key after 85 | * the object persistence 86 | */ 87 | public Observable observeSetValuePush(final DatabaseReference reference, 88 | final Object object) { 89 | return Observable.create(new Action1>() { 90 | @Override public void call(final Emitter emitter) { 91 | final DatabaseReference ref = reference.push(); 92 | ref.addListenerForSingleValueEvent(new ValueEventListener() { 93 | @Override public void onDataChange(DataSnapshot dataSnapshot) { 94 | emitter.onNext(ref.getKey()); 95 | emitter.onCompleted(); 96 | } 97 | 98 | @Override public void onCancelled(DatabaseError error) { 99 | FirebaseDatabaseErrorFactory.buildError(emitter, error); 100 | } 101 | }); 102 | ref.setValue(object); 103 | } 104 | }, Emitter.BackpressureMode.LATEST).compose(this.applyScheduler()); 105 | } 106 | 107 | /** 108 | * This methods observes data saving under the provided {@link DatabaseReference} 109 | * 110 | * @param reference {@link DatabaseReference} this is reference of a Firebase Query 111 | * @param object {@link Object} whatever object we want to save 112 | * @return an {@link rx.Observable} of the generated key after 113 | * the object persistence 114 | */ 115 | public Observable observeSetValue(final DatabaseReference reference, 116 | final Object object) { 117 | return Observable.create(new Action1>() { 118 | @Override public void call(final Emitter emitter) { 119 | final ValueEventListener listener = new ValueEventListener() { 120 | @Override public void onDataChange(DataSnapshot dataSnapshot) { 121 | emitter.onNext(reference.getKey()); 122 | emitter.onCompleted(); 123 | } 124 | 125 | @Override public void onCancelled(DatabaseError error) { 126 | FirebaseDatabaseErrorFactory.buildError(emitter, error); 127 | } 128 | }; 129 | reference.addListenerForSingleValueEvent(listener); 130 | reference.setValue(object); 131 | 132 | // When the subscription is cancelled, remove the listener 133 | emitter.setCancellation(new Cancellable() { 134 | @Override public void cancel() throws Exception { 135 | reference.removeEventListener(listener); 136 | } 137 | }); 138 | } 139 | }, Emitter.BackpressureMode.LATEST); 140 | } 141 | 142 | /** 143 | * This methods observes children update for provided {@link DatabaseReference} 144 | * 145 | * @param reference {@link DatabaseReference} 146 | * @param data {@link Map} the children items which should be updated 147 | * @return {@link rx.Observable} which emits the key of reference {@link String} 148 | */ 149 | public Observable observeUpdateChildren(final DatabaseReference reference, 150 | final Map data) { 151 | return Observable.create(new Action1>() { 152 | @Override public void call(final Emitter emitter) { 153 | final ValueEventListener listener = new ValueEventListener() { 154 | @Override public void onDataChange(DataSnapshot dataSnapshot) { 155 | emitter.onNext(reference.getKey()); 156 | emitter.onCompleted(); 157 | } 158 | 159 | @Override public void onCancelled(DatabaseError databaseError) { 160 | FirebaseDatabaseErrorFactory.buildError(emitter, databaseError); 161 | } 162 | }; 163 | reference.addListenerForSingleValueEvent(listener); 164 | reference.updateChildren(data); 165 | 166 | // When the subscription is cancelled, remove the listener 167 | emitter.setCancellation(new Cancellable() { 168 | @Override public void cancel() throws Exception { 169 | reference.removeEventListener(listener); 170 | } 171 | }); 172 | } 173 | }, Emitter.BackpressureMode.LATEST).compose(this.applyScheduler()); 174 | } 175 | 176 | /** 177 | * This methods observes a firebase query and returns back 178 | * an Observable of the {@link DataSnapshot} 179 | * when the firebase client uses a {@link ValueEventListener} 180 | * 181 | * @param firebaseRef {@link Query} this is reference of a Firebase Query 182 | * @return an {@link rx.Observable} of datasnapshot to use 183 | */ 184 | public Observable observeValueEvent(final Query firebaseRef) { 185 | return observeValueEvent(firebaseRef, Emitter.BackpressureMode.BUFFER); 186 | } 187 | 188 | /** 189 | * This methods observes a firebase query and returns back 190 | * an Observable of the {@link DataSnapshot} 191 | * when the firebase client uses a {@link ValueEventListener} 192 | * 193 | * @param firebaseRef {@link Query} this is reference of a Firebase Query 194 | * @param backPressureMode {@link Emitter.BackpressureMode} backpressure mode 195 | * @return an {@link rx.Observable} of datasnapshot to use 196 | */ 197 | public Observable observeValueEvent(final Query firebaseRef, 198 | Emitter.BackpressureMode backPressureMode) { 199 | return Observable.create(new Action1>() { 200 | @Override public void call(final Emitter emitter) { 201 | final ValueEventListener listener = 202 | firebaseRef.addValueEventListener(new ValueEventListener() { 203 | @Override public void onDataChange(DataSnapshot dataSnapshot) { 204 | emitter.onNext(dataSnapshot); 205 | } 206 | 207 | @Override public void onCancelled(DatabaseError error) { 208 | FirebaseDatabaseErrorFactory.buildError(emitter, error); 209 | } 210 | }); 211 | 212 | // When the subscription is cancelled, remove the listener 213 | emitter.setCancellation(new Cancellable() { 214 | @Override public void cancel() throws Exception { 215 | firebaseRef.removeEventListener(listener); 216 | } 217 | }); 218 | } 219 | }, backPressureMode).compose(this.applyScheduler()); 220 | } 221 | 222 | /** 223 | * This methods observes a firebase query and returns back ONCE 224 | * an Observable of the {@link DataSnapshot} 225 | * when the firebase client uses a {@link ValueEventListener} 226 | * 227 | * @param firebaseRef {@link Query} this is reference of a Firebase Query 228 | * @return an {@link rx.Observable} of datasnapshot to use 229 | */ 230 | public Observable observeSingleValue(final Query firebaseRef) { 231 | return observeSingleValue(firebaseRef, Emitter.BackpressureMode.BUFFER); 232 | } 233 | 234 | /** 235 | * This methods observes a firebase query and returns back ONCE 236 | * an Observable of the {@link DataSnapshot} 237 | * when the firebase client uses a {@link ValueEventListener} 238 | * 239 | * @param firebaseRef {@link Query} this is reference of a Firebase Query 240 | * @param backPressureMode {@link Emitter.BackpressureMode} backpressure mode 241 | * @return an {@link rx.Observable} of datasnapshot to use 242 | */ 243 | public Observable observeSingleValue(final Query firebaseRef, 244 | Emitter.BackpressureMode backPressureMode) { 245 | return Observable.create(new Action1>() { 246 | @Override public void call(final Emitter emitter) { 247 | final ValueEventListener listener = new ValueEventListener() { 248 | @Override public void onDataChange(DataSnapshot dataSnapshot) { 249 | emitter.onNext(dataSnapshot); 250 | emitter.onCompleted(); 251 | } 252 | 253 | @Override public void onCancelled(DatabaseError error) { 254 | FirebaseDatabaseErrorFactory.buildError(emitter, error); 255 | } 256 | }; 257 | 258 | firebaseRef.addListenerForSingleValueEvent(listener); 259 | 260 | // When the subscription is cancelled, remove the listener 261 | emitter.setCancellation(new Cancellable() { 262 | @Override public void cancel() throws Exception { 263 | firebaseRef.removeEventListener(listener); 264 | 265 | } 266 | }); 267 | } 268 | }, backPressureMode).compose(this.applyScheduler()); 269 | } 270 | 271 | /** 272 | * This methods observes a firebase query and returns back 273 | * an Observable of the {@link DataSnapshot} 274 | * when the firebase client uses a {@link ChildEventListener} 275 | * 276 | * @param firebaseRef {@link Query} this is reference of a Firebase Query 277 | * @return an {@link rx.Observable} of {@link FirebaseChildEvent} 278 | * to use 279 | */ 280 | public Observable observeChildEvent(final Query firebaseRef) { 281 | return this.observeChildEvent(firebaseRef, Emitter.BackpressureMode.BUFFER); 282 | } 283 | 284 | /** 285 | * This methods observes a firebase query and returns back 286 | * an Observable of the {@link DataSnapshot} 287 | * when the firebase client uses a {@link ChildEventListener} 288 | * 289 | * @param firebaseRef {@link Query} this is reference of a Firebase Query 290 | * @param backPressureMode {@link Emitter.BackpressureMode} backpressure mode 291 | * @return an {@link rx.Observable} of {@link FirebaseChildEvent} 292 | * to use 293 | */ 294 | public Observable observeChildEvent(final Query firebaseRef, 295 | Emitter.BackpressureMode backPressureMode) { 296 | return Observable.create(new Action1>() { 297 | @Override public void call(final Emitter emitter) { 298 | final ChildEventListener childEventListener = 299 | firebaseRef.addChildEventListener(new ChildEventListener() { 300 | 301 | @Override 302 | public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) { 303 | emitter.onNext( 304 | new FirebaseChildEvent(dataSnapshot, previousChildName, EventType.ADDED)); 305 | } 306 | 307 | @Override 308 | public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) { 309 | emitter.onNext( 310 | new FirebaseChildEvent(dataSnapshot, previousChildName, EventType.CHANGED)); 311 | } 312 | 313 | @Override public void onChildRemoved(DataSnapshot dataSnapshot) { 314 | emitter.onNext( 315 | new FirebaseChildEvent(dataSnapshot, EventType.REMOVED)); 316 | } 317 | 318 | @Override 319 | public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) { 320 | emitter.onNext( 321 | new FirebaseChildEvent(dataSnapshot, previousChildName, EventType.MOVED)); 322 | } 323 | 324 | @Override public void onCancelled(DatabaseError error) { 325 | FirebaseDatabaseErrorFactory.buildError(emitter, error); 326 | } 327 | }); 328 | // this is used to remove the listener when the subscriber is 329 | // cancelled (unsubscribe) 330 | emitter.setCancellation(new Cancellable() { 331 | @Override public void cancel() throws Exception { 332 | firebaseRef.removeEventListener(childEventListener); 333 | } 334 | }); 335 | } 336 | }, backPressureMode).compose(this.applyScheduler()); 337 | } 338 | 339 | /** 340 | * Creates an observable only for the child changed method 341 | * 342 | * @param firebaseRef {@link Query} this is reference of a Firebase Query 343 | * @return an {@link rx.Observable} of {@link FirebaseChildEvent} 344 | * to use 345 | */ 346 | public Observable observeChildAdded(final Query firebaseRef) { 347 | return observeChildEvent(firebaseRef).filter(filterChildEvent(EventType.ADDED)); 348 | } 349 | 350 | /** 351 | * Creates an observable only for the child changed method 352 | * 353 | * @param firebaseRef {@link Query} this is reference of a Firebase Query 354 | * @return an {@link rx.Observable} of {@link FirebaseChildEvent} 355 | * to use 356 | */ 357 | public Observable observeChildChanged(final Query firebaseRef) { 358 | return observeChildEvent(firebaseRef).filter(filterChildEvent(EventType.CHANGED)); 359 | } 360 | 361 | /** 362 | * Creates an observable only for the child removed method 363 | * 364 | * @param firebaseRef {@link Query} this is reference of a Firebase Query 365 | * @return an {@link rx.Observable} of {@link FirebaseChildEvent} 366 | * to use 367 | */ 368 | public Observable observeChildRemoved(final Query firebaseRef) { 369 | return observeChildEvent(firebaseRef).filter(filterChildEvent(EventType.REMOVED)); 370 | } 371 | 372 | /** 373 | * Creates an observable only for the child removed method 374 | * 375 | * @param firebaseRef {@link Query} this is reference of a Firebase Query 376 | * @return an {@link rx.Observable} of {@link FirebaseChildEvent} 377 | * to use 378 | */ 379 | public Observable observeChildMoved(final Query firebaseRef) { 380 | return observeChildEvent(firebaseRef).filter(filterChildEvent(EventType.MOVED)); 381 | } 382 | 383 | /** 384 | * Functions which filters a stream of {@link Observable} according to firebase 385 | * child event type 386 | * 387 | * @param type {@link FirebaseChildEvent} 388 | * @return {@link rx.functions.Func1} a function which returns a boolean if the type are equals 389 | */ 390 | private Func1 filterChildEvent(final EventType type) { 391 | return new Func1() { 392 | @Override public Boolean call(FirebaseChildEvent firebaseChildEvent) { 393 | return firebaseChildEvent.getEventType() == type; 394 | } 395 | }; 396 | } 397 | 398 | /** 399 | * Function that receives the current Observable and should apply scheduler 400 | * 401 | * @param source Observable 402 | * @return an {@link rx.Observable} with new or the same observe on scheduler 403 | */ 404 | @SuppressWarnings("unchecked") private Observable.Transformer applyScheduler() { 405 | return new Observable.Transformer() { 406 | @Override public Observable call(Observable observable) { 407 | if (observeOnScheduler != null) { 408 | return observable.observeOn(observeOnScheduler); 409 | } 410 | return observable; 411 | } 412 | }; 413 | } 414 | } 415 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/exception/FirebaseAuthProviderDisabledException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2.exception; 17 | 18 | /** 19 | * When The requested authentication provider is disabled for this Firebase. 20 | */ 21 | public class FirebaseAuthProviderDisabledException extends Exception { 22 | 23 | public FirebaseAuthProviderDisabledException() { 24 | super(); 25 | } 26 | 27 | public FirebaseAuthProviderDisabledException(String detailMessage) { 28 | super(detailMessage); 29 | } 30 | 31 | public FirebaseAuthProviderDisabledException(String detailMessage, Throwable throwable) { 32 | super(detailMessage, throwable); 33 | } 34 | 35 | public FirebaseAuthProviderDisabledException(Throwable throwable) { 36 | super(throwable); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/exception/FirebaseDisconnectedException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2.exception; 17 | 18 | /** 19 | * This exception occurred when the firebase is disconnected 20 | * eg. network is turned off 21 | */ 22 | public class FirebaseDisconnectedException extends Exception { 23 | 24 | public FirebaseDisconnectedException() { 25 | super(); 26 | } 27 | 28 | public FirebaseDisconnectedException(String detailMessage) { 29 | super(detailMessage); 30 | } 31 | 32 | public FirebaseDisconnectedException(String detailMessage, Throwable throwable) { 33 | super(detailMessage, throwable); 34 | } 35 | 36 | public FirebaseDisconnectedException(Throwable throwable) { 37 | super(throwable); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/exception/FirebaseExpiredTokenException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2.exception; 17 | 18 | /** 19 | * Raised when the supplied auth token has expired 20 | */ 21 | public class FirebaseExpiredTokenException extends Exception { 22 | 23 | public FirebaseExpiredTokenException() { 24 | super(); 25 | } 26 | 27 | public FirebaseExpiredTokenException(String detailMessage) { 28 | super(detailMessage); 29 | } 30 | 31 | public FirebaseExpiredTokenException(String detailMessage, Throwable throwable) { 32 | super(detailMessage, throwable); 33 | } 34 | 35 | public FirebaseExpiredTokenException(Throwable throwable) { 36 | super(throwable); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/exception/FirebaseGeneralException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2.exception; 17 | 18 | /** 19 | * Generic exception for Firebase 20 | */ 21 | public class FirebaseGeneralException extends Exception { 22 | 23 | public FirebaseGeneralException() { 24 | super(); 25 | } 26 | 27 | public FirebaseGeneralException(String detailMessage) { 28 | super(detailMessage); 29 | } 30 | 31 | public FirebaseGeneralException(String detailMessage, Throwable throwable) { 32 | super(detailMessage, throwable); 33 | } 34 | 35 | public FirebaseGeneralException(Throwable throwable) { 36 | super(throwable); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/exception/FirebaseInvalidTokenException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2.exception; 17 | 18 | /** 19 | * Raised when the specified authentication token is invalid. 20 | */ 21 | public class FirebaseInvalidTokenException extends Exception { 22 | 23 | public FirebaseInvalidTokenException() { 24 | super(); 25 | } 26 | 27 | public FirebaseInvalidTokenException(String detailMessage) { 28 | super(detailMessage); 29 | } 30 | 31 | public FirebaseInvalidTokenException(String detailMessage, Throwable throwable) { 32 | super(detailMessage, throwable); 33 | } 34 | 35 | public FirebaseInvalidTokenException(Throwable throwable) { 36 | super(throwable); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/exception/FirebaseNetworkErrorException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2.exception; 17 | 18 | /** 19 | * Raised when the operation could not be performed due to a network error. 20 | */ 21 | public class FirebaseNetworkErrorException extends Exception { 22 | 23 | public FirebaseNetworkErrorException() { 24 | super(); 25 | } 26 | 27 | public FirebaseNetworkErrorException(String detailMessage) { 28 | super(detailMessage); 29 | } 30 | 31 | public FirebaseNetworkErrorException(String detailMessage, Throwable throwable) { 32 | super(detailMessage, throwable); 33 | } 34 | 35 | public FirebaseNetworkErrorException(Throwable throwable) { 36 | super(throwable); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/exception/FirebaseOperationFailedException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2.exception; 17 | 18 | /** 19 | * This exception occurred when an operation has been failed 20 | */ 21 | public class FirebaseOperationFailedException extends Exception { 22 | 23 | public FirebaseOperationFailedException() { 24 | super(); 25 | } 26 | 27 | public FirebaseOperationFailedException(String detailMessage) { 28 | super(detailMessage); 29 | } 30 | 31 | public FirebaseOperationFailedException(String detailMessage, Throwable throwable) { 32 | super(detailMessage, throwable); 33 | } 34 | 35 | public FirebaseOperationFailedException(Throwable throwable) { 36 | super(throwable); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/exception/FirebasePermissionDeniedException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2.exception; 17 | 18 | /** 19 | * Raised when the Firebase returns a permission 20 | * denied error 21 | */ 22 | public class FirebasePermissionDeniedException extends Exception { 23 | 24 | public FirebasePermissionDeniedException() { 25 | super(); 26 | } 27 | 28 | public FirebasePermissionDeniedException(String detailMessage) { 29 | super(detailMessage); 30 | } 31 | 32 | public FirebasePermissionDeniedException(String detailMessage, Throwable throwable) { 33 | super(detailMessage, throwable); 34 | } 35 | 36 | public FirebasePermissionDeniedException(Throwable throwable) { 37 | super(throwable); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/exception/FirebaseSignInException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2.exception; 17 | 18 | /** 19 | * This exception occurred when something went wrong during 20 | * the logout process 21 | */ 22 | public class FirebaseSignInException extends Exception { 23 | 24 | public FirebaseSignInException() { 25 | super(); 26 | } 27 | 28 | public FirebaseSignInException(String detailMessage) { 29 | super(detailMessage); 30 | } 31 | 32 | public FirebaseSignInException(String detailMessage, Throwable throwable) { 33 | super(detailMessage, throwable); 34 | } 35 | 36 | public FirebaseSignInException(Throwable throwable) { 37 | super(throwable); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /rxfirebase/src/main/java/com/ezhome/rxfirebase2/exception/FirebaseSignOutException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2.exception; 17 | 18 | /** 19 | * This exception occurred when something went wrong during 20 | * the logout process 21 | */ 22 | public class FirebaseSignOutException extends Exception { 23 | 24 | public FirebaseSignOutException() { 25 | super(); 26 | } 27 | 28 | public FirebaseSignOutException(String detailMessage) { 29 | super(detailMessage); 30 | } 31 | 32 | public FirebaseSignOutException(String detailMessage, Throwable throwable) { 33 | super(detailMessage, throwable); 34 | } 35 | 36 | public FirebaseSignOutException(Throwable throwable) { 37 | super(throwable); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /rxfirebase/src/test/java/com/ezhome/rxfirebase2/ApplicationStub.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2; 17 | 18 | import android.app.Application; 19 | 20 | public class ApplicationStub extends Application { 21 | 22 | @Override public void onCreate() { 23 | super.onCreate(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rxfirebase/src/test/java/com/ezhome/rxfirebase2/ApplicationTestCase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2; 17 | 18 | import android.os.Build; 19 | import org.junit.runner.RunWith; 20 | import org.robolectric.RobolectricGradleTestRunner; 21 | import org.robolectric.annotation.Config; 22 | 23 | @RunWith(value = RobolectricGradleTestRunner.class) 24 | @Config(application = ApplicationStub.class, constants = BuildConfig.class, sdk = Build.VERSION_CODES.LOLLIPOP) 25 | public abstract class ApplicationTestCase { 26 | } 27 | -------------------------------------------------------------------------------- /rxfirebase/src/test/java/com/ezhome/rxfirebase2/RxFirebaseAuthTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2; 17 | 18 | import com.ezhome.rxfirebase2.auth.RxFirebaseAuth; 19 | import com.ezhome.rxfirebase2.exception.FirebaseSignInException; 20 | import com.ezhome.rxfirebase2.exception.FirebaseSignOutException; 21 | import com.google.firebase.auth.AuthCredential; 22 | import com.google.firebase.auth.FirebaseAuth; 23 | import com.google.firebase.auth.FirebaseUser; 24 | import com.google.firebase.database.DataSnapshot; 25 | import com.google.firebase.database.DatabaseReference; 26 | import java.util.Collections; 27 | import org.junit.After; 28 | import org.junit.Before; 29 | import org.junit.Rule; 30 | import org.junit.Test; 31 | import org.junit.rules.ExpectedException; 32 | import org.mockito.Mock; 33 | import org.mockito.MockitoAnnotations; 34 | import rx.Observable; 35 | import rx.observers.TestSubscriber; 36 | import rx.schedulers.Schedulers; 37 | 38 | import static org.mockito.Mockito.spy; 39 | import static org.mockito.Mockito.when; 40 | 41 | public class RxFirebaseAuthTest extends ApplicationTestCase { 42 | 43 | public static final String FAKE_TOKEN = "fakeToken"; 44 | 45 | private RxFirebaseAuth rxFirebaseAuth; 46 | private RxFirebaseAuth spyRxFirebaseAuth; 47 | @Mock FirebaseAuth mockFirebaseAuth; 48 | @Mock private AuthCredential mockAuthCredential; 49 | @Mock private FirebaseUser mockFirebaseUser; 50 | @Mock private DatabaseReference mockRef; 51 | @Mock private DataSnapshot mockDataSnapshot; 52 | @Mock private FirebaseChildEvent mockFirebaseChildEvent; 53 | 54 | @Rule public ExpectedException expectedException = ExpectedException.none(); 55 | 56 | @Before public void setUp() { 57 | MockitoAnnotations.initMocks(this); 58 | rxFirebaseAuth = RxFirebaseAuth.getInstance(mockFirebaseAuth); 59 | spyRxFirebaseAuth = spy(rxFirebaseAuth); 60 | } 61 | 62 | @After public void destroy() { 63 | rxFirebaseAuth = null; 64 | spyRxFirebaseAuth = null; 65 | } 66 | 67 | @Test public void testObserveSignIn() throws InterruptedException { 68 | when(spyRxFirebaseAuth.observeSignIn(mockAuthCredential)).thenReturn( 69 | Observable.just(mockFirebaseUser)); 70 | 71 | TestSubscriber testSubscriber = new TestSubscriber<>(); 72 | spyRxFirebaseAuth.observeSignIn(mockAuthCredential) 73 | .subscribeOn(Schedulers.immediate()) 74 | .subscribe(testSubscriber); 75 | 76 | testSubscriber.assertNoErrors(); 77 | testSubscriber.assertValueCount(1); 78 | testSubscriber.assertReceivedOnNext(Collections.singletonList(mockFirebaseUser)); 79 | testSubscriber.assertCompleted(); 80 | testSubscriber.unsubscribe(); 81 | } 82 | 83 | @Test public void testObserveSignInError() throws InterruptedException { 84 | when(spyRxFirebaseAuth.observeSignIn(mockAuthCredential)).thenReturn( 85 | Observable.error(new FirebaseSignInException())); 86 | 87 | TestSubscriber testSubscriber = new TestSubscriber<>(); 88 | spyRxFirebaseAuth.observeSignIn(mockAuthCredential) 89 | .subscribeOn(Schedulers.immediate()) 90 | .subscribe(testSubscriber); 91 | 92 | testSubscriber.assertError(FirebaseSignInException.class); 93 | testSubscriber.unsubscribe(); 94 | } 95 | 96 | @Test public void testObserveSignInToken() throws InterruptedException { 97 | when(spyRxFirebaseAuth.observeSignIn(FAKE_TOKEN)).thenReturn(Observable.just(mockFirebaseUser)); 98 | 99 | TestSubscriber testSubscriber = new TestSubscriber<>(); 100 | spyRxFirebaseAuth.observeSignIn(FAKE_TOKEN) 101 | .subscribeOn(Schedulers.immediate()) 102 | .subscribe(testSubscriber); 103 | 104 | testSubscriber.assertNoErrors(); 105 | testSubscriber.assertValueCount(1); 106 | testSubscriber.assertReceivedOnNext(Collections.singletonList(mockFirebaseUser)); 107 | testSubscriber.assertCompleted(); 108 | testSubscriber.unsubscribe(); 109 | } 110 | 111 | @Test public void testObserveSignInTokenError() throws InterruptedException { 112 | when(spyRxFirebaseAuth.observeSignIn(FAKE_TOKEN)).thenReturn( 113 | Observable.error(new FirebaseSignInException())); 114 | 115 | TestSubscriber testSubscriber = new TestSubscriber<>(); 116 | spyRxFirebaseAuth.observeSignIn(FAKE_TOKEN) 117 | .subscribeOn(Schedulers.immediate()) 118 | .subscribe(testSubscriber); 119 | 120 | testSubscriber.assertError(FirebaseSignInException.class); 121 | testSubscriber.unsubscribe(); 122 | } 123 | 124 | @Test public void testObserveSignOut() throws InterruptedException { 125 | when(spyRxFirebaseAuth.observeSignOut()).thenReturn( 126 | Observable.error(new FirebaseSignOutException())); 127 | 128 | TestSubscriber testSubscriber = new TestSubscriber<>(); 129 | spyRxFirebaseAuth.observeSignOut() 130 | .subscribeOn(Schedulers.immediate()) 131 | .subscribe(testSubscriber); 132 | 133 | testSubscriber.assertError(FirebaseSignOutException.class); 134 | testSubscriber.unsubscribe(); 135 | } 136 | 137 | @Test public void testObserveSignOutError() throws InterruptedException { 138 | when(spyRxFirebaseAuth.observeSignOut()).thenReturn(Observable.just(true)); 139 | 140 | TestSubscriber testSubscriber = new TestSubscriber<>(); 141 | spyRxFirebaseAuth.observeSignOut() 142 | .subscribeOn(Schedulers.immediate()) 143 | .subscribe(testSubscriber); 144 | 145 | testSubscriber.assertNoErrors(); 146 | testSubscriber.assertValueCount(1); 147 | testSubscriber.assertReceivedOnNext(Collections.singletonList(true)); 148 | testSubscriber.assertCompleted(); 149 | testSubscriber.unsubscribe(); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /rxfirebase/src/test/java/com/ezhome/rxfirebase2/RxFirebaseDatabaseTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Ezhome Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.ezhome.rxfirebase2; 17 | 18 | import com.ezhome.rxfirebase2.database.RxFirebaseDatabase; 19 | import com.google.firebase.database.DataSnapshot; 20 | import com.google.firebase.database.DatabaseReference; 21 | import com.google.firebase.database.Query; 22 | import java.util.Collections; 23 | import java.util.Map; 24 | import org.junit.After; 25 | import org.junit.Before; 26 | import org.junit.Rule; 27 | import org.junit.Test; 28 | import org.junit.rules.ExpectedException; 29 | import org.mockito.Mock; 30 | import org.mockito.MockitoAnnotations; 31 | import rx.Observable; 32 | import rx.observers.TestSubscriber; 33 | import rx.schedulers.Schedulers; 34 | 35 | import static org.mockito.Mockito.mock; 36 | import static org.mockito.Mockito.spy; 37 | import static org.mockito.Mockito.when; 38 | 39 | public class RxFirebaseDatabaseTest extends ApplicationTestCase { 40 | 41 | private static final String FAKE_RESPONSE = "key"; 42 | 43 | private RxFirebaseDatabase rxFirebase; 44 | private RxFirebaseDatabase spyRxFirebase; 45 | @Mock private Query mockRef; 46 | @Mock private DatabaseReference mockReference; 47 | @Mock private DataSnapshot mockDataSnapshot; 48 | @Mock private FirebaseChildEvent mockFirebaseChildEvent; 49 | 50 | @Rule public ExpectedException expectedException = ExpectedException.none(); 51 | 52 | @Before public void setUp() { 53 | MockitoAnnotations.initMocks(this); 54 | rxFirebase = RxFirebaseDatabase.getInstance(); 55 | spyRxFirebase = spy(rxFirebase); 56 | } 57 | 58 | @After public void destroy() { 59 | rxFirebase = null; 60 | spyRxFirebase = null; 61 | } 62 | 63 | @Test public void testObserveSetValue() throws InterruptedException { 64 | final Object mockData = mock(Object.class); 65 | when(spyRxFirebase.observeSetValue(mockReference, mockData)).thenReturn( 66 | Observable.just(FAKE_RESPONSE)); 67 | 68 | TestSubscriber testSubscriber = new TestSubscriber<>(); 69 | spyRxFirebase.observeSetValue(mockReference, mockData) 70 | .subscribeOn(Schedulers.immediate()) 71 | .subscribe(testSubscriber); 72 | 73 | testSubscriber.assertNoErrors(); 74 | testSubscriber.assertValueCount(1); 75 | testSubscriber.assertValue(FAKE_RESPONSE); 76 | testSubscriber.assertCompleted(); 77 | testSubscriber.unsubscribe(); 78 | } 79 | 80 | @SuppressWarnings("unchecked") 81 | @Test public void testObserveUpdateChildren() throws InterruptedException { 82 | final Map mockData = mock(Map.class); 83 | when(spyRxFirebase.observeUpdateChildren(mockReference, mockData)).thenReturn( 84 | Observable.just(FAKE_RESPONSE)); 85 | 86 | TestSubscriber testSubscriber = new TestSubscriber<>(); 87 | spyRxFirebase.observeUpdateChildren(mockReference, mockData) 88 | .subscribeOn(Schedulers.immediate()) 89 | .subscribe(testSubscriber); 90 | 91 | testSubscriber.assertNoErrors(); 92 | testSubscriber.assertValueCount(1); 93 | testSubscriber.assertValue(FAKE_RESPONSE); 94 | testSubscriber.assertCompleted(); 95 | testSubscriber.unsubscribe(); 96 | } 97 | 98 | @Test public void testObserveChildValue() { 99 | when(spyRxFirebase.observeChildEvent(mockRef)).thenReturn( 100 | Observable.just(mockFirebaseChildEvent)); 101 | 102 | TestSubscriber testSubscriber = new TestSubscriber<>(); 103 | spyRxFirebase.observeChildEvent(mockRef) 104 | .subscribeOn(Schedulers.immediate()) 105 | .subscribe(testSubscriber); 106 | 107 | testSubscriber.assertNoErrors(); 108 | testSubscriber.assertValueCount(1); 109 | testSubscriber.assertReceivedOnNext(Collections.singletonList(mockFirebaseChildEvent)); 110 | testSubscriber.assertCompleted(); 111 | testSubscriber.unsubscribe(); 112 | } 113 | 114 | @Test public void testObserveSingleValue() { 115 | when(spyRxFirebase.observeSingleValue(mockRef)).thenReturn(Observable.just(mockDataSnapshot)); 116 | 117 | TestSubscriber testSubscriber = new TestSubscriber<>(); 118 | spyRxFirebase.observeSingleValue(mockRef) 119 | .subscribeOn(Schedulers.immediate()) 120 | .subscribe(testSubscriber); 121 | 122 | testSubscriber.assertNoErrors(); 123 | testSubscriber.assertValueCount(1); 124 | testSubscriber.assertReceivedOnNext(Collections.singletonList(mockDataSnapshot)); 125 | testSubscriber.assertCompleted(); 126 | testSubscriber.unsubscribe(); 127 | } 128 | 129 | @Test public void testObserveChildAdded() { 130 | mockFirebaseChildEvent.setEventType(FirebaseChildEvent.EventType.ADDED); 131 | when(spyRxFirebase.observeChildAdded(mockRef)).thenReturn( 132 | Observable.just(mockFirebaseChildEvent)); 133 | 134 | TestSubscriber testSubscriber = new TestSubscriber<>(); 135 | spyRxFirebase.observeChildAdded(mockRef) 136 | .subscribeOn(Schedulers.immediate()) 137 | .subscribe(testSubscriber); 138 | 139 | testSubscriber.assertNoErrors(); 140 | testSubscriber.assertValueCount(1); 141 | testSubscriber.assertReceivedOnNext(Collections.singletonList(mockFirebaseChildEvent)); 142 | testSubscriber.assertCompleted(); 143 | testSubscriber.unsubscribe(); 144 | } 145 | 146 | @Test public void testObserveChildRemoved() { 147 | mockFirebaseChildEvent.setEventType(FirebaseChildEvent.EventType.REMOVED); 148 | when(spyRxFirebase.observeChildRemoved(mockRef)).thenReturn( 149 | Observable.just(mockFirebaseChildEvent)); 150 | 151 | TestSubscriber testSubscriber = new TestSubscriber<>(); 152 | spyRxFirebase.observeChildRemoved(mockRef) 153 | .subscribeOn(Schedulers.immediate()) 154 | .subscribe(testSubscriber); 155 | 156 | testSubscriber.assertNoErrors(); 157 | testSubscriber.assertValueCount(1); 158 | testSubscriber.assertReceivedOnNext(Collections.singletonList(mockFirebaseChildEvent)); 159 | testSubscriber.assertCompleted(); 160 | testSubscriber.unsubscribe(); 161 | } 162 | 163 | @Test public void testObserveChildChanged() { 164 | mockFirebaseChildEvent.setEventType(FirebaseChildEvent.EventType.CHANGED); 165 | when(spyRxFirebase.observeChildChanged(mockRef)).thenReturn( 166 | Observable.just(mockFirebaseChildEvent)); 167 | 168 | TestSubscriber testSubscriber = new TestSubscriber<>(); 169 | spyRxFirebase.observeChildChanged(mockRef) 170 | .subscribeOn(Schedulers.immediate()) 171 | .subscribe(testSubscriber); 172 | 173 | testSubscriber.assertNoErrors(); 174 | testSubscriber.assertValueCount(1); 175 | testSubscriber.assertReceivedOnNext(Collections.singletonList(mockFirebaseChildEvent)); 176 | testSubscriber.assertCompleted(); 177 | testSubscriber.unsubscribe(); 178 | } 179 | 180 | @Test public void testObserveChildMoved() { 181 | mockFirebaseChildEvent.setEventType(FirebaseChildEvent.EventType.MOVED); 182 | when(spyRxFirebase.observeChildMoved(mockRef)).thenReturn( 183 | Observable.just(mockFirebaseChildEvent)); 184 | 185 | TestSubscriber testSubscriber = new TestSubscriber<>(); 186 | spyRxFirebase.observeChildMoved(mockRef) 187 | .subscribeOn(Schedulers.immediate()) 188 | .subscribe(testSubscriber); 189 | 190 | testSubscriber.assertNoErrors(); 191 | testSubscriber.assertValueCount(1); 192 | testSubscriber.assertReceivedOnNext(Collections.singletonList(mockFirebaseChildEvent)); 193 | testSubscriber.assertCompleted(); 194 | testSubscriber.unsubscribe(); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /server/database.rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | ".read": true, 4 | ".write": false 5 | } 6 | } -------------------------------------------------------------------------------- /server/sample-data.json: -------------------------------------------------------------------------------- 1 | { 2 | "fireblog" : { 3 | "-JRHTHaKuITFIhnj02kE" : { 4 | "author" : "alan", 5 | "title" : "The Turing Machine" 6 | }, 7 | "JRHTHaIs-jNPLXOQivY" : { 8 | "author" : "spiros", 9 | "title" : "Announcing COBOL, a New Programming Language" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':rxfirebase' 2 | --------------------------------------------------------------------------------