I am trying to delete audio recordings that I created before Re-installing my app. I'm using MediaStore.createDeleteRequest() and it successfully shows me a dialog box to ask for permission to delete the files, but when I click "Allow" it doesn't delete the files.
My Audio Recordings are stored in "storage/emulated/0/MUSIC/Wear Voice Recorder/"
This is my code :
public void onClick(View v) {
List<Uri> uris = new ArrayList<>();
for (Recordings rec : selectionList) {
String date = rec.getRecordingDate();
SimpleDateFormat original = new SimpleDateFormat("d MMM yy, hh:mm:ss a");
SimpleDateFormat target = new SimpleDateFormat("yyyyMMdd_HHmmss");
try {
tempDate = original.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
String fileName = rec.getRecordingName() + "_W_" + target.format(tempDate) + ".mp3";
File directory = Environment.getExternalStorageDirectory();
file = new File(directory + File.separator + Environment.DIRECTORY_MUSIC + File.separator + "Wear Voice Recorder");
File[] list = file.listFiles(new FilenameFilter() {
#Override
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".mp3");
}
});
for (File mediaFile : list) {
if (mediaFile.getName().equals(fileName)) {
arrList.remove(rec);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
long mediaID = getFilePathToMediaID(mediaFile.getPath(), RecordingsListActivity.this);
Uri Uri_one =ContentUris.withAppendedId(MediaStore.Audio.Media.getContentUri("internal"), mediaID);
uris.add(Uri_one);
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
try {
mediaFile.delete();
} catch (Exception e) {
Toast.makeText(RecordingsListActivity.this, "Recording Not Found", Toast.LENGTH_SHORT).show();
}
}
}
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
requestDeletePermission(RecordingsListActivity.this, uris);
System.out.println(uris+"");
}
adapter.notifyDataSetChanged();
endSelectionMode();
}
#RequiresApi(api = Build.VERSION_CODES.R)
private void requestDeletePermission(Context context, List<Uri> uri_one) {
PendingIntent pi = MediaStore.createDeleteRequest(context.getContentResolver(), uri_one);
try {
startIntentSenderForResult(pi.getIntentSender(), REQUEST_PERM_DELETE, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
private long getFilePathToMediaID(String path, Context context) {
long id = 0;
ContentResolver cr = context.getContentResolver();
Uri uri = MediaStore.Files.getContentUri("internal");
String selection = MediaStore.Audio.Media.DATA;
String[] selectionArgs = {path};
String[] projection = {MediaStore.Audio.Media._ID};
String sortOrder = MediaStore.Audio.Media.TITLE + " ASC";
Cursor cursor = cr.query(uri, projection, selection + "=?", selectionArgs, null);
if (cursor != null) {
while (cursor.moveToNext()) {
int idIndex = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
id = Long.parseLong(cursor.getString(idIndex));
}
}
return id;
}
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_PERM_DELETE:
if (resultCode == Activity.RESULT_OK) {
Toast.makeText(RecordingsListActivity.this, "Deleted successfully!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(RecordingsListActivity.this, "Failed to delete!", Toast.LENGTH_SHORT).show();
}
break;
}
}
I don't really know much about MediaStore, this is my first app and it's so frustrating to ask for permission to delete files that my app created before I uninstalled and re-installed.
I think there's something wrong with the URI, when I print the URI of different files, the URIs are the same.
It does show me the dialog box to delete the files and it also shows a toast saying "Deleted Successfully!" but the files are still there.
Uri uri = MediaStore.Files.getContentUri("internal");
Try:
Uri uri = MediaStore.Video.Media.getContentUri("internal");
But probably you should change "internal" to MediaStore.VOLUME_EXTERNAL too.
Related
I have an app that allows you to pick an audio file and then load / playback etc.
For some reason certain files do not load, even though they are selectable, and are not unusual file types, for example, I am currently trying an MP3 audio file (6.5mb).
This is the process once selected;
// load audio to SoundController
public void initSound(String audioPath) {
File audioFile = new File(audioPath);
if (audioFile.exists()) {
String s = audioFile.getName();
mFileName = s.substring(0, s.length() - 4);
showProcessDialog();
try {
mSoundController.loadAudio(audioFile.getAbsolutePath());
mSoundController.loadVisualizer(visualizerView, false);
mSoundController.loadVisualizer(visualizerReverseView, true);
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Cannot load audio file", Toast.LENGTH_SHORT).show();
closeProcessDiaglog();
}
} else {
Toast.makeText(getApplicationContext(), "File not found", Toast.LENGTH_SHORT).show();
}
}
The showProcessDialog;
void showProcessDialog() {
isLoadedAudio = false;
prcDialog = new ProgressDialog(this);
prcDialog.setMessage("Please Wait - Loading Audio - if this dialogue appears for more than 15 seconds, your file is not compatible so please try loading a different audio file.");
prcDialog.setCancelable(true);
prcDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "Cancel & Try A Different Audio File",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
} );
prcDialog.show();
}
// Close Process dialog
void closeProcessDiaglog() {
if (prcDialog.isShowing()) {
prcDialog.dismiss();
}
checkAudioLoaded();
}
public void checkAudioLoaded() {
sbSongProcess.setEnabled(mSoundController.isPlaying());
if (mSoundController.isLoadedAudio()) {
playAudio.setEnabled(true);
playAudio.setChecked(mSoundController.isPlaying());
} else {
playAudio.setEnabled(false);
playAudio.setChecked(false);
}
}
Of course also onActivityResult;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == AppicationContants.OPEN_FILE_REQUEST && resultCode == RESULT_OK) {
mPath = data.getStringExtra("Path");
isLoadingFile = true;
}
}
This particular mp3 file, the dialogue shows, however does not ever dismiss and the file does not load, but other files will fire the 'File not found' Toast message found in my initSound method.
I am struggling to understand why, these are audio files that are downloaded onto my device.
The ManagerAudioActivity.java file handles the choosing of the file / opening.
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == AppicationContants.AUDIO_PICK_REQUEST_CODE && resultCode == RESULT_OK) {
try {
Uri uri = data.getData();
String arr1 = uri.toString().substring(0, uri.toString().lastIndexOf("/"));
String id = DocumentsContract.getDocumentId(uri);
String path = FilePath.getPath(this, uri);
File t = null;
// Alternatively, use FileUtils.getFile(Context, Uri)
if (path != null && FileUtils.isLocal(path)) {
t = new File(path);
}
mPath = path;
Toast.makeText(getApplicationContext(), mPath, Toast.LENGTH_LONG).show();
if(checkIfAudio(mPath)) {
if(t.exists()) {
String description = "Tempo:100 Pitch:+0 Key:+0";
Song newSong = new Song(t.getName().substring(0, t.getName().length() -4), description, t.getAbsolutePath());
if(!checkIfExisted(newSong.getName())) {
currentCategory.getSongs().add(newSong);
}
SongAdapter songAdapter = new SongAdapter(ManagerAudioActivity.this, currentCategory.getSongs());
lvListSong.setAdapter(songAdapter);
((CustomAdapter) lvListCategory.getAdapter()).updateItemList(categories);
saveData();
} else {
Toast.makeText(getApplicationContext(), "File not found", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getApplicationContext(), "File in wrong format", Toast.LENGTH_SHORT).show();
}
} catch (Exception ex) {
Toast.makeText(getApplicationContext(), "File not found", Toast.LENGTH_SHORT).show();
}
}
}
public boolean checkIfAudio(String path)
{
boolean result = false;
try {
SoundStreamAudioPlayer audioPlayer = new SoundStreamAudioPlayer(10, path, 1.0f, 0.0f);
result = true;
audioPlayer = null;
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "error="+e.getMessage(), Toast.LENGTH_SHORT).show();
}
return result;
}
public boolean checkIfExisted(String name)
{
if(currentCategory!= null && currentCategory.getSongs().size()>0)
{
for(int i =0 ; i< currentCategory.getSongs().size() ; i++)
{
if(currentCategory.getSongs().get(i).getName().equals(name))
{
return true;
}
}
}
return false;
}
I'm having difficulty simply renaming a file created by the app but was put into the documents folder.
EDIT:
As it so happens the videos are not created by the application but are expected to be renamed by the application. The user drops the videos into the documents folder manually at the start. My mistake.
Here is my code:
public static boolean renameVideoFile(Context c, File from, File to) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try {
Uri fromUri = FileProvider.getUriForFile(c, c.getPackageName() + ".provider", new File(FileUtils.getVideosDir(), from.getName()));
ContentResolver contentResolver = c.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
contentResolver.update(fromUri, contentValues, null, null);
contentValues.clear();
contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, to.getName());
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 0);
contentResolver.update(fromUri, contentValues, null, null);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
} else {
if (from.renameTo(to)) {
removeMedia(c, from);
addMedia(c, to);
return true;
} else {
return false;
}
}
}
I progressed through a few errors but my final error is:
java.lang.UnsupportedOperationException: No external updates
Which is an internal problem with the FileProvider at
at androidx.core.content.FileProvider.update(FileProvider.java:523)
EDIT #2
Also here are my provider declarations in the manifest:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths">
</meta-data>
</provider>
And here is my pathing declarations. Again this is causing no issues for saving:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path
name="internal_images"
path="files/Pictures" />
<external-files-path
name="internal_images_alternate"
path="Pictures" />
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>
EDIT: The external folder I chose was the documents folder FYI
So I did finally get it working. Here is the code to rename a video (it may not be the best but it does the trick!)
private static void tryAddVideosToMediaStore(Activity context) {
List<File> files = MediaUtils.getVideoFilesFromDirectory();
for (File file : files) {
try {
Uri fromUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file);
if (getRealPathFromURI(context, fromUri) == null) {
String nameWoExtension = MediaUtils.getNameWithoutStatus(file.getAbsolutePath());
ContentValues values = new ContentValues(3);
values.put(MediaStore.Video.Media.TITLE, nameWoExtension);
values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
values.put(MediaStore.Video.Media.DATA, file.getAbsolutePath());
context.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = {MediaStore.Images.Media.DATA};
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} catch(Exception e) {
return null;
}finally {
if (cursor != null) {
cursor.close();
}
}
}
And then the calling methods
public static String getVideoNameFromPath(String path) {
return path.substring(path.lastIndexOf("/") + 1, path.indexOf(".mp4"));
}
public static boolean renameVideoFile(MainActivityViewModel viewModel, SharedPreferenceHelper sharedPreferenceHelper, Activity c, File from, File to) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
tryAddVideosToMediaStore(c);
Uri fromUri = MediaUtils.getVideoUriFromFS(c, from);
try {
ContentResolver contentResolver = c.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
contentResolver.update(fromUri, contentValues, null, null);
contentValues.clear();
contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, to.getName());
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 0);
contentResolver.update(fromUri, contentValues, null, null);
return true;
} catch (Exception securityException) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
sharedPreferenceHelper.get().edit().putString("from", from.getAbsolutePath()).putString("to", to.getAbsolutePath()).apply();
RecoverableSecurityException recoverableSecurityException;
viewModel.setContentUri(fromUri);
if (securityException instanceof RecoverableSecurityException) {
recoverableSecurityException =
(RecoverableSecurityException) securityException;
} else {
requestVideoWritePermissions(c, Uri.parse(MediaStore.Video.Media.EXTERNAL_CONTENT_URI + "/" + MediaUtils.getVideoId(c, from)));
return false;
}
IntentSender intentSender = recoverableSecurityException.getUserAction()
.getActionIntent().getIntentSender();
try {
c.startIntentSenderForResult(intentSender, 55,
null, 0, 0, 0);
} catch (Exception e) {
e.printStackTrace();
return false;
}
} else {
throw new RuntimeException(
securityException.getMessage(), securityException);
}
}
return false;
} else {
if (from.renameTo(to)) {
removeMedia(c, from);
addMedia(c, to);
return true;
} else {
return false;
}
}
}
public static Uri getVideoUriFromFS(Context c, File file) {
long id = getFilePathToMediaID(file, c);
Uri fromUri = ContentUris.withAppendedId( MediaStore.Video.Media.EXTERNAL_CONTENT_URI,id);
return fromUri;
}
public static long getFilePathToMediaID(File videoPath, Context context)
{
Uri mainUri;
Cursor cursor1 = context.getContentResolver().query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Video.Media._ID},
MediaStore.Video.Media.DATA + "=? ",
new String[]{videoPath.getAbsolutePath()}, null);
long id = 0;
if (cursor1 != null && cursor1.moveToFirst()) {
id = cursor1.getLong(cursor1.getColumnIndex(MediaStore.MediaColumns._ID));
cursor1.close();
}
return id;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 55) { //rename video request code
if (resultCode == RESULT_OK) {
//update UI
String from = presenter.getFromFilePath();
String to = presenter.getToFilePath();
if (from != null && to != null) {
Uri fromUri = MediaUtils.getVideoUriFromFS(this, new File(from));
ContentResolver contentResolver = getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
contentResolver.update(fromUri, contentValues, null, null);
contentValues.clear();
contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, new File(to).getName());
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 0);
contentResolver.update(fromUri, contentValues, null, null);
//update UI
}
}
}
}
If I forgot something please let me know and I will post it here. It took literally hours of searching to find this solution. I'm quite upset at the simplicity vs the complexity that google has introduced.
EDIT: I Think I forgot this method which was very important
public static boolean requestVideoWritePermissions(Activity activity, Uri fromUri) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
boolean hasPermission = true;
if (activity.checkUriPermission(fromUri, Binder.getCallingPid(), Binder.getCallingUid(),
Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != PackageManager.PERMISSION_GRANTED) {
hasPermission = false;
}
List<Uri> uriList = new ArrayList<>();
uriList.add(fromUri);
if (!hasPermission) {
PendingIntent pi = MediaStore.createWriteRequest(activity.getContentResolver(), uriList);
try {
activity.startIntentSenderForResult(pi.getIntentSender(), 55, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
return false;
}
return true;
}
return true;
}
I should also mention each video is a prompt this way. The user chooses whether or not to allow you to overwrite each video which was less than optimal. I wish I could just do a whole folder of external access but I'm guessing that's not going to happen with scoped storage changes.
Since I see this is a very popular question, I'm going to go ahead and update what I changed to be doing since some of this code is deprecated or not working.
First In Your build.gradle file, implement the SAF framework's DocumentFile class:
implementation 'androidx.documentfile:documentfile:1.0.1'
Next Call this method which request permissions for the SAF to operate (You will only need to do this once on user install):
private void requestDocumentTreePermissions() {
// Choose a directory using the system's file picker.
new AlertDialog.Builder(this)
.setMessage("*Please Select A Folder For The App To Organize The Videos*")
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.Q)
#Override
public void onClick(DialogInterface dialog, int which) {
StorageManager sm = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
Intent intent = sm.getPrimaryStorageVolume().createOpenDocumentTreeIntent();
String startDir = "Documents";
Uri uri = intent.getParcelableExtra("android.provider.extra.INITIAL_URI");
String scheme = uri.toString();
scheme = scheme.replace("/root/", "/document/");
scheme += "%3A" + startDir;
uri = Uri.parse(scheme);
Uri rootUri = DocumentsContract.buildDocumentUri(
EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
uri.toString()
);
Uri treeUri = DocumentsContract.buildTreeDocumentUri(
EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
uri.toString()
);
uri = Uri.parse(scheme);
Uri treeUri2 = DocumentsContract.buildTreeDocumentUri(
EXTERNAL_STORAGE_PROVIDER_AUTHORITY,
uri.toString()
);
List<Uri> uriTreeList = new ArrayList<>();
uriTreeList.add(treeUri);
uriTreeList.add(treeUri2);
getPrimaryVolume().createOpenDocumentTreeIntent()
.putExtra(EXTRA_INITIAL_URI, rootUri);
Intent intent2 = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
// Optionally, specify a URI for the directory that should be opened in
// the system file picker when it loads.
intent2.addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
intent2.putExtra(EXTRA_INITIAL_URI, rootUri);
startActivityForResult(intent2, 99);
}
})
.setCancelable(false)
.show();
}
Next Store some Persistant Permissions:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 99 && resultCode == RESULT_OK) {
//get back the document tree URI (in this case we expect the documents root directory)
Uri uri = data.getData();
//now we grant permanent persistant permissions to our contentResolver and we are free to open up sub directory Uris as we please until the app is uninstalled
getSharedPreferences().edit().putString(ACCESS_FOLDER, uri.toString()).apply();
final int takeFlags = (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getApplicationContext().getContentResolver().takePersistableUriPermission(uri, takeFlags);
//simply recreate the activity although you could call some function at this point
recreate();
}
}
Finally call the documentFile's rename method on the correct file
DocumentFile df = DocumentFile.fromTreeUri(MainActivity.this, uri);
df = df.findFile("CurrentName")
df.renameTo("NewName");
You Can also open InputStreams and OutputStreams using your content resolver because of the persistant URI permissions granted to your content resolver for that DocumentFile using the following snippet:
getContentResolver().openInputStream(df.getUri());
getContentResolver().openOutputStream(df.getUri());
You can list files using
df.listFiles();
Or You can list out files using:
public static DocumentFile findFileInDirectoryMatchingName(Context mContext, Uri mUri, String name) {
final ContentResolver resolver = mContext.getContentResolver();
final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(mUri,
DocumentsContract.getDocumentId(mUri));
Cursor c = null;
try {
c = resolver.query(childrenUri, new String[]{
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
DocumentsContract.Document.COLUMN_DISPLAY_NAME,
DocumentsContract.Document.COLUMN_MIME_TYPE,
DocumentsContract.Document.COLUMN_LAST_MODIFIED
}, DocumentsContract.Document.COLUMN_DISPLAY_NAME + " LIKE '?%'", new String[]{name}, null);
c.moveToFirst();
while (!c.isAfterLast()) {
final String filename = c.getString(1);
final String mimeType = c.getString(2);
final Long lastModified = c.getLong(3);
if (filename.contains(name)) {
final String documentId = c.getString(0);
final Uri documentUri = DocumentsContract.buildDocumentUriUsingTree(mUri,
documentId);
return DocumentFile.fromTreeUri(mContext, documentUri);
}
c.moveToNext();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (c != null) {
c.close();
}
}
return null;
}
Which will run faster than the df.listFiles() method
As the title says, I am trying to upload images from both camera and gallery to firebase. But I have problems in both.
When I try to upload my image from the camera I get:
W/StorageUtil: no auth token for request
W/NetworkRequest: no auth token for request
Even though my firebase rules are:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}
}
}
But when I try using the gallery I get:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.compress(android.graphics.Bitmap$CompressFormat, int, java.io.OutputStream)' on a null object reference
at com.varroxsystems.plant.newPlant.Fileuploader(newPlant.java:192)
at com.varroxsystems.plant.newPlant.access$100(newPlant.java:57)
at com.varroxsystems.plant.newPlant$2.onClick(newPlant.java:162)
at android.view.View.performClick(View.java:7125)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
And I get no data in the firebase real time database nor in the firebase storage.
But I use this exact code on another application and it works just fine.
Does anyone know what am I doing wrong?
Code:
if (fragment3.isAdded()) {
EditText plantdetails = (EditText) fragment3.getView().findViewById(R.id.plantdetails);
if (plantdetails.getText().toString().equals("")) {
Toast.makeText(newPlant.this, "I think you forgot something.", Toast.LENGTH_LONG).show();
} else {
plants plants = new plants();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(newPlant.this);
prefs.edit().putString("pldetails", plantdetails.getText().toString()).apply();
String pname = prefs.getString("plname","null");
String pdate = prefs.getString("pldate","null");
String petails = prefs.getString("pldetails","null");
plants.setPlname(pname);
plants.setPldate(pdate);
plants.setPldetails(petails);
reference.child("Plants").child(pname).setValue(plants);
try {
Fileuploader();
}catch (FileNotFoundException e){
e.printStackTrace();
}
}
}
if (fragment4.isAdded()){
}
}
});
}
private void Fileuploader() throws FileNotFoundException {
String imageid;
progress.showProgress(newPlant.this,"Loading...",false);
DatabaseHelper databaseHelper = new DatabaseHelper(newPlant.this);
Cursor getimage = databaseHelper.GetPath();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(newPlant.this);
String plname = prefs.getString("plname","null");
int count = 0;
int count2 = 0;
if (getimage !=null){
while (getimage.moveToNext()) {
Bitmap bm = BitmapFactory.decodeFile(getimage.getString(0));
ByteArrayOutputStream out = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 35, out);
imageid = System.currentTimeMillis() + "_" + (count++) + "." + getExtension(uri);
DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Plants").child(plname).child("PlantImages");
String imagekey = reference.push().getKey();
reference.child(imagekey).child("ImageID").setValue(imageid);
reference.child(imagekey).child("ID").setValue(count2++);
System.out.println("IMAGES UPLOADEDDDD: " + imageid);
byte[] data = out.toByteArray();
StorageReference Ref = mStorageRef.child(imageid);
Ref.putBytes(data)
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
// Get a URL to the uploaded content
//Uri downloadUrl = taskSnapshot.getDownloadUrl();
//Toast.makeText(profuctadd.this,"Image uploaded",Toast.LENGTH_LONG).show();
progress.hideProgress();
Intent intent = new Intent(newPlant.this, Donenewplant.class);
startActivity(intent);
finish();
DatabaseHelper mDatabaseHelper = new DatabaseHelper(newPlant.this);
Cursor cursor2 = mDatabaseHelper.DeleteDataOfTableImagesAr();
cursor2.moveToNext();
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle unsuccessful uploads
// ...
Toast.makeText(newPlant.this, "Failed", Toast.LENGTH_LONG).show();
}
});
}
}
}
private String getExtension(Uri uri)
{
ContentResolver cr=getContentResolver();
MimeTypeMap mimeTypeMap=MimeTypeMap.getSingleton();
return mimeTypeMap.getExtensionFromMimeType(cr.getType(uri));
}
#RequiresApi(api = Build.VERSION_CODES.M)
private void askFileReadPermission() {
if (ContextCompat.checkSelfPermission(newPlant.this,
Manifest.permission.READ_EXTERNAL_STORAGE) + ContextCompat
.checkSelfPermission(newPlant.this,
Manifest.permission.CAMERA) + ContextCompat
.checkSelfPermission(newPlant.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale
(newPlant.this, Manifest.permission.READ_EXTERNAL_STORAGE) ||
ActivityCompat.shouldShowRequestPermissionRationale
(newPlant.this, Manifest.permission.CAMERA)||ActivityCompat.shouldShowRequestPermissionRationale
(newPlant.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Snackbar.make(newPlant.this.findViewById(android.R.id.content),
"Please Grant Permissions to upload plant photo",
Snackbar.LENGTH_INDEFINITE).setAction("ENABLE",
new View.OnClickListener() {
#Override
public void onClick(View v) {
requestPermissions(
new String[]{Manifest.permission
.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSIONS_MULTIPLE_REQUEST);
}
}).show();
} else {
requestPermissions(
new String[]{Manifest.permission
.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSIONS_MULTIPLE_REQUEST);
}
} else {
alert();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSIONS_MULTIPLE_REQUEST:
if (grantResults.length > 0) {
boolean cameraPermission = grantResults[1] == PackageManager.PERMISSION_GRANTED;
boolean readExternalFile = grantResults[0] == PackageManager.PERMISSION_GRANTED;
boolean writeExternalFile = grantResults[0] == PackageManager.PERMISSION_GRANTED;
if(cameraPermission && readExternalFile && writeExternalFile)
{
alert();
} else {
Snackbar.make(newPlant.this.findViewById(android.R.id.content),
"Please Grant Permissions to upload plant photo",
Snackbar.LENGTH_INDEFINITE).setAction("ENABLE",
new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onClick(View v) {
requestPermissions(
new String[]{Manifest.permission
.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSIONS_MULTIPLE_REQUEST);
}
}).show();
}
}
break;
}
}
private void alert() {
new androidx.appcompat.app.AlertDialog.Builder(newPlant.this)
.setTitle(null)
.setMessage("Where would you like to get your picture from?")
// Specifying a listener allows you to take an action before dismissing the dialog.
// The dialog is automatically dismissed when a dialog button is clicked.
.setPositiveButton("Open Camera", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dispatchTakePictureIntent();
}
})
// A null listener allows the button to dismiss the dialog and take no further action.
.setNegativeButton("Open Gallery", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent gallery = new Intent();
gallery.setType("image/*");
gallery.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
gallery.setAction(Intent.ACTION_PICK);
startActivityForResult(Intent.createChooser(gallery,"Select Picture"), GALLERY_REQUEST_CODE);
}
})
.setIcon(android.R.drawable.ic_menu_camera)
.show();
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
File f = new File(currentPhotoPath);
Log.d("tag", "ABsolute Url of Image is " + Uri.fromFile(f));
DatabaseHelper databaseHelper = new DatabaseHelper(newPlant.this);
databaseHelper.SavingimagepathAR(Uri.fromFile(f).getPath());
plantimage.setScaleType(ImageView.ScaleType.CENTER_CROP);
plantimage.setBackground(getResources().getDrawable(R.drawable.imageproadd));
plantimage.setClipToOutline(true);
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(f);
uri = Uri.fromFile(f);
mediaScanIntent.setData(uri);
this.sendBroadcast(mediaScanIntent);
System.out.println(databaseHelper.getProfilesCount());
//uri = Uri.parse(cursor22.getString(0));
plantimage.setImageURI(uri);
}
}
if (requestCode == GALLERY_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
if (data != null){
if (data.getClipData() != null) {
ClipData mClipData = data.getClipData();
for (int i = 0; i < mClipData.getItemCount(); i++) {
ClipData.Item item = mClipData.getItemAt(i);
Uri curi = item.getUri();
uri = item.getUri();
File imageFile = new File(getRealPathFromURI(newPlant.this, curi));
//mArrayUri.add();
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "." + getFileExt(curi);
DatabaseHelper databaseHelper = new DatabaseHelper(newPlant.this);
databaseHelper.SavingimagepathAR(Uri.fromFile(imageFile).getPath());
Log.d("tag", "onActivityResult: Gallery Image Uri: " + Uri.fromFile(imageFile));
// DatabaseHelper mDatabaseHelper = new DatabaseHelper(profuctadd.this);
// Cursor cursor22 = mDatabaseHelper.GetPath();
// while (cursor22.moveToNext()){
// System.out.println("SELECTED " + cursor22.getString(i));
// }
plantimage.setScaleType(ImageView.ScaleType.CENTER_CROP);
plantimage.setBackground(getResources().getDrawable(R.drawable.imageproadd));
plantimage.setClipToOutline(true);
//uri = Uri.parse(cursor22.getString(0));
plantimage.setImageURI(uri);
}
Log.v("LOG_TAG", "Selected Images ");
}else {
//Toast.makeText(profuctadd.this,"NO IMAGE EXCEPTION",Toast.LENGTH_LONG).show();
System.out.println(data.getData());
if (data.getData()!=null){
Uri contentUri = data.getData();
uri = data.getData();
System.out.println("CONTENT URI "+contentUri);
File imageFile = new File(getRealPathFromURI(newPlant.this, uri));
System.out.println("FILE "+imageFile);
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "." + getFileExt(uri);
DatabaseHelper databaseHelper = new DatabaseHelper(newPlant.this);
databaseHelper.SavingimagepathAR(Uri.fromFile(imageFile).getPath());
Log.d("tag", "onActivityResult: Gallery Image Uri: " + Uri.fromFile(imageFile));
//DatabaseHelper mDatabaseHelper = new DatabaseHelper(profuctadd.this);
//Cursor cursor22 = mDatabaseHelper.GetPath();
plantimage.setScaleType(ImageView.ScaleType.CENTER_CROP);
plantimage.setBackground(getResources().getDrawable(R.drawable.imageproadd));
plantimage.setClipToOutline(true);
//uri = Uri.parse(cursor22.getString(0));
plantimage.setImageURI(uri);
}
}
// }
}
}
}
}
private String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = {MediaStore.Images.Media.DATA};
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} catch (Exception e) {
Log.e(TAG, "getRealPathFromURI Exception : " + e.toString());
return "";
} finally {
if (cursor != null) {
cursor.close();
}
}
}
private String getFileExt(Uri contentUri) {
ContentResolver c = getContentResolver();
MimeTypeMap mime = MimeTypeMap.getSingleton();
return mime.getExtensionFromMimeType(c.getType(contentUri));
}
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
// File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
currentPhotoPath = image.getAbsolutePath();
return image;
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
ex.printStackTrace();
Toast.makeText(newPlant.this,ex.getMessage(),Toast.LENGTH_LONG).show();
return;
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
"com.varroxsystems.plant.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, CAMERA_REQUEST_CODE);
}
}
}
I created my OwnCloud server with Oracle VirtualBox Debian. I want my Android application to upload image to the cloud. So i created intent to get image from the Gallery and to upload it with the OwnCloud Android library from GitHub: https://github.com/owncloud/android-library
. I followed the steps from the sample but every time when i start uploading, the result is 404 - FILE_NOT_FOUND
Here is a snippet of my code:
floatingActionButton.setOnClickListener(v -> {
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType(IMAGE_INTENT);
startActivityForResult(photoPickerIntent, RESULT_LOAD_IMG);
});
}
#Override
protected void onActivityResult(int reqCode, int resultCode, Intent data) {
super.onActivityResult(reqCode, resultCode, data);
if (resultCode == RESULT_OK) {
try {
final Uri imageUri = data.getData();
final InputStream imageStream = getContentResolver().openInputStream(imageUri);
final Bitmap selectedImage = BitmapFactory.decodeStream(imageStream);
profilePicture.setImageBitmap(selectedImage);
File file = new File(getRealPathFromURI(imageUri));
Log.d("Image file", file.getAbsolutePath() + "\t" + file.getName());
handler = new Handler();
Uri serverUri = Uri.parse("http://192.168.1.8/remote.php/webdav/");
client = OwnCloudClientFactory.createOwnCloudClient(serverUri, this, true);
client.setCredentials(OwnCloudCredentialsFactory.newBasicCredentials("user", "bitnami"));
client.getParams().setAuthenticationPreemptive(true);
String remotePath = FileUtils.PATH_SEPARATOR + file.getName();
String mimeType = "image/png";
// Get the last modification date of the file from the file system
Long timeStampLong = file.lastModified() / 1000;
String timeStamp = timeStampLong.toString();
UploadRemoteFileOperation uploadOperation = new UploadRemoteFileOperation(file.getAbsolutePath(), remotePath, mimeType, timeStamp);
uploadOperation.addDatatransferProgressListener(this);
uploadOperation.execute(client, this, handler);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
private String getRealPathFromURI(Uri contentURI) {
String result;
Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
if (cursor == null) {
result = contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
result = cursor.getString(idx);
cursor.close();
}
return result;
}
#Override
public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileAbsoluteName) {
final long percentage = (totalToTransfer > 0 ? totalTransferredSoFar * 100 / totalToTransfer : 0);
handler.post(() -> Log.d("Progress", "progressRate " + percentage));
}
#Override
public void onRemoteOperationFinish(RemoteOperation caller, RemoteOperationResult result) {
Toast.makeText(this, String.valueOf(result.getHttpCode()), Toast.LENGTH_SHORT).show();
}
So after trying many answers for the same question, here are just two e.g;
Saving an image in android
and
Saving an image to a server using a Java applet
My app still fails in fact whatever I have done has made it worse, before it would actually save the image as "temp.jpg" in the ExtSD root folder, now when I click the tick to accept the photo nothing happens, no crashing, no nothing, I can retake the image and I can cancel the taking of a photo but nothing else happens.
What it does now:
Opens the camera (or gallery)
Takes the photo
Fails to save/set the photo
What I want it to do;
Take the photo
Store it with a unique name (timestamp)
Have the image set to CircleView
Here is my code (if you need more please ask for what you need);
CircleImageView circleImageView;
ImageButton b;
private void selectImage() {
final CharSequence[] options = { "Take a Pic", "Choose from Gallery", "Cancel" };
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("Set Profile Pic");
builder.setItems(options, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int item) {
if (options[item].equals("Take a Pic"))
{
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String folder_main = "iDealer";
String sub_folder = "ProPics";
String timeStamp = new SimpleDateFormat("ddMMyyy_HHmmss").format(Calendar.getInstance().getTime());
String pro_pic_name = folder_main + "_" + timeStamp;
File f = new File(android.os.Environment.getExternalStorageDirectory() + "/" + folder_main + "/" + sub_folder + pro_pic_name);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
startActivityForResult(intent, 1);
}
else if (options[item].equals("Choose from Gallery"))
{
Intent intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 2);
}
else if (options[item].equals("Cancel")) {
dialog.dismiss();
}
}
});
builder.show();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == 1) {
File f = new File(Environment.getExternalStorageDirectory().toString());
for (File temp : f.listFiles()) {
if (temp.getName().equals("temp.jpg")) {
f = temp;
break;
}
}
try {
Bitmap bitmap;
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmap = BitmapFactory.decodeFile(f.getAbsolutePath(),
bitmapOptions);
circleImageView.setImageBitmap(bitmap);
String path = android.os.Environment
.getExternalStorageDirectory()
+ File.separator
+ "iDealer" + File.separator + "default";
f.delete();
OutputStream outFile = null;
File file = new File(path, String.valueOf(System.currentTimeMillis()) + ".jpg");
try {
outFile = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 85, outFile);
outFile.flush();
outFile.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
} else if (requestCode == 2) {
Uri selectedImage = data.getData();
String[] filePath = { MediaStore.Images.Media.DATA };
Cursor c = getContentResolver().query(selectedImage,filePath, null, null, null);
if (c != null) {
c.moveToFirst();
}
int columnIndex = c.getColumnIndex(filePath[0]);
String picturePath = c.getString(columnIndex);
c.close();
Bitmap thumbnail = (BitmapFactory.decodeFile(picturePath));
Log.w("path from gallery = ", picturePath+"");
circleImageView.setImageBitmap(thumbnail);
}
}
}