Welcome to the sixth part of the Firebase Authentication series. In the previous part I showed you how to send a verification email in android studio. In this part I will show you how to change a profile picture. We are going to add a welcome screen in our Authenticated Goose app that will be shown when a user is registering and logged in for the first time. In that screen, they will be given the option to upload a profile picture. They will also be able to change the picture anytime in the main activity.
Let's begin by creating a new Java class and name it WelcomeFragment, place it in the fragment folder in company with LoginFragment and RegisterFragment.
WelcomeFragment.java
package com.frogitecture.authenticatedgoose.Fragments;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.frogitecture.authenticatedgoose.MainActivity;
import com.frogitecture.authenticatedgoose.R;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.UserProfileChangeRequest;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import static android.app.Activity.RESULT_OK;
public class WelcomeFragment extends Fragment {
private interface PictuteListener {
void onProfilePictureUpdated();
}
private PictuteListener pictureListener;
private final int PICK_IMAGE = 100;
private FirebaseUser firebaseUser;
private TextView displayNameTxt;
private ImageView imageView;
private Button skipBtn;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View parentView = inflater.inflate(R.layout.fragment_welcome, container, false);
displayNameTxt = parentView.findViewById(R.id.display_name);
imageView = parentView.findViewById(R.id.image);
skipBtn = parentView.findViewById(R.id.skip_btn);
final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
if (firebaseAuth.getCurrentUser() != null) {
firebaseUser = firebaseAuth.getCurrentUser();
}
displayNameTxt.setText(firebaseUser.getDisplayName());
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openGallery();
}
});
skipBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().finish();
startActivity(new Intent(getActivity(), MainActivity.class));
}
});
pictureListener = new PictuteListener() {
@Override
public void onProfilePictureUpdated() {
Uri uri = firebaseUser.getPhotoUrl();
Glide.with(getActivity()).load(uri).into(imageView);
skipBtn.setBackgroundColor(Color.parseColor("#2c8bff"));
skipBtn.setText("done");
}
};
return parentView;
}
private void openGallery() {
Intent gallery = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
startActivityForResult(gallery, PICK_IMAGE);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == PICK_IMAGE) {
final Uri imageUri = data.getData();
updateUserProfilePicture(imageUri);
}
}
private void updateUserProfilePicture(final Uri uri) {
UserProfileChangeRequest profileChangeRequest = new UserProfileChangeRequest.Builder()
.setPhotoUri(uri)
.build();
firebaseUser.updateProfile(profileChangeRequest)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
pictureListener.onProfilePictureUpdated();
}
}
});
}
}
We got an interface called PictureListener with the method onProfilePictureUpdated() that will be called when a user has selected a picture and the picture has been uploaded. First thing we do in the onCreateView method is to initialize the necessary variables, including FirebaseUser so we can update the users picture.
displayNameTxt = parentView.findViewById(R.id.display_name);
imageView = parentView.findViewById(R.id.image);
skipBtn = parentView.findViewById(R.id.skip_btn);
final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
if (firebaseAuth.getCurrentUser() != null) {
firebaseUser = firebaseAuth.getCurrentUser();
}
We check if the user is signed in here. This should always be true, but to dodge any errors we make sure getCurrentUser doesn't return null. If you're making a real app out of this you probably want to send the user to the register screen in an else block here, because uploading a picture to null won't make any sense. The displayNameTxt is updated so we can welcome them by their name:
displayNameTxt.setText(firebaseUser.getDisplayName());
The ImageView is currently showing us a picture of a goose, with a text under it telling the user to click on the image in order to choose a profile picture. To make it respond to our click, we attach a click listener to it.
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openGallery();
}
});
When clicked, a method openGallery()
is called that is defined later in the code. A skip button is located in the bottom right that the users can click on if they don't want to choose a profile picture yet.
skipBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().finish();
startActivity(new Intent(getActivity(), MainActivity.class));
}
});
If that's what they choose to do, we just call finish() and send them to the main activity. Then we declare the interface PictureListener.
pictureListener = new PictuteListener() {
@Override
public void onProfilePictureUpdated() {
Uri uri = firebaseUser.getPhotoUrl();
Glide.with(getActivity()).load(uri).into(imageView);
skipBtn.setBackgroundColor(Color.parseColor("#2c8bff"));
skipBtn.setText("done");
}
};
Here we get the photo url by calling firebaseUser.getPhotoUrl()
, and use Glide to show the uploaded image instead of the goose. The button text skip is also changed to done. The openGallery()
method that is called when a user clicks on the ImageView will only be responsible for opening the gallery.
private void openGallery() {
Intent gallery = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
startActivityForResult(gallery, PICK_IMAGE);
}
startActivityForResult(gallery, PICK_IMAGE)
makes it possible to get a response when a picture is selected. PICK_IMAGE is a global int that we declared before with the value 100. This value could be anything, as long as it's the same value we compare with the requestCode in the following method:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == PICK_IMAGE) {
final Uri imageUri = data.getData();
updateUserProfilePicture(imageUri);
}
}
onActivityResult
is called when a picture is selected, and we check if the result is valid and if the requestCode is the one we are looking for. If it is, we pass the selected image uri to updateUserProfilePicture
that is defined below.
private void updateUserProfilePicture(final Uri uri) {
UserProfileChangeRequest profileChangeRequest = new UserProfileChangeRequest.Builder()
.setPhotoUri(uri)
.build();
firebaseUser.updateProfile(profileChangeRequest)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
pictureListener.onProfilePictureUpdated();
}
}
});
}
Here's where the picture is uploaded to firebase. First a UserProfileChangeRequest
object is created, where we tell it to change the profile picture to the uri we sent as an argument. Then firebaseUser.updateProfile is called with this object as a parameter. If successful, pictureListener.onProfilePictureUpdated()
is called, where the picture is replacing the goose. We go through the same process in the main activity.
MainActivity.java
package com.frogitecture.authenticatedgoose;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.frogitecture.authenticatedgoose.DialogFragments.LoadingDialog;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.UserProfileChangeRequest;
public class MainActivity extends AppCompatActivity {
private final int PICK_IMAGE = 100;
private FirebaseAuth firebaseAuth;
private FirebaseUser firebaseUser;
LoadingDialog loadingDialog;
private ImageView imageView;
private TextView displayNameTxt;
private TextView useridTxt;
private TextView emailTxt;
private TextView verifiedTxt;
private TextView sendVerificationTxt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
firebaseAuth = FirebaseAuth.getInstance();
if (firebaseAuth.getCurrentUser() == null) {
finish();
startActivity(new Intent(this, AuthActivity.class));
return;
} else {
firebaseUser = firebaseAuth.getCurrentUser();
}
loadingDialog = new LoadingDialog();
imageView = findViewById(R.id.image);
useridTxt = findViewById(R.id.uid_txt);
displayNameTxt = findViewById(R.id.edittext);
emailTxt = findViewById(R.id.email_txt);
verifiedTxt = findViewById(R.id.verified_txt);
sendVerificationTxt = findViewById(R.id.send_verification_txt);
Uri profilePicture = firebaseUser.getPhotoUrl();
String uid = firebaseUser.getUid();
String displayName = firebaseUser.getDisplayName();
final String email = firebaseUser.getEmail();
String verifiedEmail = "No";
if (firebaseUser.isEmailVerified()) {
verifiedEmail = "Yes";
sendVerificationTxt.setVisibility(View.GONE);
} else {
sendVerificationTxt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
firebaseAuth.sendPasswordResetEmail(email)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(MainActivity.this, "Email sent! Check your inbox", Toast.LENGTH_SHORT).show();
}
}
});
}
});
}
Glide.with(this).load(profilePicture).into(imageView);
useridTxt.setText(uid);
displayNameTxt.setText(displayName);
emailTxt.setText(email);
verifiedTxt.setText(verifiedEmail);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitle("Authenticated Goose");
setSupportActionBar(toolbar);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.change_profile_picture:
openGallery();
break;
case R.id.change_display_name:
break;
case R.id.change_email:
break;
case R.id.change_password:
break;
case R.id.delete_account:
break;
case R.id.sign_out:
FirebaseAuth.getInstance().signOut();
finish();
startActivity(new Intent(MainActivity.this, AuthActivity.class));
break;
}
return super.onOptionsItemSelected(item);
}
private void openGallery() {
Intent gallery = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
startActivityForResult(gallery, PICK_IMAGE);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == PICK_IMAGE) {
final Uri imageUri = data.getData();
updateUserProfilePicture(imageUri);
}
}
private void updateUserProfilePicture(final Uri uri) {
loadingDialog.setMessage("Changing profile picture...");
loadingDialog.show(getSupportFragmentManager(),"Changing Profile Picture");
UserProfileChangeRequest profileChangeRequest = new UserProfileChangeRequest.Builder()
.setPhotoUri(uri)
.build();
firebaseUser.updateProfile(profileChangeRequest)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
onChangedProfilePicture(uri);
}
loadingDialog.dismiss();
}
});
}
public void onChangedProfilePicture(Uri uri) {
Glide.with(this).load(uri).into(imageView);
}
}
When a user clicks on the Change profile picture item in the toolbar, openGallery()
is called. openGallery, onActivityResult, updateuserProfilePicture and onChangedProfilePicture are almost identical to the similar methods in WelcomeFragment, so this class shouldn't be hard to follow now. I just added a LoadingDialog to inform the users that the app is processing.
In the next part I will show you how to change a users display name.
Author
2020-06-21
Changing a display name in Android Studio with firebase auth
Changing email in Android with Firebase Authentication
Changing a password in Android with Firebase Authentication
Deleting an account in Android with Firebase Authentication