i am trying to implement a webview that start a video intent, and return the video to a webView.
What i try to do:
1) Java - add webAppInterface that open video capture intent:
mWebView = (WebView) findViewById(R.id.webView);
mWebView.addJavascriptInterface(webAppInterface, "Android");
public class WebAppInterface {
...
public void dispatchTakeVideoIntent() {
Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
takeVideoIntent.putExtra(android.provider.MediaStore.EXTRA_DURATION_LIMIT,10);
if (takePictureIntent.resolveActivity(mContext.getPackageManager()) != null) {
((AppCompatActivity) mContext).startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE);
}
}
...
2) JavaScript - Call it from the webview:
Android.dispatchTakeVideoIntent()
3) Java - Get the Uri, and send path to my webview
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == Activity.RESULT_OK) {
Uri videoUri = intent.getData();
wView.loadUrl("javascript:test('" + videoUri.getPath() + "')");
}
}
4) JavaScript - Get the path in my webView
window.test = (videoUriPath) => {
...
}
My question is, how to access the video?
And maybe there is a totally different way to go about it?
Accessing the video means I'll suppose playing the video in webView. Have a video element in your HTML (suppose id is 'my-video'), then your javascript will be:
window.test = (videoUriPath) => {
var video = document.getElementById('video');
var source = document.createElement('source');
source.setAttribute('src', videoUriPath);
video.appendChild(source);
video.load();
video.play();
}
ok i found a solution, its a little overkill, but its working...
1) JAVA: convert the video to bytes array
byte[] bytes;
byte[] data = new byte[16384];
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
while ((bytesRead = is.read(data)) != -1) {
output.write(data, 0, bytesRead);
}
bytes = output.toByteArray();
2) JAVA: send encoded chunks (base64) to the webvView
int startIndex = 0;
int chunkSize= 16384;
while(startIndex < bytes.length){
byte[] newArray = Arrays.copyOfRange(bytes, startIndex, startIndex + chunkSize);
startIndex = startIndex + chunkSize;
encodedString = Base64.encodeToString(newArray, Base64.DEFAULT);
wView.loadUrl("javascript:g_sendFile_f('" + encodedString + "')");
}
wView.loadUrl("javascript:g_sendFile_f('" + "finish" + "')");
3) JAVASCRIPT: receive the encode chunks, combine them, and create blob file
let bytesArrFinal_an = []
window.g_sendFile_f = (msg) =>{
// last call
if(msg === "finish"){
let blob = new Blob(byteArrFinal_an,{type : "video/mp4"})
this.test_videoUrl = URL.createObjectURL(blob);
console.log("finish")
return
}
// add bytes to final array
let bytesArr_an = this.b64toByteArr(msg)
bytesArrFinal_an = bytesArrFinal_an.concat(bytesArr_an);
console.log(msg)
}
If someone have a more elegant solution i will be happy the see it!
Related
I have implemented a function in an .NET application to download a large number of files using a stream with an undefined initial length.
I need to capture, on the browser, when the stream ends to show an alert to the user but I have difficulty understanding how to solve or which workaround to use.
This is my function:
private void OutputStreamZipped(Page page)
{
page.Response.ContentType = "application/zip";
page.Response.AddHeader("content-disposition", "attachment" + ";filename=" + "myFileName.zip");
page.Response.AddHeader("Accept-Ranges", "bytes");
page.Response.AddHeader("Expires", "0");
page.Response.AddHeader("Pragma", "cache");
page.Response.AddHeader("Cache-Control", "private");
page.Response.Buffer = false;
page.Response.BufferOutput = false;
byte[] buffer = new byte[2 * 1024 * 1024];
try
{
using (ZipOutputStream zipOutputStream = new ZipOutputStream(Response.OutputStream))
{
zipOutputStream.SetLevel(3);
DirectoryInfo DI = new DirectoryInfo(#"C:\myFolder");
foreach (var i in DI.GetFiles())
{
Stream fs = File.OpenRead(i.FullName);
ZipEntry zipEntry = new ZipEntry(ZipEntry.CleanName(i.Name));
zipEntry.Size = fs.Length;
zipOutputStream.PutNextEntry(zipEntry);
int count = fs.Read(buffer, 0, buffer.Length);
while (count > 0)
{
zipOutputStream.Write(buffer, 0, count);
count = fs.Read(buffer, 0, buffer.Length);
if (!Response.IsClientConnected)
{
break;
}
Response.Flush();
}
fs.Close();
}
zipOutputStream.Close();
}
Response.Flush();
page.Response.SuppressContent = true;
System.Web.HttpContext.Current.ApplicationInstance.CompleteRequest();
}
catch (Exception)
{
throw;
}
}
Thanks to anyone who can give me a tip
Now i'm trying to make a file download with ajax but when i open downloaded file, picture viewer said this file format is not supported
how can i fix it?
it is javascript part
function downloadFile(file_no){
const xhr = new XMLHttpRequest();
xhr.open("POST","/timewizard/file/download/"+file_no);
xhr.send();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4 && xhr.status == 200){
if (xhr.responseText != null && xhr.responseText != "" && xhr.responseText != '[]'){
let item = JSON.parse(xhr.responseText);
console.log(item);
let bytes = new Uint8Array(item.bytes.length);
let length = bytes.length;
for (let i = 0; i < length; i++){
bytes[i] = item.bytes.charCodeAt(i);
}
// let blob = new Blob([item.bytes], {type: item.mime});
let blob = new Blob(bytes, {type: item.mime});
console.log(blob);
let link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
let fileName = "timewizard_" + new Date().getTime();
link.download = fileName + "." + item.extension;
link.click();
// return xhr.responseText;
}
}
}
}
and java class file part
#RequestMapping(value="/download/{file_no}")
// public byte[] fileDownload(HttpServletRequest request, HttpServletResponse response, #PathVariable int file_no) {
public Map<String, Object> fileDownload(HttpServletRequest request, HttpServletResponse response, #PathVariable int file_no) {
Map<String, Object> answer = new HashMap<String, Object>();
FileUploadDto dto = fileUploadBiz.selectOne(file_no);
String extension = FilenameUtils.getExtension(dto.getFile_name());
String mime_front = (dto.getFile_type().equals("P"))?"image":"video";
String mime_back = (extension.toLowerCase().equals("jpg"))?"jpeg":extension.toLowerCase();
answer.put("mime", mime_front + "/" + mime_back);
answer.put("extension", extension);
byte[] down = null;
try {
String uploadPath = WebUtils.getRealPath(request.getSession().getServletContext(), "/resources/image");
File file = new File(uploadPath + "/" + dto.getFile_name());
down = FileCopyUtils.copyToByteArray(file);
String filename = new String(file.getName().getBytes(), "8859_1");
// response.setHeader("Content-Disposition", "attachment; filename=\""+filename +"\"");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
answer.put("bytes", down);
// return down;
return answer;
}
The commented part was a method of creating a form and submit button in html and directly spread?returning a byte array, and it actually works nice.
but I want to use a blob.
is there any idea for using blob? or other nice one?
Thanks!
I have a website that is navigated from within a webview. One of the pages generates a ZIP file that is downloaded via a BLOB URL. I discovered that this is not supported by webview, so I have tried implementing this solution:
Download Blob file from Website inside Android WebViewClient
However, it is not working for me. Breakpoints in convertBase64StringToZipAndStoreIt are never hit.
UPDATE: I've found that I'm getting an HTTP 404. I've tried using blobUrl and blobUrl.substring(5) and the result is the same either way. The BLOBs are downloading fine in Chrome, though.
Webview setup:
private void launchWV() {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
1);
setContentView(R.layout.activity_self_service_launcher);
mWebView = (WebView) findViewById(R.id.activity_launcher_webview);
WebSettings webSettings = mWebView.getSettings();
webSettings.setBuiltInZoomControls(true);
webSettings.setSupportZoom(true);
webSettings.setJavaScriptEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setSupportMultipleWindows(true);
webSettings.setAllowContentAccess(true);
webSettings.setAllowFileAccess(true);
webSettings.setAllowFileAccessFromFileURLs(true);
webSettings.setUserAgentString("Mozilla/5.0 (Android; X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.34 Safari/534.24" + getClientVersionInfo());
webSettings.setDomStorageEnabled(true);
webSettings.setLoadWithOverviewMode(true);
mWebView.setWebViewClient(new MyWebViewClient(this));
mWebView.setWebChromeClient(new MyWebChromeClient(this));
mWebView.addJavascriptInterface(new JavaScriptInterface(getApplicationContext()), "Android");
}
Function called from shouldOverrideUrlLoading() (only the else condition for BLOB URLs is of concern):
private boolean handleRequest(WebView view, String url) {
String filename;
if (!checkInternetConnection()) {
ShowNetworkUnavailableDialog(false);
return true;
}
else {
if (url.contains("view/mys") || url.contains("view/myy") || url.contains("blob") || url.contains("view/mye")) {
if (url.contains("view/mys")) {
filename = getResources().getString(R.string.mys_file_name).concat(".pdf");
} else if (url.contains("view/myy")) {
filename = getResources().getString(R.string.form_file_name).concat(".pdf");
} else if (url.contains("blob")) {
filename = getResources().getString(R.string.mys_file_name).concat(".zip");
} else {
filename = getResources().getString(R.string.mye_file_name).concat(".pdf");
}
if (!url.contains("blob")) {
String cookies = CookieManager.getInstance().getCookie(url);
DownloadManager.Request downloadRequest = new DownloadManager.Request(Uri.parse(url));
downloadRequest.addRequestHeader("cookie", cookies);
downloadRequest.allowScanningByMediaScanner();
downloadRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
downloadRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
try {
dm.enqueue(downloadRequest);
} catch (SecurityException e) {
Toast.makeText(getApplicationContext(), getResources().getString(R.string.connection_unavailable), Toast.LENGTH_LONG).show();
return false;
}
} else {
String blobURL = JavaScriptInterface.getBase64StringFromBlobUrl(url);
mWebView.loadUrl(blobURL);
}
Toast.makeText(getApplicationContext(), getResources().getString(R.string.download_message), Toast.LENGTH_LONG).show();
return true;
} else if (!url.contains(getMetadata(getApplicationContext(), HOSTNAME))) {
//Navigate to external site outside of webview e.g. Help site
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
} else if(url.contains(getResources().getString(R.string.about_url))) {
mWebView.loadUrl(url);
return false;
} else {
if (savedInstanceState == null) {
mWebView.loadUrl(url);
}
return false;
}
}
}
JavaScriptInterface class:
public class JavaScriptInterface {
private Context context;
private NotificationManager nm;
public JavaScriptInterface(Context context) {
this.context = context;
}
#JavascriptInterface
public void getBase64FromBlobData(String base64Data) throws IOException {
convertBase64StringToZipAndStoreIt(base64Data);
}
public static String getBase64StringFromBlobUrl(String blobUrl){
if(blobUrl.startsWith("blob")){
return "javascript: var xhr = new XMLHttpRequest();" +
"xhr.open('GET', '" + blobUrl.substring(5) + "', true);" +
"xhr.setRequestHeader('Content-type','application/zip');" +
"xhr.responseType = 'blob';" +
"xhr.onload = function(e) {" +
" if (this.status == 200) {" +
" var blobZip = this.response;" +
" var reader = new FileReader();" +
" reader.readAsDataURL(blobZip);" +
" reader.onloadend = function() {" +
" base64data = reader.result;" +
" Android.getBase64FromBlobData(base64data);" +
" }" +
" }" +
"};" +
"xhr.send();";
}
return "javascript: console.log('It is not a Blob URL');";
}
private void convertBase64StringToZipAndStoreIt(String base64Zip) throws IOException {
final int notificationId = 1;
String currentDateTime = DateFormat.getDateTimeInstance().format(new Date());
final File dwldsPath = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS) + "/YourFileName_" + currentDateTime + "_.zip");
byte[] zipAsBytes = Base64.decode(base64Zip.replaceFirst("^data:application/zip;base64,", ""), 0);
FileOutputStream os;
os = new FileOutputStream(dwldsPath, false);
os.write(zipAsBytes);
os.flush();
if(dwldsPath.exists()) {
NotificationCompat.Builder b = new NotificationCompat.Builder(context, "MY_DL")
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("MY TITLE")
.setContentText("MY TEXT CONTENT");
nm = (NotificationManager) this.context.getSystemService(Context.NOTIFICATION_SERVICE);
if(nm != null) {
nm.notify(notificationId, b.build());
Handler h = new Handler();
long delayInMilliseconds = 5000;
h.postDelayed(new Runnable() {
public void run() {
nm.cancel(notificationId);
}
}, delayInMilliseconds);
}
}
}
}
One thing I know I am unclear on is what URL should be going into the call to xhr.open in the class.
I also tried using onDownloadStart with the same result.
Any insight is greatly appreciated!
I'm trying to upload the image in Samsung j7 camera. I get some server response with </div> tag.
How can I resolve this error and what is the way to get the image from the response?
Error Image Form Android Server Response
My code
protected void Upload_Server() {
// TODO Auto-generated method stub
String urlServer = null;
System.out.println("After call progress");
try{
Log.e("Image Upload", "Inside Upload");
HttpURLConnection connection = null;
DataOutputStream outputStream = null;
DataInputStream inputStream = null;
String pathToOurFile = imagepath;
// String pathToOurFile1 = imagepathcam;
System.out.println("Before Image Upload" + imagepath);
if(Videoboolean){
urlServer = Constants.IMAGEVIDEOURL+"videopostUpload/";
}else {
urlServer = Constants.IMAGEVIDEOURL+"imagepostUpload/";
}
System.out.println("URL SETVER" + urlServer);
System.out.println("After Image Upload" + imagepath);
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1*1024*1024;
System.out.println("enter the file path in android"+pathToOurFile);
FileInputStream fileInputStream = new FileInputStream(new File(pathToOurFile));
// FileInputStream fileInputStream1 = new FileInputStream(new File(pathToOurFile1));
URL url = new URL(urlServer);
connection = (HttpURLConnection) url.openConnection();
System.out.println("URL is "+url);
System.out.println("connection is "+connection);
// Allow Inputs & Outputs
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
// Enable POST method
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
outputStream = new DataOutputStream( connection.getOutputStream() );
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + pathToOurFile +"\"" + lineEnd);
outputStream.writeBytes(lineEnd);
System.out.println("enter the image upload response"+outputStream.getClass().getCanonicalName());
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
// Read file
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
outputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// Responses from the server (code and message)
int serverResponseCode = connection.getResponseCode();
String serverResponseMessage = connection.getResponseMessage();
System.out.println("image"+serverResponseMessage);
fileInputStream.close();
outputStream.flush();
outputStream.close();
DataInputStream inputStream1 = null;
inputStream1 = new DataInputStream (connection.getInputStream());
String str="";
String Str1_imageurl="";
while (( str = inputStream1.readLine()) != null)
{
Log.e("Debug","Server Response "+str);
Str1_imageurl = str;
Log.e("Debug","Server Response String imageurl"+str);
}
inputStream1.close();
System.out.println("image url"+Str1_imageurl);
PostImVD = Str1_imageurl.trim();
JSONArray array = new JSONArray(PostImVD);
JSONObject jsonObj = array.getJSONObject(0);
if(Videoboolean){
ImageVideo = jsonObj.optString("video_name");
}else {
ImageVideo = jsonObj.optString("image_name");
}
System.out.println("Profile Picture Path" + PostImVD);
System.out.println("Profile Picture Path" + ImageVideo);
}
catch(Exception e){
e.printStackTrace();
}
};
1: Error Image Form Android Server Response
First, try to validate your JSON response in this page for example:
https://jsonlint.com/
If your JSON is correct, then determine if is an array or an object, depends of that use the correct parsing :
If it's an array:
JSONArray array = new JSONArray(your_string_json);
If it's an object
JSONObject object = new JSONObject(your_string_json);
i'm trying to implements this:
1) Have a file uploader in a JSP page
2) select an image and push the button "save"
3) then in a servlet save the image into a database
4) so when i need read the image from the database
Just for info i'm using spring and hibernate.
I found a working code. This is the html code:
<form class="navbar-form" name="myform" id="myform" method="POST">
<input type="file" id="files" name="file" />
<input class="span2" type="hidden" name="image" id="image" value="-1">
<span class="readBytesButtons">
<button>Save</button>
</span>
</form>
And i've a javascript with this code
<script>
function base64_encode (data) {
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
ac = 0,
enc = "",
tmp_arr = [];
if (!data) {
return data;
}
do { // pack three octets into four hexets
o1 = data.charCodeAt(i++);
o2 = data.charCodeAt(i++);
o3 = data.charCodeAt(i++);
bits = o1 << 16 | o2 << 8 | o3;
h1 = bits >> 18 & 0x3f;
h2 = bits >> 12 & 0x3f;
h3 = bits >> 6 & 0x3f;
h4 = bits & 0x3f;
// use hexets to index into b64, and append result to encoded string
tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
} while (i < data.length);
enc = tmp_arr.join('');
var r = data.length % 3;
return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
}
function readBlob(opt_startByte, opt_stopByte) {
var files = document.getElementById('files').files;
if (!files.length) {
alert('Please select a file!');
return;
}
var file = files[0];
var start = parseInt(opt_startByte) || 0;
var stop = parseInt(opt_stopByte) || file.size - 1;
var reader = new FileReader();
// If we use onloadend, we need to check the readyState.
reader.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
document.getElementById('myform').image.value= base64_encode(evt.target.result);
document.getElementById('myform').action = "saveImg.htm";
document.getElementById('myform').submit();
}
};
var blob = file.slice(start, stop + 1);
reader.readAsBinaryString(blob);
}
document
.querySelector('.readBytesButtons')
.addEventListener(
'click',
function(evt) {
if (evt.target.tagName.toLowerCase() == 'button') {
var startByte = evt.target
.getAttribute('data-startbyte');
var endByte = evt.target
.getAttribute('data-endbyte');
readBlob(startByte, endByte);
}
}, false);
</script>
and the code of my sprint controller
#RequestMapping(value = "saveImg", method = RequestMethod.POST)
public ModelAndView login(
#RequestParam("image") String image,
Model model) {
try {
Images newImage = new Images();
newImage.setImage(image.getBytes());
imagesBo.save(newImage);
System.out.println(newImage.getStrImage());
model.addAttribute("strImage", newImage.getStrImage());
return new ModelAndView("index");
}
catch (Exception e) {
model.addAttribute("msg", e.getMessage());
System.out.println("Eccezione: " + e.getMessage());
return new ModelAndView("index");
}
And now the image its saved in the database. Now when i need to load the image from the database i just do this
#Autowired
#Autowired
ImagesBo imagesBo;
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
ModelAndView model = new ModelAndView("show_image");
Map<String, Object> myModel = new HashMap<String, Object>();
Images img = imagesBo.getImage();
myModel.put("image", img.getStrImage());
return new ModelAndView("lista_libri_in_catalogo", "model", myModel);
}
where getStrImage() it's a function in the Class Images
public String getStrImage() {
byte[] _bytes = this.image;
String file_string = "";
for (int i = 0; i < _bytes.length; i++) {
file_string += (char) _bytes[i];
}
return file_string;
}
At last in the show:image.jsp i use this code
<img src="data:img/jpeg;base64, ${model.strImage}" width="200px" height="200px"></div>
As i said, this works perfectly, but i'm not sure the best way to do this. Someone have some better codes? Or some suggestion?
Thanks.
I would not save the contents of an image direct into my database.
I would transfer the image to a folder and then save the path in my database with the location of the image.
I don't know for sure if this is the best practice but i see it get used allot and I also used this implementation to save images in past projects.