I was trying to use Firebase Storage to change the Profile Image by selecting one form the device and uploading it, but when i click on the Select Image button i get an Error “Permission denied. Unable to select image. ” Someone can help me thanks in advance.
package it.unich.s3221238.tesi;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.bumptech.glide.Glide;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
public class ProfileActivity extends AppCompatActivity {
private static final int PICK_IMAGE_REQUEST = 1;
private static final int REQUEST_PERMISSION_CODE = 2;
private static final int EDIT_PROFILE_REQUEST = 3;
private static final String TAG = "ProfileActivity";
private TextView profileName, profileEmail, profileUsername;
private ImageView profileImg;
private Button selectImageButton, uploadImageButton, editProfile, homeButton;
private Uri imageUri;
private String currentUsername;
private StorageReference storageReference;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
profileName = findViewById(R.id.profileName);
profileEmail = findViewById(R.id.profileEmail);
profileUsername = findViewById(R.id.profileUsername);
profileImg = findViewById(R.id.profileImg);
selectImageButton = findViewById(R.id.selectImageButton);
uploadImageButton = findViewById(R.id.uploadImageButton);
editProfile = findViewById(R.id.editButton);
homeButton = findViewById(R.id.homeButton);
storageReference = FirebaseStorage.getInstance().getReference();
showAllUserData();
editProfile.setOnClickListener(v -> passUserData());
homeButton.setOnClickListener(v -> finish());
selectImageButton.setOnClickListener(v -> {
if (ContextCompat.checkSelfPermission(ProfileActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(ProfileActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_PERMISSION_CODE);
} else {
openImagePicker();
}
});
uploadImageButton.setOnClickListener(v -> {
if (imageUri != null) {
uploadImageToFirebase();
} else {
Toast.makeText(ProfileActivity.this, "Please select an image first", Toast.LENGTH_SHORT).show();
}
});
}
private void showAllUserData() {
Intent intent = getIntent();
String nameUser = intent.getStringExtra("name");
String emailUser = intent.getStringExtra("email");
String usernameUser = intent.getStringExtra("username");
profileName.setText(nameUser);
profileEmail.setText(emailUser);
profileUsername.setText(usernameUser);
currentUsername = usernameUser;
loadProfileImage(); // Load the profile image if available
}
private void passUserData() {
String userUsername = profileUsername.getText().toString().trim();
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("users");
Query checkUserDatabase = reference.orderByChild("username").equalTo(userUsername);
checkUserDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
if (snapshot.exists()) {
String nameFromDB = snapshot.child(userUsername).child("name").getValue(String.class);
String emailFromDB = snapshot.child(userUsername).child("email").getValue(String.class);
String usernameFromDB = snapshot.child(userUsername).child("username").getValue(String.class);
Intent intent = new Intent(ProfileActivity.this, EditProfileActivity.class);
intent.putExtra("name", nameFromDB);
intent.putExtra("email", emailFromDB);
intent.putExtra("username", usernameFromDB);
startActivityForResult(intent, EDIT_PROFILE_REQUEST);
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
Log.e(TAG, "Database error: ", error.toException());
}
});
}
private void openImagePicker() {
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, PICK_IMAGE_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
imageUri = data.getData();
profileImg.setImageURI(imageUri); // Show the selected image immediately
Toast.makeText(ProfileActivity.this, "Image selected", Toast.LENGTH_SHORT).show();
}
if (requestCode == EDIT_PROFILE_REQUEST && resultCode == RESULT_OK && data != null) {
String updatedName = data.getStringExtra("name");
String updatedEmail = data.getStringExtra("email");
String updatedUsername = data.getStringExtra("username");
profileName.setText(updatedName);
profileEmail.setText(updatedEmail);
profileUsername.setText(updatedUsername);
}
}
private void uploadImageToFirebase() {
if (imageUri != null) {
String filePath = "profile_images/" + currentUsername + ".jpg";
Log.d(TAG, "Uploading image to path: " + filePath);
StorageReference profileImageRef = storageReference.child(filePath);
profileImageRef.putFile(imageUri)
.addOnSuccessListener(taskSnapshot -> profileImageRef.getDownloadUrl().addOnSuccessListener(uri -> {
Glide.with(ProfileActivity.this)
.load(uri)
.placeholder(R.drawable.akwhitelogo)
.into(profileImg);
Toast.makeText(ProfileActivity.this, "Image uploaded successfully", Toast.LENGTH_SHORT).show();
}))
.addOnFailureListener(e -> {
Toast.makeText(ProfileActivity.this, "Image upload failed: " + e.getMessage(), Toast.LENGTH_SHORT).show();
Log.e(TAG, "Upload error: ", e);
});
} else {
Toast.makeText(ProfileActivity.this, "No image selected", Toast.LENGTH_SHORT).show();
}
}
private void loadProfileImage() {
if (currentUsername != null) {
String filePath = "profile_images/" + currentUsername + ".jpg";
Log.d(TAG, "Loading image from path: " + filePath);
StorageReference profileImageRef = storageReference.child(filePath);
profileImageRef.getDownloadUrl().addOnSuccessListener(uri -> {
Glide.with(ProfileActivity.this)
.load(uri)
.placeholder(R.drawable.akwhitelogo)
.into(profileImg);
}).addOnFailureListener(e -> {
profileImg.setImageResource(R.drawable.akwhitelogo);
Log.e(TAG, "Failed to load profile image: ", e);
});
} else {
profileImg.setImageResource(R.drawable.akwhitelogo);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSION_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openImagePicker();
} else {
Toast.makeText(this, "Permission denied. Unable to select image.", Toast.LENGTH_SHORT).show();
}
}
}
}
This is my Profile class, it shows no errors
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="it.unich.s3221238.tesi">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Material3.Light"
tools:targetApi="31">
<activity
android:name=".SignupActivity"
android:theme="@style/Theme.Material3.Light.NoActionBar"
android:exported="false" />
<activity
android:name=".LoginActivity"
android:exported="true"
android:label="@string/title_activity_login"
android:theme="@style/Theme.Material3.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ProfileActivity"
android:exported="true" />
<activity
android:name=".EditProfileActivity"
android:exported="true" />
<activity
android:name=".Home"
android:exported="true" />
<activity
android:name=".Workout"
android:exported="true" />
<activity
android:name=".ExerciseDetailActivity"
android:exported="true" />
<activity
android:name=".SettingsActivity"
android:exported="true" />
<activity
android:name=".PrivacyActivity"
android:exported="true" />
</application>
</manifest>
And this is the manifest.
This is the logcat error:
StorageException has occurred.
Object does not exist at location.
Code: -13010 HttpResult: 404
2024-08-05 00:37:28.761 10819-10855 StorageException it.unich.s3221238.tesi E { "error": { "code": 404, "message": "Not Found." }}
java.io.IOException: { "error": { "code": 404, "message": "Not Found." }}
at com.google.firebase.storage.network.NetworkRequest.parseResponse(NetworkRequest.java:415)
at com.google.firebase.storage.network.NetworkRequest.parseErrorResponse(NetworkRequest.java:432)
at com.google.firebase.storage.network.NetworkRequest.processResponseStream(NetworkRequest.java:423)
at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:265)
at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:282)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:76)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:68)
at com.google.firebase.storage.GetDownloadUrlTask.run(GetDownloadUrlTask.java:77)
at com.google.firebase.concurrent.LimitedConcurrencyExecutor.lambda$decorate$0$com-google-firebase-concurrent-LimitedConcurrencyExecutor(LimitedConcurrencyExecutor.java:65)
at com.google.firebase.concurrent.LimitedConcurrencyExecutor$$ExternalSyntheticLambda0.run(Unknown Source:4)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at com.google.firebase.concurrent.CustomThreadFactory.lambda$newThread$0$com-google-firebase-concurrent-CustomThreadFactory(CustomThreadFactory.java:47)
at com.google.firebase.concurrent.CustomThreadFactory$$ExternalSyntheticLambda0.run(Unknown Source:4)
at java.lang.Thread.run(Thread.java:1012)
2024-08-05 00:37:28.794 10819-10819 WindowOnBackDispatcher it.unich.s3221238.tesi W sendCancelIfRunning: isInProgress=falsecallback=ImeCallback=ImeOnBackInvokedCallback@236402277 Callback=android.window.IOnBackInvokedCallback$Stub$Proxy@5213cd
2024-08-05 00:37:28.911 10819-10819 ProfileActivity it.unich.s3221238.tesi E Failed to load profile image:
com.google.firebase.storage.StorageException: Object does not exist at location.
at com.google.firebase.storage.network.NetworkRequest.completeTask(NetworkRequest.java:509)
at com.google.firebase.storage.GetDownloadUrlTask.run(GetDownloadUrlTask.java:85)
at com.google.firebase.concurrent.LimitedConcurrencyExecutor.lambda$decorate$0$com-google-firebase-concurrent-LimitedConcurrencyExecutor(LimitedConcurrencyExecutor.java:65)
at com.google.firebase.concurrent.LimitedConcurrencyExecutor$$ExternalSyntheticLambda0.run(Unknown Source:4)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at com.google.firebase.concurrent.CustomThreadFactory.lambda$newThread$0$com-google-firebase-concurrent-CustomThreadFactory(CustomThreadFactory.java:47)
at com.google.firebase.concurrent.CustomThreadFactory$$ExternalSyntheticLambda0.run(Unknown Source:4)
at java.lang.Thread.run(Thread.java:1012)
Caused by: java.io.IOException: { "error": { "code": 404, "message": "Not Found." }}
at com.google.firebase.storage.network.NetworkRequest.parseResponse(NetworkRequest.java:415)
at com.google.firebase.storage.network.NetworkRequest.parseErrorResponse(NetworkRequest.java:432)
at com.google.firebase.storage.network.NetworkRequest.processResponseStream(NetworkRequest.java:423)
at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:265)
at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:282)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:76)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:68)
at com.google.firebase.storage.GetDownloadUrlTask.run(GetDownloadUrlTask.java:77)
at com.google.firebase.concurrent.LimitedConcurrencyExecutor.lambda$decorate$0$com-google-firebase-concurrent-LimitedConcurrencyExecutor(LimitedConcurrencyExecutor.java:65)
at com.google.firebase.concurrent.LimitedConcurrencyExecutor$$ExternalSyntheticLambda0.run(Unknown Source:4)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at com.google.firebase.concurrent.CustomThreadFactory.lambda$newThread$0$com-google-firebase-concurrent-CustomThreadFactory(CustomThreadFactory.java:47)
at com.google.firebase.concurrent.CustomThreadFactory$$ExternalSyntheticLambda0.run(Unknown Source:4)
at java.lang.Thread.run(Thread.java:1012)
I’m new to Firebase thanks for your patience.