In my firebase application and I have an issue unable to solve.
In my AccountFragment Im trying to upload an user profile image - After selecting the image, the application craches. Please help me fix this
I have been on this for days now, Im really lost here.
The application only crashes when I try to upload an image, When I try to update name, phone number, or email - All is working fine
package com.company.walt.fragments;
public class AccountFragment extends BaseFragment implements
ChangePhotoDialog.OnPhotoReceivedListener {
// Statics
private static final String TAG = "AccountFragment";
private static final int REQUEST_CODE = 1234;
private static final double MB_THRESHHOLD = 5.0;
private static final double MB = 1000000.0;
// Widgets
private ImageView mProfileImage;
private EditText mName;
private EditText mEmail;
private EditText mPhone;
private EditText mConfirm;
private Button mUpdateBtn;
// Vars
private boolean mStoragePermissions;
private Uri mSelectedImageUri;
private Bitmap mSelectedImageBitmap;
private byte[] mBytes;
private double progress;
public AccountFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_account, container, false);
mProfileImage = (ImageView)view.findViewById(R.id.user_img);
mName = (EditText) view.findViewById(R.id.input_name);
mEmail = (EditText) view.findViewById(R.id.input_email);
mPhone = (EditText) view.findViewById(R.id.input_phone);
mConfirm = (EditText) view.findViewById(R.id.input_confirm);
mUpdateBtn = (Button) view.findViewById(R.id.btn_update);
setupFirebaseAuth();
updateInformation();
hideSoftKeyboard();
return view;
}
private void updateInformation(){
mProfileImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mStoragePermissions){
ChangePhotoDialog dialog = new ChangePhotoDialog();
dialog.show(getChildFragmentManager(), "ChangePhotoDialog");
}else{
verifyStoragePermissions();
}
}
});
mUpdateBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d(TAG, "onClick: Attempting to save settings");
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
// If user only wants to update name
if (!isEmpty(mName.getText().toString())) {
reference.child(getString(R.string.dbnode_users))
.child(FirebaseAuth.getInstance().getCurrentUser().getUid())
.child(getString(R.string.field_name))
.setValue(mName.getText().toString());
Toast.makeText(getActivity(), "Your name have been updated", Toast.LENGTH_SHORT).show();
}
// If user only wants to update phone
if (!isEmpty(mPhone.getText().toString())) {
reference.child(getString(R.string.dbnode_users))
.child(FirebaseAuth.getInstance().getCurrentUser().getUid())
.child(getString(R.string.field_phone))
.setValue(mPhone.getText().toString());
Toast.makeText(getActivity(), "Your phone have been updated", Toast.LENGTH_SHORT).show();
}
// If user only wants to update email
if (!isEmpty(mEmail.getText().toString())
&& !isEmpty(mConfirm.getText().toString())) {
updateUserEmailOnly();
}
if (!isEmpty(mEmail.getText().toString())
&& isEmpty(mConfirm.getText().toString())) {
Toast.makeText(getActivity(), "You must enter password to change email", Toast.LENGTH_SHORT).show();
}
else if (isEmpty(mEmail.getText().toString())
&& !isEmpty(mConfirm.getText().toString())) {
Toast.makeText(getActivity(), "You only entered password, nothing will happen", Toast.LENGTH_SHORT).show();
}
/*
------ Upload the New Photo -----
*/
if(mSelectedImageUri != null){
uploadNewPhoto(mSelectedImageUri);
}else if(mSelectedImageBitmap != null){
uploadNewPhoto(mSelectedImageBitmap);
}
}
});
}
/**
* Uploads a new profile photo to Firebase Storage using a @param ***imageUri***
* @param imageUri
*/
public void uploadNewPhoto(Uri imageUri){
/*
upload a new profile photo to firebase storage
*/
Log.d(TAG, "uploadNewPhoto: uploading new profile photo to firebase storage.");
//Only accept image sizes that are compressed to under 5MB. If thats not possible
//then do not allow image to be uploaded
BackgroundImageResize resize = new BackgroundImageResize(null);
resize.execute(imageUri);
}
/**
* Uploads a new profile photo to Firebase Storage using a @param ***imageBitmap***
* @param imageBitmap
*/
public void uploadNewPhoto(Bitmap imageBitmap){
/*
upload a new profile photo to firebase storage
*/
Log.d(TAG, "uploadNewPhoto: uploading new profile photo to firebase storage.");
//Only accept image sizes that are compressed to under 5MB. If thats not possible
//then do not allow image to be uploaded
BackgroundImageResize resize = new BackgroundImageResize(imageBitmap);
Uri uri = null;
resize.execute(uri);
}
/**
* 1) doinBackground takes an imageUri and returns the byte array after compression
* 2) onPostExecute will print the % compression to the log once finished
*/
public class BackgroundImageResize extends AsyncTask<Uri, Integer, byte[]> {
Bitmap mBitmap;
public BackgroundImageResize(Bitmap bm) {
if(bm != null){
mBitmap = bm;
}
}
@Override
protected void onPreExecute() {
super.onPreExecute();
showProgress();
Toast.makeText(getActivity(), "compressing image", Toast.LENGTH_SHORT).show();
}
@Override
protected byte[] doInBackground(Uri... params ) {
Log.d(TAG, "doInBackground: started.");
if(mBitmap == null){
try {
mBitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), params[0]);
Log.d(TAG, "doInBackground: bitmap size: megabytes: " + mBitmap.getByteCount()/MB + " MB");
} catch (IOException e) {
Log.e(TAG, "doInBackground: IOException: ", e.getCause());
}
}
byte[] bytes = null;
for (int i = 1; i < 11; i++){
if(i == 10){
Toast.makeText(getActivity(), "That image is too large.", Toast.LENGTH_SHORT).show();
break;
}
bytes = getBytesFromBitmap(mBitmap,100/i);
Log.d(TAG, "doInBackground: megabytes: (" + (11-i) + "0%) " + bytes.length/MB + " MB");
if(bytes.length/MB < MB_THRESHHOLD){
return bytes;
}
}
return bytes;
}
@Override
protected void onPostExecute(byte[] bytes) {
super.onPostExecute(bytes);
hideProgress();
mBytes = bytes;
//execute the upload
executeUploadTask();
}
}
// convert from bitmap to byte array
public static byte[] getBytesFromBitmap(Bitmap bitmap, int quality) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream);
return stream.toByteArray();
}
private void executeUploadTask(){
showProgress();
FilePaths filePaths = new FilePaths();
//specify where the photo will be stored
final StorageReference storageReference = FirebaseStorage.getInstance().getReference()
.child(filePaths.FIREBASE_USER_IMAGE_STORAGE + "/" + FirebaseAuth.getInstance().getCurrentUser().getUid()
+ "/profile_image"); //just replace the old image with the new one
if(mBytes.length/MB < MB_THRESHHOLD) {
// Create file metadata including the content type
StorageMetadata metadata = new StorageMetadata.Builder()
.setContentType("image/jpg")
.setContentLanguage("en") //see nodes below
/*
Make sure to use proper language code ("English" will cause a crash)
I actually submitted this as a bug to the Firebase github page so it might be
fixed by the time you watch this video. You can check it out at https://github.com/firebase/quickstart-unity/issues/116
*/
.setCustomMetadata("Mitch's special meta data", "JK nothing special here")
.setCustomMetadata("location", "Iceland")
.build();
//if the image size is valid then we can submit to database
UploadTask uploadTask = null;
uploadTask = storageReference.putBytes(mBytes, metadata);
//uploadTask = storageReference.putBytes(mBytes); //without metadata
uploadTask.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
@Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
//Now insert the download url into the firebase database
Uri firebaseURL = taskSnapshot.getDownloadUrl();
Toast.makeText(getActivity(), "Upload Success", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onSuccess: firebase download url : " + firebaseURL.toString());
FirebaseDatabase.getInstance().getReference()
.child(getString(R.string.dbnode_users))
.child(FirebaseAuth.getInstance().getCurrentUser().getUid())
.child(getString(R.string.field_profile_image))
.setValue(firebaseURL.toString());
hideProgress();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
Toast.makeText(getActivity(), "could not upload photo", Toast.LENGTH_SHORT).show();
hideProgress();
}
}).addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
@Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
double currentProgress = (100 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
if(currentProgress > (progress + 15)){
progress = (100 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
Log.d(TAG, "onProgress: Upload is " + progress + "% done");
Toast.makeText(getActivity(), progress + "%", Toast.LENGTH_SHORT).show();
}
}
})
;
}else{
Toast.makeText(getActivity(), "Image is too Large", Toast.LENGTH_SHORT).show();
}
}
/**
* Generalized method for asking permission. Can pass any array of permissions
*/
public void verifyStoragePermissions(){
Log.d(TAG, "verifyPermissions: asking user for permissions.");
String[] permissions = {
android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA};
if (ContextCompat.checkSelfPermission(this.getActivity(),
permissions[0] ) == PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this.getActivity(),
permissions[1] ) == PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this.getActivity(),
permissions[2] ) == PackageManager.PERMISSION_GRANTED) {
mStoragePermissions = true;
}
else {
ActivityCompat.requestPermissions(getActivity(), permissions, REQUEST_CODE);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Log.d(TAG, "onRequestPermissionsResult: requestCode: " + requestCode);
switch(requestCode){
case REQUEST_CODE:
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
Log.d(TAG, "onRequestPermissionsResult: User has allowed permission to access: " + permissions[0]);
}
break;
}
}
@Override
public void getImagePath(Uri imagePath) {
if( !imagePath.toString().equals("")){
mSelectedImageBitmap = null;
mSelectedImageUri = imagePath;
Log.d(TAG, "getImagePath: got the image uri: " + mSelectedImageUri);
ImageLoader.getInstance().displayImage(imagePath.toString(), mProfileImage);
}
}
@Override
public void getImageBitmap(Bitmap bitmap) {
if(bitmap != null){
mSelectedImageUri = null;
mSelectedImageBitmap = bitmap;
Log.d(TAG, "getImageBitmap: got the image bitmap: " + mSelectedImageBitmap);
mProfileImage.setImageBitmap(bitmap);
}
}
/*
* **********************************************************************************************
* USER OPTION METHODS
* */
/**
* Update Email Only
*/
private void updateUserEmailOnly() {
showProgress();
AuthCredential credential = EmailAuthProvider
.getCredential(FirebaseAuth.getInstance().getCurrentUser().getEmail(), mConfirm.getText().toString());
FirebaseAuth.getInstance().getCurrentUser().reauthenticate(credential)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "onComplete: reauthenticate success.");
///////////////////now check to see if the email is not already present in the database
FirebaseAuth.getInstance().fetchProvidersForEmail(mEmail.getText().toString()).addOnCompleteListener(
new OnCompleteListener<ProviderQueryResult>() {
@Override
public void onComplete(@NonNull Task<ProviderQueryResult> task) {
if (task.isSuccessful()) {
///////// getProviders().size() will return size 1 if email ID is in use.
Log.d(TAG, "onComplete: RESULT: " + task.getResult().getProviders().size());
if (task.getResult().getProviders().size() == 1) {
Log.d(TAG, "onComplete: That email is already in use.");
hideProgress();
Toast.makeText(getActivity(), "That email is already in use", Toast.LENGTH_SHORT).show();
} else {
Log.d(TAG, "onComplete: That email is available.");
/////////////////////add new email
FirebaseAuth.getInstance().getCurrentUser().updateEmail(mEmail.getText().toString())
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "onComplete: User email address updated.");
Toast.makeText(getActivity(), "Updated email", Toast.LENGTH_SHORT).show();
sendVerificationEmail();
FirebaseAuth.getInstance().signOut();
} else {
Log.d(TAG, "onComplete: Could not update email.");
Toast.makeText(getActivity(), "unable to update email", Toast.LENGTH_SHORT).show();
}
hideProgress();
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
hideProgress();
Toast.makeText(getActivity(), "unable to update email", Toast.LENGTH_SHORT).show();
}
});
}
}
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
hideProgress();
Toast.makeText(getActivity(), "“unable to update email”", Toast.LENGTH_SHORT).show();
}
});
} else {
Log.d(TAG, "onComplete: Incorrect Password");
Toast.makeText(getActivity(), "Incorrect Password", Toast.LENGTH_SHORT).show();
hideProgress();
}
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
hideProgress();
Toast.makeText(getActivity(), "“unable to update email”", Toast.LENGTH_SHORT).show();
}
});
}
/**
* sends an email verification link to the user
*/
public void sendVerificationEmail() {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
user.sendEmailVerification()
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(getActivity(), "Sent Verification Email", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getActivity(), "Couldn't Verification Send Email", Toast.LENGTH_SHORT).show();
}
}
});
}
}
/**
* Return true if the @param is null
* @param string
* @return
*/
private boolean isEmpty(String string) {
return string.equals("");
}
/*
* **********************************************************************************************
* INHERITED METHODS
* */
/**
* Display progressbar
*/
protected void showProgress() {
if (getActivity() instanceof IProgressDisplay) {
((IProgressDisplay) getActivity()).showProgress();
}
}
/**
* Hide progressbar
*/
protected void hideProgress() {
if (getActivity() instanceof IProgressDisplay) {
((IProgressDisplay) getActivity()).hideProgress();
}
}
/**
* Hide softKeyboard
*/
protected void hideSoftKeyboard() {
if (getActivity() instanceof ISoftKeyboard) {
((ISoftKeyboard) getActivity()).hideSoftKeyboard();
}
}
/**
* Firebase Auth
*/
protected void setupFirebaseAuth() {
if (getActivity() instanceof IFirebaseAuth) {
((IFirebaseAuth) getActivity()).setupFirebaseAuth();
}
}
}
This is the LogCat
01-02 20:34:41.590 16223-16223/com.company.walt E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.company.walt, PID: 16223
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=73888, result=-1, data=Intent { dat=content://com.android.providers.media.documents/document/image:672 flg=0x1 }} to activity {com.company.walt/com.company.walt.activities.MainActivity}: java.lang.NullPointerException: Attempt to invoke interface method 'void com.company.walt.Dialogs.ChangePhotoDialog$OnPhotoReceivedListener.getImagePath(android.net.Uri)' on a null object reference
at android.app.ActivityThread.deliverResults(ActivityThread.java:4528)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4571)
at android.app.ActivityThread.-wrap19(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1744)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6809)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'void com.company.walt.Dialogs.ChangePhotoDialog$OnPhotoReceivedListener.getImagePath(android.net.Uri)' on a null object reference
at com.company.walt.Dialogs.ChangePhotoDialog.onActivityResult(ChangePhotoDialog.java:78)
at android.support.v4.app.FragmentActivity.onActivityResult(FragmentActivity.java:151)
at android.app.Activity.dispatchActivityResult(Activity.java:7267)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4524)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4571)
at android.app.ActivityThread.-wrap19(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1744)
at android.os.Looper.loop(Looper.java:164)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
01-02 20:34:41.591 468-468/? W/auditd: type=1400 "memtrack@1.0-se""mem""debugfs"