undercoverindian
12/27/2017 - 12:46 AM

Firebase API

Realtime Database, Authentication

//read and write - shallower rules override deeper rules
//validate - rules don't cascade, must all evaluate to true to write

- Rule types = ".read", ".write", ".validate"

- Grant write access to "/users/<uid>/"
".write": "$uid === auth.uid"

https://firebase.google.com/docs/reference/security/database/#variables
//before starting, change security rules so that read + write are both true
//when structuring data, flatten data structures instead of nesting them + duplicate for 2 way relationship
//when passing objects, default + custom constructor required

FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference();
DatabaseReference refChild = ref.child("posts");


- WRITE TO THE DATABASE

ref.child("posts").setValue("I can only add one value to branch!");

refChild.push().setValue(Post1);
refChild.push().setValue(Post2);
refChild.push().setValue(Post3);


- REMOVE FROM DATABASE

refChild.removeValue();


- READ FROM DATABASE IN REALTIME

refChild.addValueEventListener(new ValueEventListener() {
//use addListenerForSingleValueEvent to only read once

  @Override
  public void onDataChange(DataSnapshot dataSnapshot) {
      String data = dataSnapshot.getValue(String.class);
  }

  @Override
  public void onCancelled(DatabaseError databaseError) { }

});


- READING ALL VALUES IN SPECIFIC JSON TREE

//add to onDataChange
for (DataSnapshot messageSnapshot : dataSnapshot.getChildren()) {
    String name = (String) messageSnapshot.getValue();
}

//getting values of multiple objects, will loop for all objects in branch
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {

    //make sure to use "Object" instead of "Post"
    Map<String, Object> post = (Map<String, Object>) postSnapshot.getValue();

    String author = post.get("author").toString();
    String content = post.get("content").toString();
    String starCount = post.get("starCount").toString();
  
}
                

- READING A CHILD BRANCH THAT IS ADDED/CHANGED/REMOVED

//triggered once for each existing child, and then every time child added, blog posts
refChild.addChildEventListener(new ChildEventListener() {

    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String s) { }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String s) { }

    @Override
    public void onChildRemoved(DataSnapshot dataSnapshot) { }
    
});


- UPDATING AT THE SAME TIME FOR 2-WAY RELATIONSHIPS

//add following to object class
public Map<String, Object> toMap() {

    HashMap<String, Object> result = new HashMap<>();

    result.put("content", content);
    result.put("author", author);
    result.put("size", size);

    return result;
}

//add following to main class
Post post = new Post("Hello", "Ishan", 10);
String key = refChild.push().getKey();

Map<String, Object> postValues = post.toMap();

Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/posts/" + key, postValues);
childUpdates.put("/user-posts/" + post.getAuthor(), key);

ref.updateChildren(childUpdates);


- SORT DATA IN ASCENDING ORDER

Query sorted = refChild.orderByChild("starCount");
//can also orderByKey on a specific branch

sorted.addChildEventListener(new ChildEventListener() {

    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String s) {

        Map<String, Object> hash = (Map<String, Object>) dataSnapshot.getValue();
        //each hash represents a separate post

        String author = hash.get("author").toString();
        String content = hash.get("content").toString();
        String starCount = hash.get("starCount").toString();

        Log.d("map", author + ", " + content + ", " + starCount);

    }
});


- OFFLINE BEHAVIOR 

FirebaseDatabase.getInstance().setPersistenceEnabled(true);

ref.keepSynced(true);

DatabaseReference connected = database.getReference((".info/connected"));
connected.addValueEventListener(new ValueEventListener() {
   
    @Override
    public void onDataChange(DataSnapshot snapshot) {
        boolean connected = snapshot.getValue(Boolean.class);
        
        if (connected) 
           Log.d("connection", "yes");
           
        else 
            Log.d("connection", "no");
    }
});
1. Firebase Console -> Create a project -> Add Firebase to your Android app 
2. Download google-services.JSON and add to "app directory" 
3. Add dependencies to project gradle - "classpath 'com.google.gms:google-services:3.0.0'"
4. Add to bottom of app gradle - "apply plugin: 'com.google.gms.google-services'"

ADD DEPENDENCIES IN APP GRADLE FOR WHATEVER FIREBASE FEAUTURES YOU WISH TO USE (ANALYTICS, REALTIME DATABASE, ETC)
- surprisingly, don't need internet permissions
//NoSuchMethodError -> use same Firebase library versions
//StorageException -> use more specific StorageReference and use ".jpg" + edit permission rules on console


- STORE IMAGE FROM GALLERY/CAMERA 

final int GALLERY_REQUEST_CODE = 1;
final int CAMERA_REQUEST_CODE = 2;

FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference storageRef = storage.getReferenceFromUrl("gs://test-caae7.appspot.com");
UploadTask uploadTask;

final Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
final Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);

galleryButton.setOnClickListener((view) {
    startActivityForResult(galleryIntent, 1);
});

cameraButton.setOnClickListener((view) {
    startActivityForResult(cameraIntent, 2);
});

//generate method
protected void onActivityResult {

    String name = "test";
    StorageReference picRef = storageRef.child("images/" + name + ".jpg");
    
    //surround with try catch
    switch (requestCode) {

      case GALLERY_REQUEST_CODE: {
          Uri path = data.getData();

          StorageMetadata metadata = new StorageMetadata.Builder().setContentType("image/jpg").build();
          uploadTask = picRef.putFile(path, metadata);
          break;
      }

      case CAMERA_REQUEST_CODE: {
          Bitmap pictureObject = (Bitmap) data.getExtras().get("data");
          ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
          pictureObject.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
          byte[] byteArray = outputStream.toByteArray();
          
          StorageMetadata metadata = new StorageMetadata.Builder().setContentType("image/jpg").build();
          uploadTask = picRef.putBytes(byteArray, metadata);
          break;
      }
      
    }
    
    uploadTask.addOnFailureListener(new OnFailureListener() {
            
            @Override
            public void onFailure(@NonNull Exception e) { }
            
        }).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
           
            @Override
            public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { 
                Uri downloadUrl = taskSnapshot.getDownloadUrl();  
            }
       
    });
}


- MONITOR + MODIFY UPLOAD PROGRESS

uploadTask.pause();
uploadTask.resume();
uploadTask.cancel();

uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
    
    @Override
    public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
        double total = taskSnapshot.getTotalByteCount();
        double current = taskSnapshot.getBytesTransferred();
        double progress = (100.0 * (current/total));
    }
    
}).addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() {
    
    @Override
    public void onPaused(UploadTask.TaskSnapshot taskSnapshot) { }
});


- DOWNLOAD A FILE BYTE[]

//ten megabytes
long maxSize = 1024 * 1024 * 10;

picRef.getBytes(maxSize).addOnSuccessListener(new OnSuccessListener<byte[]>() {
   
    @Override
    public void onSuccess(byte[] bytes) {
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        imageView.setImageBitmap(bitmap);
    }
    
}).addOnFailureListener(new OnFailureListener() {
   
    @Override
    public void onFailure(@NonNull Exception e) { }
});


- DELETE A FILE

picRef.delete().addOnSuccessListener(new OnSuccessListener() {
  
    @Override
    public void onSuccess(Void aVoid) { }
    
}).addOnFailureListener(new OnFailureListener() {
   
    @Override
    public void onFailure(@NonNull Exception exception) { }
});
//enable sign-in providers in Firebase Console -> Sign-In Method
//for creating account + signing in, must put code in separate method


- CREATE AN ACCOUNT WITH EMAIL/PASSWORD

final FirebaseAuth auth = FirebaseAuth.getInstance();

//password minimum 8 characters
auth.createUserWithEmailAndPassword(email, password)
    .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {

        @Override
        public void onComplete(@NonNull Task<AuthResult> task) {

            if (!task.isSuccessful()) { }
               
        }
});
    

- SIGN IN WITH EMAIL/PASSWORD

//if login does not occur, update Google Play Services on device

final FirebaseAuth auth = FirebaseAuth.getInstance();

auth.signInWithEmailAndPassword(email, password)
    .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {

        @Override
        public void onComplete(@NonNull Task<AuthResult> task) {

            if (!task.isSuccessful())
                Log.d("Error", "Not successful");

            else
                Log.d("Message", "Successful");

        }
});


- CHECK SIGN-IN STATE

FirebaseAuth.AuthStateListener listener;

listener = new FirebaseAuth.AuthStateListener() {
    @Override
    public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
        
        FirebaseUser user = firebaseAuth.getCurrentUser();

        //user is signed in
        if (user != null)
        
        //user is not signed in
        else
    }
};

OnStart() ->  auth.addAuthStateListener(listener);

onStop() ->  if (listener != null)
                   auth.removeAuthStateListener(listener);
                   

- SIGN OUT USER

FirebaseAuth.getInstance().signOut();


- GET USER PROFILE FOR FIREBASE ACCOUNT

FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();

if (user != null) {
  
    String name = user.getDisplayName();
    String email = user.getEmail();
    Uri photoUrl = user.getPhotoUrl();
    String uid = user.getUid();
}


- SIGN IN WITH FACEBOOK

1. Go to Facebook Developers site + create app, follow "Get Started" guide
2. Add Gradle dependencies, App ID to strings.xml, meta-data to manifest, internet permissions
3. Add "FacebookSdk.sdkInitialize(getApplicationContext());" before setContentView()
4. Enable Facebook sign-in on Firebase and add enter App ID/App Secret
5. Within Facebook console, add product -> Facebook login -> link from Firebase
6. Add "com.facebook.login.widget.LoginButton" to layout file

public CallbackManager callback = CallbackManager.Factory.create();
public FirebaseAuth auth = FirebaseAuth.getInstance();

LoginButton loginButton = (LoginButton) findViewById(R.id.login_button);
loginButton.setReadPermissions("email", "public_profile");

loginButton.registerCallback(callback, new FacebookCallback<LoginResult>() {

    @Override
    public void onSuccess(LoginResult loginResult) {
        Log.d("message", "facebook:onSuccess:" + loginResult);
        handleFacebookAccessToken(loginResult.getAccessToken());
    }

    @Override
    public void onCancel() { }

    @Override
    public void onError(FacebookException error) {  }
});

onActivityResult() ->  callback.onActivityResult(requestCode, resultCode, data);

private void handleFacebookAccessToken(AccessToken token) {

    AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());

    auth.signInWithCredential(credential).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
    
       @Override
       public void onComplete(@NonNull Task<AuthResult> task) {
           Log.d("login", "signInWithCredential:onComplete:" + task.isSuccessful());

           if (!task.isSuccessful())
               Log.w("login", "signInWithCredential", task.getException());
       }
   });
}

Incorrect hash -> http://stackoverflow.com/questions/16767672/key-hash-doesnt-match-while-facebook-login-in-android


- GET USER PROFILE FOR FACEBOOK/GOOGLE ACCOUNT

FirebaseUser user = auth.getCurrentUser();

if (user != null) {

    for (UserInfo profile : user.getProviderData()) {
    
        String providerID = profile.getProviderId();
        String providerUID = profile.getUid();
        String name = profile.getDisplayName();
        Uri photoURL = profile.getPhotoUrl();
        
        String userID = user.getUid();
        String email = user.getEmail();
    }
}