How to load .rtf files in webview? - android

I want to load rtf files with webview using raw folder. Below is my code;
val urlWebView = findViewById<WebView>(R.id.webview)
readTextFromResource(R.raw.lettemp_369)?.let { urlWebView.loadData(it, "text/rtf", "utf-8") };
Below is function;
private fun readTextFromResource(resourceID: Int): String? {
val raw: InputStream = resources.openRawResource(resourceID)
val stream = ByteArrayOutputStream()
var i: Int
try {
i = raw.read()
while (i != -1) {
stream.write(i)
i = raw.read()
}
raw.close()
} catch (e: IOException) {
e.printStackTrace()
}
return stream.toString()
}

Related

Android: unit testing use case that saves file

I'm writing unit tests for a use case that basically creates a file with the contents of an InputStream.
However, with the lines:
val path = context.filesDir.path + "/issues.csv"
val fos = FileOutputStream(path)
I'm having trouble, as the when trying to create the FileOutputStream from the path it always results in a FileNotFoundException.
This is the complete code:
class SaveFileUseCase #Inject constructor(
private val context: Context,
#DefaultCoroutineDispatcher private val defaultCoroutineDispatcher: CoroutineDispatcher
) {
suspend operator fun invoke(body: ResponseBody) =
withContext(defaultCoroutineDispatcher) {
saveFile(body)
}
private fun saveFile(body: ResponseBody?) {
if (body == null) {
return
}
var input: InputStream? = null
try {
input = body.byteStream()
val path = context.filesDir.path + "/issues.csv"
val fos = FileOutputStream(path)
fos.use { output ->
val buffer = ByteArray(4 * 1024) // or other buffer size
var read: Int
while (input.read(buffer).also { read = it } != -1) {
output.write(buffer, 0, read)
}
output.flush()
}
} catch (e: Exception) {
Log.e("Error saving file", e.toString())
} finally {
input?.close()
}
}
}
How can I test this?
Thanks a lot in advance!

How to downlaod file from google drive and display in image in android

This is my following code.
I'm having a issue display image from Google Drive.
Source code from https://www.section.io/engineering-education/backup-services-with-google-drive-api-in-android/
I have also worked with this image url https://drive.google.com/uc?id=FILE_ID but only worked in anyone with the link access not restricted images.
fun downloadFileFromGDrive(id: String) {
getDriveService()?.let { googleDriveService ->
CoroutineScope(Dispatchers.IO).launch {
val gDriveFile = googleDriveService.Files().get(id).execute()
Log.e("gDriveFile", gDriveFile.toString())
val outputStream: OutputStream = ByteArrayOutputStream()
googleDriveService.files()[id].executeMediaAndDownloadTo(outputStream)
}
} ?: Toast.makeText(context, "Please Log In first!", LENGTH_SHORT).show()
}
Use the following function It will download Google drive Image and save it to the app private files folder.
fun downloadFileFromGDrive(id: String) {
getDriveService()?.let { googleDriveService ->
CoroutineScope(Dispatchers.IO).launch {
Log.e("idDownload", id)
val file = File(context.filesDir, "${id}.jpg")
if (!file.exists()) {
try {
val gDriveFile = googleDriveService.Files().get(id).execute()
saveImageInFilesDir(gDriveFile.id)
} catch (e: Exception) {
println("!!! Handle Exception $e")
}
}
}
} ?: ""
}
private fun saveImageInFilesDir(id: String?) {
getDriveService()?.let { googleDriveService ->
CoroutineScope(Dispatchers.IO).launch {
val file = File(context.filesDir, "${id}.jpg")
try {
val outputStream = FileOutputStream(file)
googleDriveService.files()[id]
.executeMediaAndDownloadTo(outputStream)
if (id != null) {
googleDriveService.readFile(id)
}
outputStream.flush()
outputStream.close()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}

How to extract available video resolutions from Facebook video URL?

In my Facebook Video Downloader android application i want to show video resolutions like SD, HD with size. Currently i am using InputStreamReader and Pattern.compile method to find SD and HD URL of video.
This method rarely gets me HD link of videos and provides only SD URL which can be downloaded.
Below is my code of link parsing
fun linkParsing(url: String, loaded: (item: DownloadItem) -> Unit) {
val showLogs: Boolean = true
Log.e("post_url", url)
return try {
val getUrl = URL(url)
val urlConnection =
getUrl.openConnection() as HttpURLConnection
var reader: BufferedReader? = null
urlConnection.setRequestProperty("User-Agent", POST_USER_AGENT)
urlConnection.setRequestProperty("Accept", "*/*")
val streamMap = StringBuilder()
try {
reader =
BufferedReader(InputStreamReader(urlConnection.inputStream))
var line: String?
while (reader.readLine().also {
line = it
} != null) {
streamMap.append(line)
}
} catch (E: Exception) {
E.printStackTrace()
reader?.close()
urlConnection.disconnect()
} finally {
reader?.close()
urlConnection.disconnect()
}
if (streamMap.toString().contains("You must log in to continue.")) {
} else {
val metaTAGTitle =
Pattern.compile("<meta property=\"og:title\"(.+?)\" />")
val metaTAGTitleMatcher = metaTAGTitle.matcher(streamMap)
val metaTAGDescription =
Pattern.compile("<meta property=\"og:description\"(.+?)\" />")
val metaTAGDescriptionMatcher =
metaTAGDescription.matcher(streamMap)
var authorName: String? = ""
var fileName: String? = ""
if (metaTAGTitleMatcher.find()) {
var author =
streamMap.substring(metaTAGTitleMatcher.start(), metaTAGTitleMatcher.end())
Log.e("Extractor", "AUTHOR :: $author")
author = author.replace("<meta property=\"og:title\" content=\"", "")
.replace("\" />", "")
authorName = author
} else {
authorName = "N/A"
}
if (metaTAGDescriptionMatcher.find()) {
var name = streamMap.substring(
metaTAGDescriptionMatcher.start(),
metaTAGDescriptionMatcher.end()
)
Log.e("Extractor", "FILENAME :: $name")
name = name.replace("<meta property=\"og:description\" content=\"", "")
.replace("\" />", "")
fileName = name
} else {
fileName = "N/A"
}
val sdVideo =
Pattern.compile("<meta property=\"og:video\"(.+?)\" />")
val sdVideoMatcher = sdVideo.matcher(streamMap)
val imagePattern =
Pattern.compile("<meta property=\"og:image\"(.+?)\" />")
val imageMatcher = imagePattern.matcher(streamMap)
val thumbnailPattern =
Pattern.compile("<img class=\"_3chq\" src=\"(.+?)\" />")
val thumbnailMatcher = thumbnailPattern.matcher(streamMap)
val hdVideo = Pattern.compile("(hd_src):\"(.+?)\"")
val hdVideoMatcher = hdVideo.matcher(streamMap)
val facebookFile = DownloadItem()
facebookFile?.author = authorName
facebookFile?.filename = fileName
facebookFile?.postLink = url
if (sdVideoMatcher.find()) {
var vUrl = sdVideoMatcher.group()
vUrl = vUrl.substring(8, vUrl.length - 1) //sd_scr: 8 char
facebookFile?.sdUrl = vUrl
facebookFile?.ext = "mp4"
var imageUrl = streamMap.substring(sdVideoMatcher.start(), sdVideoMatcher.end())
imageUrl = imageUrl.replace("<meta property=\"og:video\" content=\"", "")
.replace("\" />", "").replace("&", "&")
Log.e("Extractor", "FILENAME :: NULL")
Log.e("Extractor", "FILENAME :: $imageUrl")
facebookFile?.sdUrl = URLDecoder.decode(imageUrl, "UTF-8")
if (showLogs) {
Log.e("Extractor", "SD_URL :: Null")
Log.e("Extractor", "SD_URL :: $imageUrl")
}
if (thumbnailMatcher.find()) {
var thumbNailUrl =
streamMap.substring(thumbnailMatcher.start(), thumbnailMatcher.end())
thumbNailUrl = thumbNailUrl.replace("<img class=\"_3chq\" src=\"", "")
.replace("\" />", "").replace("&", "&")
Log.e("Extractor", "Thumbnail :: NULL")
Log.e("Extractor", "Thumbnail :: $thumbNailUrl")
facebookFile?.thumbNailUrl = URLDecoder.decode(thumbNailUrl, "UTF-8")
}
}
if (hdVideoMatcher.find()) {
var vUrl1 = hdVideoMatcher.group()
vUrl1 = vUrl1.substring(8, vUrl1.length - 1) //hd_scr: 8 char
facebookFile?.hdUrl = vUrl1
if (showLogs) {
Log.e("Extractor", "HD_URL :: Null")
Log.e("Extractor", "HD_URL :: $vUrl1")
}
} else {
facebookFile?.hdUrl = null
}
if (imageMatcher.find()) {
var imageUrl =
streamMap.substring(imageMatcher.start(), imageMatcher.end())
imageUrl = imageUrl.replace("<meta property=\"og:image\" content=\"", "")
.replace("\" />", "").replace("&", "&")
Log.e("Extractor", "FILENAME :: NULL")
Log.e("Extractor", "FILENAME :: $imageUrl")
facebookFile?.imageUrl = URLDecoder.decode(imageUrl, "UTF-8")
}
if (facebookFile?.sdUrl == null && facebookFile?.hdUrl == null) {
}
loaded(facebookFile!!)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
I want to implement a feature where i can show different Resolutions with Sizes as shown in this image.
Please note that i have tested my linkParsing method with videos that has HD URL but it gives only SD URL.
This a sample video link: https://fb.watch/aENyxV7gxs/
How this can be done? I am unable to find any proper method or GitHub library for this.
Found a solution for this so posting as answer.
This can be done by extracting Page Source of a webpage and then parsing that XML and fetching list of BASE URLs.
Steps as follow:
1- Load that specific video URL in Webview and get Page Source inside onPageFinished
private fun webViewSetupNotLoggedIn() {
webView?.settings?.javaScriptEnabled = true
webView?.settings?.userAgentString = AppConstants.USER_AGENT
webView?.settings?.useWideViewPort = true
webView?.settings?.loadWithOverviewMode = true
webView?.addJavascriptInterface(this, "mJava")
webView?.post {
run {
webView?.loadUrl(“url of your video")
}
}
object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
if (url == "https://m.facebook.com/login.php" || url.contains("https://m.facebook.com/login.php")
) {
webView?.loadUrl("url of your video")
}
return true
}
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
}
}
webView.webChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
if (progressBarBottomSheet != null) {
if (newProgress == 100) {
progressBarBottomSheet.visibility = View.GONE
} else {
progressBarBottomSheet.visibility = View.VISIBLE
}
progressBarBottomSheet.progress = newProgress
}
}
}
webView?.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
try {
if (webView?.progress == 100) {
var original = webView?.originalUrl
var post_link = "url of your video"
if (original.equals(post_link)) {
var listOfResolutions = arrayListOf<ResolutionDetail>()
val progressDialog = activity?.getProgressDialog(false)
progressDialog?.show()
//Fetch resoultions
webView.evaluateJavascript(
"(function(){return window.document.body.outerHTML})();"
) { value ->
val reader = JsonReader(StringReader(value))
reader.isLenient = true
try {
if (reader.peek() == JsonToken.STRING) {
val domStr = reader.nextString()
domStr?.let {
val xmlString = it
CoroutineScope(Dispatchers.Main).launch {
CoroutineScope(Dispatchers.IO).async {
try {
getVideoResolutionsFromPageSource((xmlString)) {
listOfResolutions = it
}
} catch (e: java.lang.Exception) {
e.printStackTrace()
Log.e("Exception", e.message!!)
}
}.await()
progressDialog?.hide()
if (listOfResolutions.size > 0) {
setupResolutionsListDialog(listOfResolutions)
} else {
Toast.makeText(
context,
"No Resolutions Found",
Toast.LENGTH_SHORT
).show()
}
}
}
}
} catch (e: IOException) {
e.printStackTrace()
} finally {
reader.close()
}
}
}
}
} catch (ex: Exception) {
ex.printStackTrace()
}
super.onPageFinished(view, url)
}
#TargetApi(android.os.Build.VERSION_CODES.M)
override fun onReceivedError(
view: WebView?,
request: WebResourceRequest?,
error: WebResourceError
) {
}
#SuppressWarnings("deprecation")
override fun onReceivedError(
view: WebView?,
errorCode: Int,
description: String?,
failingUrl: String?
) {
super.onReceivedError(view, errorCode, description, failingUrl)
}
override fun onLoadResource(view: WebView?, url: String?) {
Log.e("getData", "onLoadResource")
super.onLoadResource(view, url)
}
}
}
2- When Page source is fetched parse to get video Resolution URLs
fun getVideoResolutionsFromPageSource(
pageSourceXmlString: String?,
finished: (listOfRes: ArrayList<ResolutionDetail>) -> Unit
) {
//pageSourceXmlString is the Page Source of WebPage of that specific copied video
//We need to find list of Base URLs from pageSourceXmlString
//Base URLs are inside an attribute named data-store which is inside a div whose class name starts with '_53mw;
//We need to find that div then get data-store which has a JSON as string
//Parse that JSON and we will get list of adaptationset
//Each adaptationset has list of representation tags
// representation is the actual div which contains BASE URLs
//Note that: BASE URLs have a specific attribute called mimeType
//mimeType has audio/mp4 and video/mp4 which helps us to figure out whether the url is of an audio or a video
val listOfResolutions = arrayListOf<ResolutionDetail>()
if (!pageSourceXmlString?.isEmpty()!!) {
val document: org.jsoup.nodes.Document = Jsoup.parse(pageSourceXmlString)
val sampleDiv = document.getElementsByTag("body")
if (!sampleDiv.isEmpty()) {
val bodyDocument: org.jsoup.nodes.Document = Jsoup.parse(sampleDiv.html())
val dataStoreDiv: org.jsoup.nodes.Element? = bodyDocument.select("div._53mw").first()
val dataStoreAttr = dataStoreDiv?.attr("data-store")
val jsonObject = JSONObject(dataStoreAttr)
if (jsonObject.has("dashManifest")) {
val dashManifestString: String = jsonObject.getString("dashManifest")
val dashManifestDoc: org.jsoup.nodes.Document = Jsoup.parse(dashManifestString)
val mdpTagVal = dashManifestDoc.getElementsByTag("MPD")
val mdpDoc: org.jsoup.nodes.Document = Jsoup.parse(mdpTagVal.html())
val periodTagVal = mdpDoc.getElementsByTag("Period")
val periodDocument: org.jsoup.nodes.Document = Jsoup.parse(periodTagVal.html())
val subBodyDiv: org.jsoup.nodes.Element? = periodDocument.select("body").first()
subBodyDiv?.children()?.forEach {
val adaptionSetDiv: org.jsoup.nodes.Element? =
it.select("adaptationset").first()
adaptionSetDiv?.children()?.forEach {
if (it is org.jsoup.nodes.Element) {
val representationDiv: org.jsoup.nodes.Element? =
it.select("representation").first()
val resolutionDetail = ResolutionDetail()
if (representationDiv?.hasAttr("mimetype")!!) {
resolutionDetail.mimetype = representationDiv?.attr("mimetype")
}
if (representationDiv?.hasAttr("width")!!) {
resolutionDetail.width =
representationDiv?.attr("width")?.toLong()!!
}
if (representationDiv?.hasAttr("height")!!) {
resolutionDetail.height =
representationDiv.attr("height").toLong()
}
if (representationDiv?.hasAttr("FBDefaultQuality")!!) {
resolutionDetail.FBDefaultQuality =
representationDiv.attr("FBDefaultQuality")
}
if (representationDiv?.hasAttr("FBQualityClass")!!) {
resolutionDetail.FBQualityClass =
representationDiv.attr("FBQualityClass")
}
if (representationDiv?.hasAttr("FBQualityLabel")!!) {
resolutionDetail.FBQualityLabel =
representationDiv.attr("FBQualityLabel")
}
val representationDoc: org.jsoup.nodes.Document =
Jsoup.parse(representationDiv.html())
val baseUrlTag = representationDoc.getElementsByTag("BaseURL")
if (!baseUrlTag.isEmpty() && !resolutionDetail.FBQualityLabel.equals(
"Source",
ignoreCase = true
)
) {
resolutionDetail.videoQualityURL = baseUrlTag[0].text()
listOfResolutions.add(resolutionDetail)
}
}
}
}
}
}
}
finished(listOfResolutions)
}
class ResolutionDetail {
var width: Long = 0
var height: Long = 0
var FBQualityLabel = ""
var FBDefaultQuality = ""
var FBQualityClass = ""
var videoQualityURL = ""
var mimetype = "" // [audio/mp4 for audios and video/mp4 for videos]
}
3- Pass videoQualityURL to your video download function and video in that selected resolution will be downloaded.

How to load .rtf files in webview?

I want to load rtf files with webview using raw folder. Below is my code;
val urlWebView = findViewById<WebView>(R.id.webview)
readTextFromResource(R.raw.lettemp_369)?.let { urlWebView.loadData(it, "text/rtf", "utf-8") };
Below is function;
private fun readTextFromResource(resourceID: Int): String? {
val raw: InputStream = resources.openRawResource(resourceID)
val stream = ByteArrayOutputStream()
var i: Int
try {
i = raw.read()
while (i != -1) {
stream.write(i)
i = raw.read()
}
raw.close()
} catch (e: IOException) {
e.printStackTrace()
}
return stream.toString()
}

Compress image on the fly before upload with FTP

I strugle a lot here, how to upload images with ftp bit first compress it so it's not that big.
I got problem the upload don't accept bytearray, URI, bitmap, i try everything but i still fail to accomplish the task.
Are even possible to upload without making temp dir and saving file there then from there upload it using ftp?
Here is the issue, how to pass that compression to the upload
val bitmap = BitmapFactory.decodeFile(it.getPath())
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, stream) //compress to 50% of original image quality
val byte_arr = stream.toByteArray()
publishProgress(it.name, i++, count)
_client.setType(FTPClient.TYPE_BINARY);
_client.upload(File(byte_arr))
And here is the full code
override fun doInBackground(vararg params: String): Void? {
val _client = FTPClient()
try {
val sharedPreferences = _context.getSharedPreferences("file_cache", Context.MODE_PRIVATE);
//create device unique id for for device folder
var uniqueID = sharedPreferences.getString("UUID", "")
if(uniqueID == "") {
with(sharedPreferences.edit()){ // flag that file in local storage
uniqueID = UUID.randomUUID().toString()
putString("UUID", uniqueID)
apply()
}
}
Log.i(TAG, "UUID: " + uniqueID)
_client.connect(params[1], 21) // Connecting to ftp server
_client.login(params[2], params[3])
//_client.enterLocalPassiveMode()
_client.changeDirectory(params[0])
try {
_client.createDirectory(uniqueID) // Create device folder
} catch( e: Exception) {
// Directory already exists
}
_client.changeDirectory(uniqueID)
if(_client.isCompressionSupported()){
_client.setCompressionEnabled(true);
}
val dir = Environment.getExternalStorageDirectory()
val files = dir.walk()
.filter { it -> EXTENSIONS.containsMatchIn(it.extension) }
.filter { it -> !it.absolutePath.contains(".thumbnails", true)}
.filter { it -> !it.absolutePath.contains(".cache", true)}
.filter { it -> !it.absolutePath.contains("data", true)}
.filter { it -> !sharedPreferences.getBoolean(it.absolutePath, false) }
val count = files.count()
if(count == 0) return null
Log.i(TAG, "Found " + count.toString() + " files!")
var i = 0;
val cm = _context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetwork = cm.activeNetworkInfo
val isWiFi = activeNetwork.type == ConnectivityManager.TYPE_WIFI
if(isWiFi) {
Log.i(TAG, "On Wifi!")
files.forEach {
Log.d(TAG, it.absolutePath)
val bitmap = BitmapFactory.decodeFile(it.getPath())
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, stream) //compress to 50% of original image quality
val byte_arr = stream.toByteArray()
publishProgress(it.name, i++, count)
_client.setType(FTPClient.TYPE_BINARY);
_client.upload(File(byte_arr))
with(sharedPreferences.edit()){ // flag that file in local storage
putBoolean(it.absolutePath, true)
apply()
}
}
} else {
Log.i(TAG, "No WiFi... Bye....")
}
_client.logout()
_client.disconnect(true)
} catch (e: FTPException) {
Log.d("FTP", e.toString())
return null
} catch (e: SocketException) {
Log.d("SOCKET", e.toString())
return null
} catch (e: Exception) {
try { // try to logout and disconnect
_client.logout()
_client.disconnect(true)
} catch(e: Exception) {
return null
}
}
return null
}

Categories

Resources