Android Image Share to Another App Where is problem? - android

Im doing an app and i want to share photo just i saved to phone to another apps like instagram twitter.Im not able to do it and i cant see where the mistake is.Here is my code
`private fun getScreenshot(currentPage: Int){
QuickShot.of(requireActivity().findViewById<ConstraintLayout(currentPage))
.setResultListener(this)
.enableLogging()
.setFilename("screen")
.setPath("Spotibud")
.toJPG()
.save()
}
override fun onQuickShotSuccess(path: String?) {
Log.d(TAG, "onQuickShotSuccess: $path")
shareOnInstagram(path!!)
}
override fun onQuickShotFailed(path: String?, errorMsg: String?) {
Log.d(TAG, "onQuickShotFailed: $errorMsg")
}
private fun shareOnInstagram(path: String){
val stickerAssetUri: Uri = Uri.parse(path)
val intent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_STREAM,stickerAssetUri)
type = "image/*"
}
startActivity(intent)
}`
and my log when app saves image
2021-02-18 17:28:08.750 16355-16355/com.example.contestifyfirsttry D/Home Fragment: onQuickShotSuccess: /Pictures/Spotibud/screen.jpg
also is there any code how i can see error.try catch not worked

now i found the solution this isnt best practice but im sure it makes you to see what you should do
private fun shareOnInstagram(path: String){
var file : File = File("/storage/emulated/0/Pictures/Spotibud/screen.jpg")
if (file.exists()){
Log.d(TAG, "shareOnInstagram: file exists")
val stickerAssetUri: Uri = Uri.fromFile(file)
val sourceApplication = "com.example.contestifyfirsttry"
val intent = Intent("com.instagram.share.ADD_TO_STORY")
intent.putExtra("source_application", sourceApplication)
intent.type = "image/*"
intent.putExtra("interactive_asset_uri", stickerAssetUri)
intent.putExtra("top_background_color", "#33FF33")
intent.putExtra("bottom_background_color", "#FF00FF")
val activity: Activity? = activity
activity!!.grantUriPermission(
"com.instagram.android", stickerAssetUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
)
if (activity!!.packageManager.resolveActivity(intent, 0) != null) {
activity!!.startActivityForResult(intent, 0)
}
}else{
Log.d(TAG, "shareOnInstagram: file dont exists")
}
}

Related

Automatic video selector from galary android kotlin

i am using this code for selecting the video from gallery app but the problem is that this will open the gallery app and user select the video manually i dont want that.I am looking for the code that will automatically pick video from gallery app by just giving the video path.. I just want to upload a specific video by giving video path from mobile storage to firebase
Intent intent = new Intent();
intent.setType("video/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Video"), REQUEST_TAKE_GALLERY_VIDEO);
this code basically allow user to pick video from mobile storage and it is working fine.. but i want to automatically upload first video to firebase from folder Movies/CamerX-Videos. This folder is in my mobile storage
class MainActivity : AppCompatActivity() {
val VIDEO : Int = 3
lateinit var uri : Uri
lateinit var mStorage : StorageReference
//val uri: Uri = Uri.fromFile(File("/Internal storage/Movies/cameraX-Video/Has.mp4"))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mStorage = FirebaseStorage.getInstance().getReference("Uploads")
val videoBtn = findViewById<View>(R.id.videoBtn) as Button
mStorage = FirebaseStorage.getInstance().reference.child("Uploads")
videoBtn.setOnClickListener(View.OnClickListener {
val intent = Intent()
intent.type = "video/*"
intent.action = Intent.ACTION_GET_CONTENT
startActivityForResult(Intent.createChooser(intent, "Select Video"), VIDEO)
})
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val uriTxt = findViewById<View>(R.id.uriTxt) as TextView
if (resultCode == RESULT_OK) {
if (requestCode == VIDEO) {
uri = data!!.data!!
uriTxt.text = uri.toString()
upload ()
}
}
super.onActivityResult(requestCode, resultCode, data)
}
private fun upload() {
var mReference = uri.lastPathSegment?.let { mStorage.child(it) }
try {
mReference?.putFile(uri)?.addOnSuccessListener { taskSnapshot: UploadTask.TaskSnapshot? -> var url = taskSnapshot!!
val dwnTxt = findViewById<View>(R.id.dwnTxt) as TextView
dwnTxt.text = url.toString()
Toast.makeText(this, "Successfully Uploaded :)", Toast.LENGTH_LONG).show()
}
}catch (e: Exception) {
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show()
}
}
}

Share Image Intent [The file format is not supported]

I implemented share image to other apps using intent, I followed the recommended approach by saving the image first then getting its LocalBitmapUri. but when i run the app and share image i get the Toast message [The file format is not supported]. and i cant seem to figure out what I did wrong.. thanks.
fun shareItem(url: String?,context: Context,scope: CoroutineScope) {
scope.launch {
withContext(Dispatchers.IO){
val i = Intent(Intent.ACTION_SEND)
i.type = "image/*"
i.putExtra(Intent.EXTRA_STREAM,
getBitmap("d",context,"https://cdn2.thecatapi.com/images/3o8.jpg")?.let {
getLocalBitmapUri(
it,
context
)
})
startActivity(context,Intent.createChooser( i, "Share Image"),null)
}
}
}
fun getLocalBitmapUri(bmp: Bitmap,context: Context): Uri? {
val builder = VmPolicy.Builder()
StrictMode.setVmPolicy(builder.build())
var bmpUri: Uri? = null
try {
val file = File(
context.getExternalFilesDir(Environment.DIRECTORY_PICTURES),
"share_image_jj" + System.currentTimeMillis() + ".png"
)
val out = FileOutputStream(file)
bmp.compress(Bitmap.CompressFormat.PNG, 90, out)
out.close()
bmpUri = Uri.fromFile(file)
} catch (e: IOException) {
e.printStackTrace()
}
return bmpUri
}
private suspend fun getBitmap(tag: String, context: Context, imageUrl: String): Bitmap? {
var bitmap: Bitmap? = null
val imageRequest = ImageRequest.Builder(context)
.data(imageUrl)
.target(
...//,
onSuccess = { result ->
Log.e(tag, "Coil loader success.")
bitmap = result.toBitmap()
}
)
.build()
context.imageLoader.execute(imageRequest)
return bitmap
}

How do I stop PDF viewing apps from keeping previous PDFs in the stack?

When I successfully download a PDF from a WebView, I am able to open the PDF with a VIEW intent. When I press the back button, I am returned to my own app. However, when I download and open another PDF, the first PDF appears to still be on the stack. I have to press the back button twice to get back to my app. This is true whether I use the main navigation back button, or the one in the title bar of the PDF viewing activity.
What do I need to change to ensure that only the PDF I am opening is on the stack?
setDownloadListener { url, _, _, mimetype, _ ->
val downloadUri = Uri.parse(url)
val downloadRequest = DownloadManager.Request(downloadUri).apply {
setTitle("Title")
setDescription("Downloading file")
setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, downloadUri.lastPathSegment)
addRequestHeader("Cookie", CookieManager.getInstance().getCookie(url))
}
val manager: DownloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downloadId = manager.enqueue(downloadRequest)
registerReceiver(
object: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.w("onReceive", "${intent?.action}")
if (intent !== null && DownloadManager.ACTION_DOWNLOAD_COMPLETE == intent.action) {
val cursor = manager.query(DownloadManager.Query().apply{ setFilterById(downloadId) })
if (cursor.moveToFirst()) {
val downloadStatus = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
val downloadLocalUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))
val downloadMimeType = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE))
if (downloadStatus == DownloadManager.STATUS_SUCCESSFUL && downloadLocalUri !== null) {
val viewIntent = Intent(Intent.ACTION_VIEW).apply {
this.setDataAndType(Uri.parse(downloadLocalUri), downloadMimeType)
this.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
if (viewIntent.resolveActivity(packageManager) !== null) {
startActivity(
Intent.createChooser(viewIntent, "Choose app")
)
} else {
Toast.makeText(context, "No app available that can open file", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(context, "Unable to download file", Toast.LENGTH_SHORT).show()
Log.w("onReceive", "failure reason ${cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_REASON))}, ${cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))}")
}
}
}
}
},
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
)
}

How to open a PDF from URL that uses authentication?

I have to open a PDF from a URL that requires an access token (The PDF is not publically available). The PDF should not be permanently stored on the device.
If the access token wouldn't be required, the solution would look like this:
val intent = Intent(Intent.ACTION_VIEW).apply { setDataAndType(Uri.parse(url), "application/pdf") }
startActivity(intent)
However, an access token is required and therefore this doesn't work.
I have tried downloading the file in the app and then opening the local copy of the file, like this:
val inputStream = /*get PDF as an InputStream*/
val file = File.createTempFile(
fileName,
".pdf",
context?.externalCacheDir
).apply { deleteOnExit() }
stream.use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
val intent = Intent(Intent.ACTION_VIEW).apply { setDataAndType(Uri.fromFile(file), "application/pdf") }
startActivity(intent)
but this gives me a android.os.FileUriExposedException with the message <myFilePath> exposed beyond app through Intent.getData().
I have also tried the same thing using context?.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS) and got the same result.
So far, the closest I got was like this:
val inputStream = /*get PDF as an InputStream*/
val file = File.createTempFile(
fileName,
".pdf",
context?.filesDir
).apply { deleteOnExit() }
stream.use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
val intent = Intent(Intent.ACTION_VIEW).apply { setDataAndType(Uri.parse(file.absolutePath), "application/pdf") }
startActivity(intent)
Doing it like this, my Samsung device offered me Samsung Notes and Microsoft Word to open the PDF and neither of them was actually able to do it. (It just opened these apps and they showed an error that they couldn't find the file they were supposed to open)
The installed PDF reader - the one that would normally open the PDF when using my two lines of code at the very top of this post - wasn't even listed.
So, how do I properly show this PDF?
Edit:
After finding this answer, I added a file Provider and now my code looks like this:
val inputStream = /*get PDF as an InputStream*/
val file = File.createTempFile(
fileName,
".pdf",
context?.getExternalFilesDir(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
Environment.DIRECTORY_DOCUMENTS
else
Environment.DIRECTORY_DOWNLOADS
).apply { deleteOnExit() }
stream.use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
val documentUri: Uri = FileProvider.getUriForFile(
requireContext(),
getString(R.string.file_provider_authority),
file
)
val intent = Intent(Intent.ACTION_VIEW).apply { setDataAndType(documentUri, "application/pdf") }
startActivity(intent)
Now the PDF can be opened properly. However the PDF is empty.
This is how I load the PDF to an InputStream:
interface DocumentsClient {
#GET("/api/something/pdf/{pdf_id}")
#Headers("Accept: application/pdf")
#Streaming
fun loadSomethingPDF(#Path("pdf_id") pdfId: Long): Call<ResponseBody>
}
fun loadSomethingPDF(accessToken: String?, pdfId: Long) =
createDocumentsClient(accessToken).loadSomethingPDF(pdfId)
private fun createDocumentsClient(accessToken: String?): DocumentsClient {
val okClientBuilder = OkHttpClient.Builder()
// add headers
okClientBuilder.addInterceptor { chain ->
val original = chain.request()
val requestBuilder = original.newBuilder()
if (accessToken != null) {
requestBuilder.header("Authorization", "Bearer $accessToken")
}
val request = requestBuilder.build()
chain.proceed(request)
}
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.client(okClientBuilder.build())
.build()
return retrofit.create(DocumentsClient::class.java)
}
loadSomethingPdf then gets called like this:
#Throws(IOException::class, IllegalStateException::class)
suspend fun loadSomethingPdf(accessToken: String?, pdfId: Long) = withContext(Dispatchers.IO) {
val call = remoteManager.loadSomethingPDF(accessToken, pdfId)
try {
val response = call.execute()
if (!response.isSuccessful) {
return#withContext null
}
return#withContext response.body()?.byteStream()
} catch (e: IOException) {
throw e
} catch (e: IllegalStateException) {
throw e
}
}
And that's where I get the inputStream from.
Ok, my problem was somewhere completely different.
I needed to grant Uri permissions to allow the other apps to read the Uri I am sending them.
The code just needed this:
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION

Kotlin how to properly use Android Intent to save file

I am currently trying to save a text file inside a fragment, but I can't get it to work:
Here is the method called when the user clicks the save button
private fun saveText(){
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*"
putExtra(Intent.EXTRA_TITLE, "text.txt")
}
startActivityForResult(intent, 1)
}
Here is the onActivityResult method:
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (requestCode == 1 && resultCode == Activity.RESULT_OK) {
try {
val path = resultData?.data?.path
Log.wtf("Path", filePath)
val writer: Writer = BufferedWriter(FileWriter(path))
writer.write("Example Text")
writer.close()
} catch (e: Exception){
e.printStackTrace()
}
}
}
I also have the permissions set in the manifest and the file itself is created, but nothing is written. Perhaps I'm writing to the file wrong?
The error thrown is FileNotFoundException, because its trying to use a file from /document when I'm selecting one from /downloads
Suggested solution which unfortunately doesn't work:
resultData?.data?.let {
requireActivity().contentResolver.openOutputStream(it).use { stream ->
stream!!.bufferedWriter().write("Example Text")
}
}
A Uri is not a file.
Replace:
val path = resultData?.data?.path
Log.wtf("Path", filePath)
val writer: Writer = BufferedWriter(FileWriter(path))
writer.write("Example Text")
writer.close()
with:
resultData?.data?.let { contentResolver.openOutputStream(it).use { stream ->
stream.writer().write("Example Text")
}
}

Categories

Resources