I'm trying to get a image from android Photos app using the share option that point to my PhotoGetFromGallery activity. Here is the code:
public void copy(File src, File dst) throws IOException {
FileInputStream inStream = new FileInputStream(src);
FileOutputStream outStream = new FileOutputStream(dst);
FileChannel inChannel = inStream.getChannel();
FileChannel outChannel = outStream.getChannel();
inChannel.transferTo(0, inChannel.size(), outChannel);
inStream.close();
outStream.close();
}
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
void handleSendImage(Intent intent) {
Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
String sourcePath = getRealPathFromURI(imageUri);
if(isExternalStorageWritable()) {
if (imageUri != null) {
File sd = Environment.getExternalStorageDirectory();
File data = Environment.getDataDirectory();
String destinationImagePath = sd + "/Pictures/MyAppImgFolder/";
File source = new File(data, sourcePath);
String fileName = source.getName();
File destination = new File(sd, destinationImagePath + fileName);
try {
copy(source, destination);
} catch (Exception e) {
Log.e("COPY IMAGE ERROR", e.toString() + ". Destination Path is " + destinationImagePath.toString() + " and Source path is "+ sourcePath);
}
}
}
}
sourcePath string returns the correct image path (ex. /storage/emulated/0/Pictures/Instagram/IMG_20150413_114608.jpg). However, I'm getting the FileNotFoundException because Environment.getDataDirectory() returns /data/storage/emulated/0/Pictures/Instagram/IMG_20150413_114608.jpg.
Here is my log:
E/COPY IMAGE ERROR﹕ java.io.FileNotFoundException: /data/storage/emulated/0/Pictures/Instagram/IMG_20150413_114608.jpg: open failed: ENOENT (No such file or directory). Destination Path is /storage/emulated/0/Pictures/MyAppImgFolder/ and Source path is /storage/emulated/0/Pictures/Instagram/IMG_20150413_114608.jpg
Here is my AndroidManifest.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
My question is how can I get, if possible, any path of images stored at Photos app or Android Gallery?
You should not be using getDataDirectory - you are already being handed a complete path, starting with "/storage" Use the single argument File() constructor passing only the sourcePath, like this:
File sd = Environment.getExternalStorageDirectory();
String destinationImagePath = sd + "/Pictures/MyAppImgFolder/";
//sourcePath is already a full path name
File source = new File(sourcePath);
//redundant String fileName = source.getName();
File destination = new File(destinationImagePath + sourcePath);
//You are proposing many new subdirectories, so you must create them
destination.getParentFile()makeDirs();
//now you can continue with your copy attempt
I managed to solve the problem. Follows the code that works . Thanks to Chris Stratton for guiding me in this matter.
File sd = Environment.getExternalStorageDirectory();
String destinationImagePath = sd + AppConstant.PHOTO_ALBUM;
File imagePath = new File(destinationImagePath);
File source = new File(sourcePath);
String fileName = source.getName();
File destination = new File(destinationImagePath + fileName);
if (!imagePath.exists()) {
imagePath.mkdirs();
try {
copy(source, destination);
Toast.makeText(getApplicationContext(), "Success! File was copy from " + sourcePath + " to " + destinationImagePath, Toast.LENGTH_LONG).show();
} catch (Exception e) {
Log.e("COPY IMAGE ERROR", e.toString());
}
} else if(destination.exists() && !destination.isDirectory()){
Toast.makeText(getApplicationContext(), "Image is already on your image folder", Toast.LENGTH_LONG).show();
}
Related
I have an Intent of ACTION_GET_CONTENT in my app and I need to put the picked file ( there will be different files, ppt, doc...) in a java.io File.
I'm able to get the data and put it into a android.net Uri. Is there a way I ca create a java File from this Uri?
I need it to be a file in order to upload it do google drive using the google drive API
This is the code to upload to the drive, I need to convert the uri to a temporary file in order to pass it as the javaFile of this method
public Task<File> uploadFileWithMetadata(java.io.File javaFile, boolean isSlide, #Nullable final String folderId, PostFileHolder postFileHolder) {
return Tasks.call(mExecutor, () -> {
Log.i("upload file", "chegou" );
String convertTo; // string to convert to gworkspace
if(isSlide){
convertTo = TYPE_GOOGLE_SLIDES;
}
else{
convertTo = TYPE_GOOGLE_DOCS;
}
List<String> folder;
if (folderId == null) {
folder = Collections.singletonList("root");
} else {
folder = Collections.singletonList(folderId);
}
File metadata = new File()
.setParents(Collections.singletonList(folderId))
.setName(postFileHolder.getDisplayName())
.setMimeType(convertTo);
Log.i("convert to: ", convertTo );
// the convert to is the mimeType of the file, withg gworkspace it is a gdoc or gslide, with others is the regular mimetype
FileContent mediaContent = new FileContent(postFileHolder.getConvertTo(), javaFile);
Log.i("media content", "chegou" );
// até aqui com gworkspace chega
File uploadedFile = mDriveService.files().create(metadata, mediaContent)
.setFields("id")
.execute();
Log.i("File ID: " , uploadedFile.getId());
return uploadedFile;
});
}
This is my code to get the Uri
case REQUEST_CODE_FILE_PICKER:
// get uri from file picked
Uri url = data.getData();
break;
}
Solved it!
Here's how I did it:
// my uri
Uri fileUri = Uri.parse(postFileHolder.getFileUri());
// create a null InputSream
InputStream iStream = null;
try {
// create a temporary file
File fileToUpload = File.createTempFile("fileToUpload", null, this.getCacheDir());
iStream = getContentResolver().openInputStream(fileUri);
// use function to get the bytes from the created InputStream
byte[] byteData = getBytes(iStream);
convert byteArray to File
FileOutputStream fos = new FileOutputStream(fileToUpload);
fos.write(byteData);
fos.flush();
fos.close();
if(fileToUpload == null){
Log.i("create file", "null");
}
else{
Log.i("create file", "not null: "+ fileToUpload.getTotalSpace());
getEGDrive(fileToUpload);
}
}
catch (FileNotFoundException e) {
Log.i("error create file uri", e.getLocalizedMessage());
e.printStackTrace();
} catch (IOException e) {
Log.i("error create file uri", e.getLocalizedMessage());
e.printStackTrace();
}
And here's the function to transform the InputStream into byteArray:
public byte[] getBytes(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
byteBuffer.write(buffer, 0, len);
}
return byteBuffer.toByteArray();
}
Got big part of the answer from: https://stackoverflow.com/a/10297073/14990708
I'm trying to write a text file and save it in the android external storage, but file is not showing and I don't get any errors.
Here is my code:
String r;
String fname= "readme.txt";
r = Environment.getExternalStorageDirectory().toString();
File myDir = new File(r);
if (!myDir.exists()) {
myDir.mkdirs();
}
File file = new File (myDir, fname);
if (file.exists ())
file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
Out.write(wfile)
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
Try something below. You can add validations to check whether file exists or not, as you please.
File file = new
File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "readme.txt");
FileOutputStream out = new FileOutputStream(file);
out.write(wfile);
out.flush();
out.close();
MediaScannerConnection.scanFile(mContext, new String[] { file.toString() }, null,new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
Just FYI, Environment.DIRECTORY_DOCUMENTS may does not exists in older android versions. Then you may have to add a validation to check that and create a directory if not.
i'm trying to create a new file with this code but i have the "java.io.IOException: open failed: ENOENT (No such file or directory)"
This is my code: i hope you can help me.
final File f = new File(Environment.
getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS).getPath() + "/"
+ MainActivity.getContext().getPackageName()
+ "/wifip2pshared-" + System.currentTimeMillis()
+ ".jpg");
Log.d("WIFI","file created :"+f.getAbsolutePath());
File dirs = new File(f.getParent());
Log.d("WIFI","dir created :"+dirs.getAbsolutePath());
dirs.mkdirs();
f.createNewFile();
And I did declare the permission in the android manifest.
Add this in your manifest application
android:requestLegacyExternalStorage="true"
Handle run time permissions if you user Android M or next version
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "wifip2pshared/" + dirName);
boolean success = true;
if (!folder.exists()) {
success = folder.mkdirs();
}
if (success) {
// Do something on success
} else {
// Do something else on failure
}
OR
File dir = new File("storage/emulated/0/wifip2pshared/" + dirName);
try {
if (!dir.exists()) {
if (dir.mkdir()) {
System.out.println("Directory created");
} else {
System.out.println("Directory is not created");
}
}
} catch (Exception e) {
e.printStackTrace();
}
I am trying to use this code to send my application apk file to another device:
public static void sendAppItself(Activity paramActivity) throws IOException {
PackageManager pm = paramActivity.getPackageManager();
ApplicationInfo appInfo;
try {
appInfo = pm.getApplicationInfo(paramActivity.getPackageName(),
PackageManager.GET_META_DATA);
Intent sendBt = new Intent(Intent.ACTION_SEND);
sendBt.setType("*/*");
sendBt.putExtra(Intent.EXTRA_STREAM,
Uri.parse("file://" + appInfo.publicSourceDir));
paramActivity.startActivity(Intent.createChooser(sendBt,
"Share it using"));
} catch (PackageManager.NameNotFoundException e1) {
e1.printStackTrace();
}
}
This code works very well.
But the name of the apk file shared with this code is base.apk
How can I change it?
Copy the file from the source directory to a new directory.
Rename the file while copying and share the copied file.
Delete the temp file after share is complete.
private void shareApplication() {
ApplicationInfo app = getApplicationContext().getApplicationInfo();
String filePath = app.sourceDir;
Intent intent = new Intent(Intent.ACTION_SEND);
// MIME of .apk is "application/vnd.android.package-archive".
// but Bluetooth does not accept this. Let's use "*/*" instead.
intent.setType("*/*");
// Append file and send Intent
File originalApk = new File(filePath);
try {
//Make new directory in new location
File tempFile = new File(getExternalCacheDir() + "/ExtractedApk");
//If directory doesn't exists create new
if (!tempFile.isDirectory())
if (!tempFile.mkdirs())
return;
//Get application's name and convert to lowercase
tempFile = new File(tempFile.getPath() + "/" + getString(app.labelRes).replace(" ","").toLowerCase() + ".apk");
//If file doesn't exists create new
if (!tempFile.exists()) {
if (!tempFile.createNewFile()) {
return;
}
}
//Copy file to new location
InputStream in = new FileInputStream(originalApk);
OutputStream out = new FileOutputStream(tempFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
System.out.println("File copied.");
//Open share dialog
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
startActivity(Intent.createChooser(intent, "Share app via"));
} catch (IOException e) {
e.printStackTrace();
}
}
Update: this method does not work anymore and throws exception if you implement it. Since android N, we should use content providers if we want to have access to files in memory(like the apk file). For more information please visit this Guide. Although the whole idea of copying and renaming and sharing the copied version is still valid.
You can use this function, test on api 22 and 27
private void shareApplication() {
ApplicationInfo app = getApplicationContext().getApplicationInfo();
String filePath = app.sourceDir;
Intent intent = new Intent(Intent.ACTION_SEND);
// MIME of .apk is "application/vnd.android.package-archive".
// but Bluetooth does not accept this. Let's use "*/*" instead.
intent.setType("*/*");
// Append file and send Intent
File originalApk = new File(filePath);
try {
//Make new directory in new location=
File tempFile = new File(getExternalCacheDir() + "/ExtractedApk");
//If directory doesn't exists create new
if (!tempFile.isDirectory())
if (!tempFile.mkdirs())
return;
//Get application's name and convert to lowercase
tempFile = new File(tempFile.getPath() + "/" + getString(app.labelRes).replace(" ","").toLowerCase() + ".apk");
//If file doesn't exists create new
if (!tempFile.exists()) {
if (!tempFile.createNewFile()) {
return;
}
}
//Copy file to new location
InputStream in = new FileInputStream(originalApk);
OutputStream out = new FileOutputStream(tempFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
System.out.println("File copied.");
//Open share dialog
// intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
Uri photoURI = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", tempFile);
// intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
intent.putExtra(Intent.EXTRA_STREAM, photoURI);
startActivity(Intent.createChooser(intent, "Share app via"));
} catch (IOException e) {
e.printStackTrace();
}
}
This only happens because it is saved by base.apk name.
To share it as per your need you have to just copy this file into another directory path and rename it over there. Then use new file to share.
This file path[file:///data/app/com.yourapppackagename/base.apk] in data folder is having only read permissions so you can't rename .apk file over there.
2021 Kotlin way
First we need to set a file provider
In AndroidManifest.xml create a File provider
<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"
/>
</provider>
If you don't have file_path.xml the create one in res/xml (create xml folder if it doesn't exist)
and in file_path.xml add
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-files-path
name="apk"
path="cache/ExtractedApk/" />
</paths>
Now add the code to share the apk
private fun shareAppAsAPK(context: Context) {
val app: ApplicationInfo = context.applicationInfo
val originalApk = app.publicSourceDir
try {
//Make new directory in new location
var tempFile: File = File(App.instance.getExternalCacheDir().toString() + "/ExtractedApk")
//If directory doesn't exists create new
if (!tempFile.isDirectory) if (!tempFile.mkdirs()) return
//rename apk file to app name
tempFile = File(tempFile.path + "/" + getString(app.labelRes).replace(" ", "") + ".apk")
//If file doesn't exists create new
if (!tempFile.exists()) {
if (!tempFile.createNewFile()) {
return
}
}
//Copy file to new location
val inp: InputStream = FileInputStream(originalApk)
val out: OutputStream = FileOutputStream(tempFile)
val buf = ByteArray(1024)
var len: Int
while (inp.read(buf).also { len = it } > 0) {
out.write(buf, 0, len)
}
inp.close()
out.close()
//Open share dialog
val intent = Intent(Intent.ACTION_SEND)
//MIME type for apk, might not work in bluetooth sahre as it doesn't support apk MIME type
intent.type = "application/vnd.android.package-archive"
intent.putExtra(
Intent.EXTRA_STREAM, FileProvider.getUriForFile(
context, BuildConfig.APPLICATION_ID + ".fileprovider", File(tempFile.path)
)
)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
startActivity(intent)
} catch (e: IOException) {
e.printStackTrace()
}
}
If someone trying to generate apk from fragment they may need to change few lines from #sajad's answer as below
Replace
File tempFile = new File(getExternalCacheDir() + "/ExtractedApk");
with
File tempFile = new File(getActivity().getExternalCacheDir() + "/ExtractedApk");
2.while importing BuildConfig for below line
import androidx.multidex.BuildConfig // DO NOT DO THIS!!! , use your app BuildConfig.
and if you're getting below EXCEPTION
Couldn't find meta-data for provider with authority
Look for provider info in manifest file
then look for "provider"s name and authority in your manifest file and if it's androidx.core.content.FileProvider then
Replace
Uri photoURI = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", tempFile);
With
Uri photoURI = FileProvider.getUriForFile(getActivity(), BuildConfig.APPLICATION_ID + ".fileprovider", tempFile);
I'm trying to make an app that uploads a file to dropbox and downloads it.
Uploading seems to work, downloading doesn't. Also it doesn't actually upload from my SD card but from my phone internal memory.
saveOnDropbox() uploads a file.txt from phone/MyFiles/file.txt to dropbox app folder.
saveOnDevice() - something happens when I use this, but the file doesn't get neither to my phone or SD card
public void saveOnDropBox() throws IOException, DropboxException {
File sdCard = Environment.getExternalStorageDirectory();
File file = new File(sdCard.getAbsolutePath() + "/MyFiles/file.txt");
FileInputStream inputStream = new FileInputStream(file);
DropboxAPI.Entry response = dropboxAPI.putFile("/file.txt", inputStream,
file.length(), null, null);
Log.i("D bExam pleLog", "The uploaded file's rev is: " + response.rev);
}
public void saveOnDevice() {
FileOutputStream outputStream = null;
try {
File sdCard = Environment.getExternalStorageDirectory();
File file = new File(sdCard.getAbsolutePath() + "/MyFiles/file.txt");
outputStream = new FileOutputStream(file);
DropboxAPI.DropboxFileInfo info = dropboxAPI.getFile("/file.txt", null, outputStream, null);
} catch (Exception e) {
System.out.println("Som ething w ent w rong: " + e);
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
System.out.println("___" + e);
}
}
}
}}
Appreciate any help.