How to save video to gallery and retrieve the saved video uri? - java

I am trying to make a save to gallery feature for my app. My app's minimum api level is 21 and max 30.
Here is the code I am using for saving video to gallery. Everything works perfect but the code only works for API 29 and Above. Here is the code:
String videoFileName = "video_" + System.currentTimeMillis() + ".mp4";
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ContentValues valuesvideos;
valuesvideos = new ContentValues();
valuesvideos.put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/" + "Folder");
valuesvideos.put(MediaStore.Video.Media.TITLE, videoFileName);
valuesvideos.put(MediaStore.Video.Media.DISPLAY_NAME, videoFileName);
valuesvideos.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
valuesvideos.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
valuesvideos.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
valuesvideos.put(MediaStore.Video.Media.IS_PENDING, 1);
ContentResolver resolver = context.getContentResolver();
Uri collection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
Uri uriSavedVideo = resolver.insert(collection, valuesvideos);
ParcelFileDescriptor parcelFileDescriptor;
try {
assert uriSavedVideo != null;
parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uriSavedVideo, "w");
assert parcelFileDescriptor != null;
FileOutputStream out = new FileOutputStream(parcelFileDescriptor.getFileDescriptor());
FileInputStream in = new FileInputStream(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES) + File.separator + "Application" + File.separator + "video.mp4");
byte[] buf = new byte[8192];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.close();
in.close();
parcelFileDescriptor.close();
} catch (Exception e) {
e.printStackTrace();
}
valuesvideos.clear();
valuesvideos.put(MediaStore.Video.Media.IS_PENDING, 0);
context.getContentResolver().update(uriSavedVideo, valuesvideos, null, null);
}
This is the code I use for Versions below API 29:
ContentValues valuesvideos;
valuesvideos = new ContentValues();
valuesvideos.put(MediaStore.Video.Media.DATA, context.getExternalFilesDir(Environment.DIRECTORY_MOVIES) + File.separator + "Folder");
valuesvideos.put(MediaStore.Video.Media.TITLE, videoFileName);
valuesvideos.put(MediaStore.Video.Media.DISPLAY_NAME, videoFileName);
valuesvideos.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
valuesvideos.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
ContentResolver resolver = context.getContentResolver();
Uri collection = MediaStore.Video.Media.INTERNAL_CONTENT_URI;
Uri uriSavedVideo = resolver.insert(collection, valuesvideos);
ParcelFileDescriptor parcelFileDescriptor;
try {
assert uriSavedVideo != null;
parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uriSavedVideo, "w");
assert parcelFileDescriptor != null;
FileOutputStream out = new FileOutputStream(parcelFileDescriptor.getFileDescriptor());
FileInputStream in = new FileInputStream(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES) + File.separator + "Application" + File.separator + "video.mp4");
byte[] buf = new byte[8192];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.close();
in.close();
parcelFileDescriptor.close();
} catch (Exception e) {
e.printStackTrace();
}
valuesvideos.clear();
context.getContentResolver().update(uriSavedVideo, valuesvideos, null, null);
How to write this exact function for lower APIs? Now I have tried MediaScanner but it seems too slow and I can't get the uri of the saved file. Hope you will answer. Regards.

Related

Handle Uri without creating a new file

The library I'm using requires me to pass it a file path.
Currently, I use the Uri to create a new file (in an AsyncTask) as shown below:
#Override
protected String doInBackground(Uri... params) {
File file = null;
int size = -1;
try {
try {
if (returnCursor != null && returnCursor.moveToFirst()){
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
size = (int) returnCursor.getLong(sizeIndex);
}
}
finally {
if (returnCursor != null)
returnCursor.close();
}
if (extension == null){
pathPlusName = folder + "/" + filename;
file = new File(folder + "/" + filename);
}else {
pathPlusName = folder + "/" + filename + "." + extension;
file = new File(folder + "/" + filename + "." + extension);
}
BufferedInputStream bis = new BufferedInputStream(is);
FileOutputStream fos = new FileOutputStream(file);
byte[] data = new byte[1024];
long total = 0;
int count;
while ((count = bis.read(data)) != -1) {
if (!isCancelled()) {
total += count;
if (size != -1) {
publishProgress((int) ((total * 100) / size));
}
fos.write(data, 0, count);
}
}
fos.flush();
fos.close();
} catch (IOException e) {
errorReason = e.getMessage();
}
return file.getAbsolutePath();
}
As you can imagine, this might take some time depending on the file size.
Question
Is there any way to access the file without having to create/copy it?
*I have read that I can use ContentResolver and methods like openInputStream() and openOutputStream(). But this will only provide me with a stream and does not solve the issue I have of having to write a new file?
Extra info:
I get the Uri by passing the following to an Intent:
intent.setType("video/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
Then in onActivityResult I get the Uri by calling data.getData().
Please do not provide me with solutions like this one. I do not want to get a file Uri from a content Uri because it's unreliable and incorrect.
It looks pretty clear that a library that cannot handle a content scheme is of no use if you only have a content scheme.
You have to make a copy of the content in a file. As you do now.

Weird issue with zip/gzip files

Below is a program which saves the bytes to a .png file and zips into a given name folder.
byte[] decodedBytes = Base64.decodeBase64(contents);
// System.out.println(new String(decodedBytes));
InputStream targetStream = new ByteArrayInputStream(decodedBytes);
int count;
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFilePath));
out.putNextEntry(new ZipEntry(pngFile));
byte[] b = new byte[1024];
while ((count = targetStream.read(b)) > 0) {
out.write(b, 0, count);
}
out.flush();
out.close();
targetStream.close();
When i open it manually using 7 zip I see the following folder structure (c:\output\nameofzipfile.zip\nameofpng.png\nameofpng). Why is this happening? What am I doing wrong? As per my understanding this should be the structure (c:\output\nameofzipfile.zip\nameofpng.png)
Worked with the following code
byte[] decoded = Base64.decodeBase64(contents);
try (FileOutputStream fos = new FileOutputStream(zipFilePath + amazonOrderId + zipFileName)) {
fos.write(decoded);
fos.close();
}
file = new File(destDirectory + amazonOrderId + pngFile);
if (file.exists()) {
file.delete();
}
try (OutputStream out = new FileOutputStream(destDirectory + amazonOrderId + pngFile)) {
try (InputStream in = new GZIPInputStream(
new FileInputStream(zipFilePath + amazonOrderId + zipFileName))) {
byte[] buffer = new byte[65536];
int noRead;
while ((noRead = in.read(buffer)) != -1) {
out.write(buffer, 0, noRead);
}
}
}

Images compressing with wrong colors

I using java code for compressing images. Sometimes i am getting image with wrong colors. I don't understand why it's beheviour is inconsistent.
Images downloading from urls
public void imageDownload() {
String key = (String) map.get("key");
String url = (String) map.get("url");
**String imagePath = java.util.UUID.randomUUID() + ".jpg";
String compressedImage = Constant.COMPRESSED + imagePath;**
try {
URL url = new URL(url);
InputStream is = url.openStream();
// Stream to the destionation file
FileOutputStream fos = new FileOutputStream(imagePath);
// Read bytes from URL to the local file
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = is.read(buffer)) != -1)
fos.write(buffer, 0, bytesRead);
// Close destination stream
fos.close();
// Close URL stream
is.close();
compressFile(imagePath, compressedImage, key);
} catch (Exception exception) {
log.debug("Exception occured while downloading images..." + exception.getLocalizedMessage());
}
}
}
Image compression code
private void compressFile(final String inputFilePath, final String outputFilePath,final String fileKey) {
log.debug("Image file name::" + outputFilePath);
log.debug("Image key is::" + fileKey);
final String outputImagePath = tempFilePath + outputFilePath;
final File inputFile = new File(inputFilePath);
float quality = FileUpload.getQuality(inputFile);
log.debug("Image size for url is::" + inputFile.length() + "quality constent::" + quality);
final File outputFile = new File(outputImagePath);
boolean s3Uploaded = true;
if (quality != 0.0f) {
final boolean isCompressed = FileUpload.fileCompress(inputFile, outputFile, quality);
}
}
Compression code
public static boolean fileCompress(File inputFilePath, File outputFilePath, float quality) {
log.debug("File compress with path::" + inputFilePath + "output file path" + outputFilePath);
boolean isCompressed = false;
OutputStream os = null;
ImageOutputStream ios = null;
ImageWriter writer = null;
try {
BufferedImage image = ImageIO.read(inputFilePath);
os = new FileOutputStream(outputFilePath);
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
writer = (ImageWriter) writers.next();
ios = ImageIO.createImageOutputStream(os);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
writer.write(null, new IIOImage(image, null, null), param);
os.close();
ios.close();
writer.dispose();
isCompressed = true;
} catch (Exception exception) {
log.error("File could not compress due to " + exception.getCause());
isCompressed= false;
}
return isCompressed;
}
getting quality parameter
public static float getQuality(File input) {
long size = input.length();
log.debug("getting quality constant on the basis of image size: " + size);
if (size > 768000) {
return 0.3f;
}
if (size > 512000 && size <= 768000) {
return 0.6f;
}
if (size > 256000 && size <= 512000) {
return 0.7f;
}
if (size > 51200) {
return 0.9f;
}
return 0.0f;
}
Destroyed image(image size was before compressing - 84616)
Thanks

Upload Image to FTP Server using ADF Mobile Application

I want to upload an image to FTP Server. Currently i am using JDeveloper 12c(12.1.3.0).
My Code:
private static final int BUFFER_SIZE = 4096;
public String fileUploadMethod(String imagePath){
String ftpUrl = "ftp://";
String host = "http://192.168.0.42";
String user = "XXXXXX";
String pass = "XXXXXX";
String filePath = "783771-1.jpg";
String uploadPath = imagePath;
ftpUrl =ftpUrl + user +":"+ pass+"#"+host+"/"+filePath+";";
System.out.println("Upload URL: " + ftpUrl);
try {
URL url = new URL(ftpUrl);
URLConnection conn = url.openConnection();
OutputStream outputStream = conn.getOutputStream();
FileInputStream inputStream = new FileInputStream(uploadPath);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outputStream.close();
System.out.println("File uploaded");
return "File uploaded";
} catch (IOException ex) {
ex.printStackTrace();
}
return null;
}
I am getting an error MalFormedURLException i.e. in detail message "unknown protocol:ftp"
Is there any other option to upload an image using JDeveloper.
Any idea regarding this.
Thanks, Siddharth
Your ftpUrl is wrong. Remove http:// in the host variable. Should be ok then
I haven't really tried ftp upload. But I had tried with multipart form upload. As far as I know, MAF doesnt provide Out-Of-Box support for file upload. What I did was essential recreating the HTTP stream for the image upload.
The POC code is attached below. This may be definitely the CRUDEST implementation but I am not sure if there is a better way.
public void doUpload() {
try {
DeviceManager dm = DeviceManagerFactory.getDeviceManager();
String imgData =
dm.getPicture(50, DeviceManager.CAMERA_DESTINATIONTYPE_FILE_URI, DeviceManager.CAMERA_SOURCETYPE_CAMERA,
false, DeviceManager.CAMERA_ENCODINGTYPE_PNG, 0, 0);
imgData = imgData.substring(7, imgData.length());
int start = imgData.lastIndexOf('/');
String fileName = imgData.substring(start+1, imgData.length());
RestServiceAdapter restServiceAdapter = Model.createRestServiceAdapter();
restServiceAdapter.clearRequestProperties();
String requestMethod = RestServiceAdapter.REQUEST_TYPE_POST;
String requestEndPoint = restServiceAdapter.getConnectionEndPoint("serverBaseUrl");
String requestURI = "/workers/100000018080264";
String request = requestEndPoint + requestURI;
HashMap httpHeadersValue = new HashMap();
httpHeadersValue.put("X-ANTICSRF", "TRUE");
httpHeadersValue.put("Connection", "Keep-Alive");
httpHeadersValue.put("content-type","multipart/form-data; boundary=----------------------------4abf1aa47e18");
// Get the connection
HttpConnection connection = restServiceAdapter.getHttpConnection(requestMethod, request, httpHeadersValue);
OutputStream os = connection.openOutputStream();
byte byteBuffer[] = new byte[50];
int len;
//String temp is appended before the image body
String temp = "------------------------------4abf1aa47e18\r\nContent-Disposition: form-data; name=\"file\"; filename=\"" +fileName+ "\"\r\nContent-Type: image/jpeg\r\n\r\n";
InputStream stream = new ByteArrayInputStream(temp.getBytes("UTF-8"));
if (stream != null) {
while ((len = stream.read(byteBuffer)) >= 0) {
os.write(byteBuffer, 0, len);
}
stream.close();
}
FileInputStream in = new FileInputStream(imgData);
if (in != null) {
while ((len = in.read(byteBuffer)) >= 0) {
os.write(byteBuffer, 0, len);
}
in.close();
}
//The below String is appended after the image body
InputStream stream2 =new ByteArrayInputStream("\r\n------------------------------4abf1aa47e18--\r\n".getBytes("UTF-8"));
if (stream2 != null) {
while ((len = stream2.read(byteBuffer)) >= 0) {
os.write(byteBuffer, 0, len);
}
stream2.close();
}
int status = connection.getResponseCode();
InputStream inputStream = restServiceAdapter.getInputStream(connection);
ByteArrayOutputStream incomingBytes = new ByteArrayOutputStream() // get and process the response.
while ((len = inputStream.read(byteBuffer)) >= 0) {
incomingBytes.write(byteBuffer, 0, len);
}
String ret = incomingBytes.toString();
incomingBytes.close();
} catch (Exception e) {
e.printStackTrace();
}
}

Reading JPEG Stream over socket gives Null characters

I am reading a .jpg file over InputStream using this code but I am receiving NULNUL...n stream after some text. Ii am reading this file link to file and link of file that I received , link is Written File link.
while ((ret = input.read(imageCharArray)) != -1) {
packet.append(new String(imageCharArray, 0, ret));
totRead += ret;
imageCharArray = new char[4096];
}
file = new File(
Environment.getExternalStorageDirectory()
+ "/FileName_/"
+ m_httpParser.filename + ".jpg");
PrintWriter printWriter = new PrintWriter(file);
// outputStream = new FileOutputStream(file); //also Used FileoutputStream for writting
// outputStream.write(packet.toString().getBytes());//
// ,
printWriter.write(packet.toString());
// outputStream.close();
printWriter.close();
}
I have also tried FileoutputStream but hardlucj for this too as commented in my code.
Edit
I have used this also. I have a content length field upto which i am reading and writing
byte[] bytes = new byte[1024];
int totalReadLength = 0;
// read untill we have bytes
while ((read = inputStream.read(bytes)) != -1
&& contentLength >= (totalReadLength)) {
outputStream.write(bytes, 0, read);
totalReadLength += read;
System.out.println(" read size ======= "
+ read + " totalReadLength = "
+ totalReadLength);
}
String is not a container for binary data, and PrintWriter isn't a way to write it. Get rid of all, all, the conversions between bytes and String and vice versa, and just transfer the bytes with input and output streams:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
If you need to constrain the number of bytes read from the input, you have to do that before calling read(), and you also have to constrain the read() correctly:
while (total < length && (count = in.read(buffer, 0, length-total > buffer.length ? buffer.length: (int)(length-total))) > 0)
{
total += count;
out.write(buffer, 0, count);
}
I tested it in my Nexus4 and it's working for me. Here is the snippet of code what I tried :
public void saveImage(String urlPath)throws Exception{
String fileName = "kumar.jpg";
File folder = new File("/sdcard/MyImages/");
// have the object build the directory structure, if needed.
folder.mkdirs();
final File output = new File(folder,
fileName);
if (output.exists()) {
output.delete();
}
InputStream stream = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlPath);
stream = url.openConnection().getInputStream();
// InputStreamReader reader = new InputStreamReader(stream);
DataInputStream dis = new DataInputStream(url.openConnection().getInputStream());
byte[] fileData = new byte[url.openConnection().getContentLength()];
for (int x = 0; x < fileData.length; x++) { // fill byte array with bytes from the data input stream
fileData[x] = dis.readByte();
}
dis.close();
fos = new FileOutputStream(output.getPath());
fos.write(fileData);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Just Call the above function in a background thread and pass your url. It'll work for sure. Let me know if it helps.
You can check below code.
destinationFile = new File(
Environment.getExternalStorageDirectory()
+ "/FileName_/"
+ m_httpParser.filename + ".jpg");
BufferedOutputStream buffer = new BufferedOutputStream(new FileOutputStream(destinationFile));
byte byt[] = new byte[1024];
int i;
for (long l = 0L; (i = input.read(byt)) != -1; l += i ) {
buffer.write(byt, 0, i);
}
buffer.close();

Categories

Resources