I am building an app that calls an activity to analyze a photo. once that activity starts it launches the camera or gallery depending on the value of "capture" or "gallery". the problem is:
I want to keep the activity orientation in portrait but the camera follows the phone orientation and after taking the photo it loses everything and starts the camera again OnResume again and again. if I held the phone vertically and captured the pic everything works fine and the pic appears in
Any changing of the rotation gets me error W/ImageView: Unable to open content: content://com.myProject.projecttwo.provider/external/Android/media/com.myProject.projecttwo/projectTwo/2021-07-31-17-59-19-4262257504715507656821.jpeg
import android.content.Context
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.ImageView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.FileProvider
import androidx.lifecycle.lifecycleScope
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
class PhotoAnalysis : AppCompatActivity() {
private var receivedUriKey: Uri? = null
private lateinit var outputDirectory: File
//private var selection: String? = null
private var selection: String? = "capture" /* later will get it from clicks*/
private lateinit var imageView: ImageView
private val pickerContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
if(uri != null) { receivedUriKey = uri}
}
private val capturePicture = registerForActivityResult(ActivityResultContracts.TakePicture()) {
if(it) {
receivedUriKey.let { uri ->
if( uri != null) {
receivedUriKey = uri
Log.d("Capture Pic", receivedUriKey.toString())
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_photo_analysis)
imageView = findViewById(R.id.result_image_view)
}
override fun onResume() {
super.onResume()
if( selection == "gallery" && receivedUriKey == null) {
pickerContent.launch("image/*")
} else if(selection == "capture" && receivedUriKey == null) {
Log.d("Capture Resume", receivedUriKey.toString())
takeImage()
}
if(receivedUriKey != null) {
Log.d("Capture Resume 2", receivedUriKey.toString())
imageView.setImageURI(receivedUriKey)
}
}
private fun takeImage() {
lifecycleScope.launchWhenStarted {
getTmpFileUri().let { uri ->
receivedUriKey = uri
capturePicture.launch(uri)
}
}
}
private fun getTmpFileUri(): Uri {
outputDirectory = getOutputDirectory(this)
val tmpFile = File.createTempFile(
SimpleDateFormat(FILENAME, Locale.ENGLISH).format(System.currentTimeMillis()), PHOTO_EXTENSION, outputDirectory).apply {
createNewFile()
deleteOnExit()
}
return FileProvider.getUriForFile(this, "${BuildConfig.APPLICATION_ID}.provider", tmpFile)
}
companion object {
private const val FILENAME = "yyyy-MM-dd-HH-mm-ss-SSS"
private const val PHOTO_EXTENSION = ".jpeg"
private fun getOutputDirectory(context: Context): File {
val appContext = context.applicationContext
val mediaDir = context.externalMediaDirs.firstOrNull()?.let {
File(it, appContext.resources.getString(R.string.app_name)).apply { mkdirs() } }
return if (mediaDir != null && mediaDir.exists())
mediaDir else appContext.filesDir
}
}
}
Related
I am getting the following error as show in the screenshot,please help me to solve the error related to the tensorflow lite.
[i was following this tutorial on youtube][1]
Iam not getting why the error is occurring as the code in the tutorial runs well.
thankyou
Below is the code where I am getting the following error.
package com.example.machineleaarningapp
import android.app.Activity
import android.content.ContentValues
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.example.machineleaarningapp.databinding.ActivityMainBinding
import com.example.machineleaarningapp.ml.Birdmodel2
import java.io.IOException
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var imageView: ImageView
private lateinit var button: Button
private lateinit var tvOutput: TextView
private val GALLERY_REQUEST_CODE = 123
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
imageView = binding.imageView
button = binding.btnCaptureImage
tvOutput = binding.tvOutput
val buttonLoad = binding.btnLoadImage
button.setOnClickListener {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED
) {
takePicturePreview.launch(null)
}
else {
requestPermission.launch(android.Manifest.permission.CAMERA)
}
}
buttonLoad.setOnClickListener {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED){
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
intent.type = "image/*"
val mimeTypes = arrayOf("image/jpeg","image/png","image/jpg")
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
onresult.launch(intent)
}else {
requestPermission.launch(android.Manifest.permission.READ_EXTERNAL_STORAGE)
}
}
//to redirct user to google search for the scientific name
tvOutput.setOnClickListener {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com/search?q=${tvOutput.text}"))
startActivity(intent)
}
// to download image when longPress on ImageView
imageView.setOnLongClickListener {
requestPermissionLauncher.launch(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
return#setOnLongClickListener true
}
}
//request camera permission
private val requestPermission = registerForActivityResult(ActivityResultContracts.RequestPermission()){granted->
if (granted){
takePicturePreview.launch(null)
}else {
Toast.makeText(this, "Permission Denied !! Try again", Toast.LENGTH_SHORT).show()
}
}
//launch camera and take picture
private val takePicturePreview = registerForActivityResult(ActivityResultContracts.TakePicturePreview()){bitmap->
if(bitmap != null){
imageView.setImageBitmap(bitmap)
outputGenerator(bitmap)
}
}
//to get image from gallery
private val onresult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){result->
Log.i("TAG", "This is the result: ${result.data} ${result.resultCode}")
onResultReceived(GALLERY_REQUEST_CODE,result)
}
private fun onResultReceived(requestCode: Int, result: ActivityResult?){
when(requestCode){
GALLERY_REQUEST_CODE ->{
if (result?.resultCode == Activity.RESULT_OK){
result.data?.data?.let{uri ->
Log.i("TAG", "onResultReceived: $uri")
val bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(uri))
imageView.setImageBitmap(bitmap)
outputGenerator(bitmap)
}
}else {
Log.e("TAG", "onActivityResult: error in selecting image")
}
}
}
}
private fun outputGenerator(bitmap: Bitmap){
//declearing tensor flow lite model variable
val birdsModel = Birdmodel2.newInstance(this)
// converting bitmap into tensor flow image
val newBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)
val tfimage = TensorImage.fromBitmap(newBitmap)
//process the image using trained model and sort it in descending order
val outputs = birdsModel.process(tfimage)
.probabilityAsCategoryList.apply {
sortByDescending { it.score }
}
//getting result having high probability
val highProbabilityOutput = outputs[0]
//setting ouput text
tvOutput.text = highProbabilityOutput.label
Log.i("TAG", "outputGenerator: $highProbabilityOutput")
}
// to download image to device
private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()){
isGranted: Boolean ->
if (isGranted){
AlertDialog.Builder(this).setTitle("Download Image?")
.setMessage("Do you want to download this image to your device?")
.setPositiveButton("Yes"){_, _ ->
val drawable:BitmapDrawable = imageView.drawable as BitmapDrawable
val bitmap = drawable.bitmap
downloadImage(bitmap)
}
.setNegativeButton("No") {dialog, _ ->
dialog.dismiss()
}
.show()
}else {
Toast.makeText(this, "Please allow permission to download image", Toast.LENGTH_LONG).show()
}
}
//fun that takes a bitmap and store to user's device
private fun downloadImage(mBitmap: Bitmap):Uri? {
val contentValues = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME,"Birds_Images"+ System.currentTimeMillis()/1000)
put(MediaStore.Images.Media.MIME_TYPE,"image/png")
}
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
if (uri != null){
contentResolver.insert(uri, contentValues)?.also {
contentResolver.openOutputStream(it).use { outputStream ->
if (!mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)){
throw IOException("Couldn't save the bitmap")
}
else{
Toast.makeText(applicationContext, "Image Saved", Toast.LENGTH_LONG).show()
}
}
return it
}
}
return null
}
}
```[These are the errors I am getting][2]
[1]: https://www.youtube.com/watch?v=hsSPb6V84zc&t=1034s
[2]: https://i.stack.imgur.com/GsmBW.png
Here I'm trying to upload an image from the local storage to the firebase storage.
I'm uploading the image using its URI
package com.example.demochat
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.storage.FirebaseStorage
import java.util.*
class RegisterActivity : AppCompatActivity() {
private lateinit var username: EditText
private lateinit var email: EditText
private lateinit var password: EditText
private lateinit var register: Button
private lateinit var haveAccount: TextView
private lateinit var imageInsert: Button
private lateinit var imageView: ImageView
private val tag: String = "RegisterActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_register)
username = findViewById(R.id.editTextUsername)
email = findViewById(R.id.editTextTextEmailAddress)
password = findViewById(R.id.editTextTextPassword)
register = findViewById(R.id.buttonRegister)
haveAccount = findViewById(R.id.textViewAlready_have_an_account)
imageInsert = findViewById(R.id.buttonInsertImage)
imageView = findViewById(R.id.imageViewImageInsert)
imageInsert.setOnClickListener {
selectImage()
}
register.setOnClickListener {
performRegister()
}
haveAccount.setOnClickListener {
val intent = Intent(this#RegisterActivity, LoginActivity::class.java)
startActivity(intent)
}
}
private var selectedPhotoUri: Uri? = null
private fun selectImage() {
Log.d(tag, "clicked image button")
val intent = Intent()
intent.type = "image/*"
intent.action = Intent.ACTION_GET_CONTENT
startActivityForResult(intent, 100)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 100 && resultCode == RESULT_OK && data != null && data.data != null) {
Toast.makeText(this#RegisterActivity, "clicked image selected", Toast.LENGTH_SHORT)
.show()
val selectedPhotoUri = data.data
Toast.makeText(this#RegisterActivity, "$selectedPhotoUri", Toast.LENGTH_SHORT).show()
imageView.setImageURI(selectedPhotoUri)
}
}
private fun performRegister() {
if (email.text.isEmpty() || password.text.isEmpty()) {
Toast.makeText(this, "Fill the above details", Toast.LENGTH_SHORT).show()
return
}
FirebaseAuth.getInstance()
.createUserWithEmailAndPassword(email.text.toString(), password.text.toString())
.addOnCompleteListener {
if (!it.isSuccessful) return#addOnCompleteListener
Log.d(tag, "uid = ${it.result?.user?.uid}")
uploadImageToFirebase()
}
.addOnFailureListener {
Toast.makeText(this, "${it.message}", Toast.LENGTH_SHORT).show()
Log.d(tag, "${it.message}")
}
}
private fun uploadImageToFirebase() {
if (selectedPhotoUri == null) return
val fileName = UUID.randomUUID().toString() + ".jpg"
val refStorage = FirebaseStorage.getInstance().reference.child("/images/$fileName")
refStorage.putFile(selectedPhotoUri!!)
.addOnSuccessListener {
Log.d(tag, "image uploaded")
}
.addOnFailureListener {
Log.d("RegisterActivity", "${it.message}")
}
}
}
following is the rules for the firebase stroage
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}
}
}
firebase authentication part is working fine, users are added successfully. But I'm unable to upload an image. I have included internet permissions in the manifest file.
And I'm not getting any error message
So, please help
Here:
val selectedPhotoUri = data.data
you are not reassigning the global property selectedPhotoUri, but creating a new one.
Then, here:
if (selectedPhotoUri == null) return
you are checking with the global property which is always null.
I have find the following code from https://github.com/blink22/react-native-html-to-pdf/blob/master/android/src/main/java/android/print/PdfConverter.java converted in Kotlin:
import android.content.Context
import android.os.Build
import android.os.Handler
import android.os.ParcelFileDescriptor
import android.print.PrintAttributes.Resolution
import android.print.PrintDocumentAdapter.LayoutResultCallback
import android.print.PrintDocumentAdapter.WriteResultCallback
import android.util.Log
import android.webkit.WebView
import android.webkit.WebViewClient
import java.io.File
/**
* Converts HTML to PDF.
*
*
* Can convert only one task at a time, any requests to do more conversions before
* ending the current task are ignored.
*/
class PdfConverter private constructor() : Runnable {
private var mContext: Context? = null
private var mHtmlString: String? = null
private var mPdfFile: File? = null
private var mPdfPrintAttrs: PrintAttributes? = null
private var mIsCurrentlyConverting = false
private var mWebView: WebView? = null
private var done: Boolean = false
override fun run() {
mWebView = WebView(mContext as Context)
mWebView!!.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) throw RuntimeException(
"call requires API level 19"
) else {
val documentAdapter =
mWebView!!.createPrintDocumentAdapter()
documentAdapter.onLayout(
null,
pdfPrintAttrs,
null,
object : LayoutResultCallback() {},
null
)
documentAdapter.onWrite(
arrayOf(PageRange.ALL_PAGES),
outputFileDescriptor,
null,
object : WriteResultCallback() {
override fun onWriteFinished(pages: Array<PageRange>) {
destroy()
done = true
}
})
}
Log.d("end of onpagefinished()", "end of onpagefinished()")
}
}
mWebView!!.loadData(mHtmlString, "text/HTML", "UTF-8")
Log.d("end of run()", "end of run()")
}
var pdfPrintAttrs: PrintAttributes?
get() = if (mPdfPrintAttrs != null) mPdfPrintAttrs else defaultPrintAttrs
set(printAttrs) {
mPdfPrintAttrs = printAttrs
}
fun convert(
context: Context?,
htmlString: String?,
file: File?
) {
requireNotNull(context) { "context can't be null" }
requireNotNull(htmlString) { "htmlString can't be null" }
requireNotNull(file) { "file can't be null" }
if (mIsCurrentlyConverting) return
mContext = context
mHtmlString = htmlString
mPdfFile = file
mIsCurrentlyConverting = true
runOnUiThread(this)
Log.d("end of convert()","end of convert()")
}
private val outputFileDescriptor: ParcelFileDescriptor?
private get() {
try {
mPdfFile!!.createNewFile()
Log.d("outputfiledescriptor","the file has been created")
return ParcelFileDescriptor.open(
mPdfFile,
ParcelFileDescriptor.MODE_TRUNCATE or ParcelFileDescriptor.MODE_READ_WRITE
)
} catch (e: Exception) {
Log.d(TAG, "Failed to open ParcelFileDescriptor", e)
}
return null
}
private val defaultPrintAttrs: PrintAttributes?
private get() = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) null else PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.NA_GOVT_LETTER)
.setResolution(Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
.build()
private fun runOnUiThread(runnable: Runnable) {
val handler = Handler(mContext!!.mainLooper)
handler.post(this)
}
private fun destroy() {
mContext = null
mHtmlString = null
mPdfFile = null
mPdfPrintAttrs = null
mIsCurrentlyConverting = false
mWebView = null
Log.d("end of destroy()","end of destroy()")
}
companion object {
private const val TAG = "PdfConverter"
private var sInstance: PdfConverter? = null
#get:Synchronized
val instance: PdfConverter?
get() {
if (sInstance == null) sInstance =
PdfConverter()
return sInstance
}
}
}
I want the execution to wait for the onWriteFinished before go back to runOnUiThread. Also I want the main Thread to execute run. So I tried to make it happen with the following code using coroutines :
package android.print
import kotlinx.coroutines.runBlocking
import android.content.Context
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.os.ParcelFileDescriptor
import android.print.PrintAttributes.Resolution
import android.print.PrintDocumentAdapter.LayoutResultCallback
import android.print.PrintDocumentAdapter.WriteResultCallback
import android.util.Log
import android.webkit.WebView
import android.webkit.WebViewClient
import java.io.File
/**
* Converts HTML to PDF.
*
*
* Can convert only one task at a time, any requests to do more conversions before
* ending the current task are ignored.
*/
class PdfConverter2 {
private var mContext: Context? = null
private var mHtmlString: String? = null
private var mPdfFile: File? = null
private var mPdfPrintAttrs: PrintAttributes? = null
private var mIsCurrentlyConverting = false
private var mWebView: WebView? = null
private var done: Boolean = false
suspend fun run() {
Log.d("run()","is this the main thread :"+(Looper.myLooper() == Looper.getMainLooper()))
mWebView = WebView(mContext as Context)
mWebView!!.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) throw RuntimeException(
"call requires API level 19"
) else {
val documentAdapter =
mWebView!!.createPrintDocumentAdapter()
documentAdapter.onLayout(
null,
pdfPrintAttrs,
null,
object : LayoutResultCallback() {},
null
)
documentAdapter.onWrite(
arrayOf(PageRange.ALL_PAGES),
outputFileDescriptor,
null,
object : WriteResultCallback() {
override fun onWriteFinished(pages: Array<PageRange>) {
destroy()
done = true
}
})
}
Log.d("end of onpagefinished()", "end of onpagefinished()")
}
}
mWebView!!.loadData(mHtmlString, "text/HTML", "UTF-8")
Log.d("end of run()", "end of run()")
}
var pdfPrintAttrs: PrintAttributes?
get() = if (mPdfPrintAttrs != null) mPdfPrintAttrs else defaultPrintAttrs
set(printAttrs) {
mPdfPrintAttrs = printAttrs
}
fun convert(
context: Context?,
htmlString: String?,
file: File?
) {
requireNotNull(context) { "context can't be null" }
requireNotNull(htmlString) { "htmlString can't be null" }
requireNotNull(file) { "file can't be null" }
if (mIsCurrentlyConverting) return
mContext = context
mHtmlString = htmlString
mPdfFile = file
mIsCurrentlyConverting = true
runOnUiThread()
Log.d("end of convert()","end of convert()")
}
private val outputFileDescriptor: ParcelFileDescriptor?
private get() {
try {
mPdfFile!!.createNewFile()
Log.d("outputfiledescriptor","the file has been created")
return ParcelFileDescriptor.open(
mPdfFile,
ParcelFileDescriptor.MODE_TRUNCATE or ParcelFileDescriptor.MODE_READ_WRITE
)
} catch (e: Exception) {
Log.d(TAG, "Failed to open ParcelFileDescriptor", e)
}
return null
}
private val defaultPrintAttrs: PrintAttributes?
private get() = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) null else PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.NA_GOVT_LETTER)
.setResolution(Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
.build()
private fun runOnUiThread() {
runBlocking {
run()
while(!done){
}
}
}
private fun destroy() {
mContext = null
mHtmlString = null
mPdfFile = null
mPdfPrintAttrs = null
mIsCurrentlyConverting = false
mWebView = null
Log.d("end of destroy()","end of destroy()")
}
companion object {
private const val TAG = "PdfConverter2"
private var sInstance: PdfConverter2? = null
#get:Synchronized
val instance: PdfConverter2?
get() {
if (sInstance == null) sInstance =
PdfConverter2()
return sInstance
}
}
}
Also there is a function in another file that calls the PdfConverter and it calls the PdfConverter.
fun createPdfFromHtml(htmlstring: String) {
val converter: PdfConverter? = PdfConverter.instance
val file = File(
Environment.getExternalStorageDirectory().getPath().toString() + "/" + name_of_directory_of_pdfs + "/",
nameofpdf
)
converter?.convert(m_context, htmlstring, file)
mFilepdf = file
}
What I want is the code execution stops at the 'converter?.convert(m_context, htmlstring, file)' and wait for 'onWriteFinished' of PdfConverter to be executed and then continue. The other senario I thought was that the execution stops at 'runonUiThread' and wait for ''onWriteFinished' again to be executed.
After the answer of #m0skit0 I change the last code :
fun createPdfFromHtml(htmlstring: String) {
val file = File(
Environment.getExternalStorageDirectory().path.toString() + "/" + name_of_directory_of_pdfs + "/",
nameofpdf
)
var converter = PdfConverter3.from(m_context)
GlobalScope.launch(Dispatchers.IO) {// I TRY ALSO Dispatchers.Main
converter.convert(htmlstring, file)
}
mFilepdf = file
Log.d("mich/createPDfFromHtml", "at the end of createPdfFromHtml, is this the main thread ? "+ (Looper.myLooper() == Looper.getMainLooper()))
}
But the thing is existing again.
Here's my take on translating that class to Kotlin using coroutines
package org.m0skit0.android.testapp
import android.annotation.TargetApi
import android.content.Context
import android.os.ParcelFileDescriptor
import android.print.PageRange
import android.print.PrintAttributes
import android.print.PrintDocumentAdapter
import android.webkit.WebView
import android.webkit.WebViewClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
#TargetApi(19)
class PdfConverter private constructor(private val context: Context) {
private val defaultPrintAttributes: PrintAttributes by lazy {
PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.NA_GOVT_LETTER)
.setResolution(PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
.build()
}
private var printAttributes: PrintAttributes? = null
fun printAttributes(printAttributes: PrintAttributes): PdfConverter = apply {
this.printAttributes = printAttributes
}
suspend fun convert(htmlString: String, pdfFile: File) {
withContext(Dispatchers.Main) {
suspendCoroutine<Unit> { continuation ->
WebView(context).apply {
webViewClient = WebViewClientImpl(pdfFile, continuation)
}.loadData(htmlString, "text/html", "UTF-8")
}
}
}
private fun File.outputFileDescriptor(): ParcelFileDescriptor? =
try {
createNewFile()
ParcelFileDescriptor.open(this, ParcelFileDescriptor.MODE_TRUNCATE or ParcelFileDescriptor.MODE_READ_WRITE)
} catch (e: Exception) {
null
}
companion object {
fun from(context: Context): PdfConverter = PdfConverter(context)
}
private inner class WebViewClientImpl(private val file: File, private val continuation: Continuation<Unit>) : WebViewClient() {
override fun onPageFinished(webView: WebView, url: String) {
webView.createPrintDocumentAdapter()?.run {
onLayout(
null,
printAttributes ?: defaultPrintAttributes,
null,
object : PrintDocumentAdapter.LayoutResultCallback() {},
null
)
onWrite(
arrayOf(PageRange.ALL_PAGES),
file.outputFileDescriptor(),
null,
object : PrintDocumentAdapter.WriteResultCallback() {
override fun onWriteCancelled() {
super.onWriteCancelled()
continuation.resume(Unit)
}
override fun onWriteFailed(error: CharSequence?) {
super.onWriteFailed(error)
continuation.resumeWithException(Exception(error.toString()))
}
override fun onWriteFinished(pages: Array<out PageRange>?) {
super.onWriteFinished(pages)
continuation.resume(Unit)
}
}
)
}
}
}
}
if I understood you correctly, you want run to be executed on the main thread. In order to achieve this, instead of making run a suspend function, you could let the function launch a coroutine with the Dispatchers.Main scope.
I would like to create and store new users also update the existing users in the following code
What code needs to be added to strore new users in a SQLitedatabase
I have a sqllitehelper class
which has adduser,updateuser,and readuser methods
From what i understand ,the signinfragment activity stores the instance of the logged in user and
if the instance exists then its loaded.When we logout we basically have to make a new user and we login
i would like to create,store,update users using an SQLite database.
package com.google.samples.apps.topeka.fragment
import android.annotation.TargetApi
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.database.sqlite.SQLiteDatabase
import android.os.Build
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
import android.support.v4.app.ActivityOptionsCompat
import android.support.v4.app.Fragment
import android.support.v4.util.Pair
import android.support.v4.view.ViewCompat
import android.support.v4.view.animation.FastOutSlowInInterpolator
import android.text.Editable
import android.text.TextWatcher
import android.transition.Transition
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.EditText
import android.widget.GridView
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import com.google.samples.apps.topeka.activity.SignInActivity
import com.google.samples.apps.topeka.adapter.AvatarAdapter
import com.google.samples.apps.topeka.base.R
import com.google.samples.apps.topeka.helper.ActivityLaunchHelper
import com.google.samples.apps.topeka.helper.ApiLevelHelper
import com.google.samples.apps.topeka.helper.DefaultLogin
import com.google.samples.apps.topeka.helper.TAG
import com.google.samples.apps.topeka.helper.TransitionHelper
import com.google.samples.apps.topeka.helper.isLoggedIn
import com.google.samples.apps.topeka.helper.login
import com.google.samples.apps.topeka.helper.onLayoutChange
import com.google.samples.apps.topeka.helper.onSmartLockResult
import com.google.samples.apps.topeka.model.Avatar
import com.google.samples.apps.topeka.model.Player
import com.google.samples.apps.topeka.persistence.PPlayer
import com.google.samples.apps.topeka.widget.TextWatcherAdapter
import com.google.samples.apps.topeka.widget.TransitionListenerAdapter
import com.google.samples.apps.topeka.persistence.TopekaDatabaseHelper;
/**
* Enable selection of an [Avatar] and user name.
*/
class SignInFragment : Fragment() {
private var firstNameView: EditText? = null
private var lastInitialView: EditText? = null
private var doneFab: FloatingActionButton? = null
private var avatarGrid: GridView? = null
private var firstName = ""
private var lastInitial= ""
private var avatar = ""
private val edit by lazy { arguments?.getBoolean(ARG_EDIT, false) ?: false }
private var selectedAvatarView: View? = null
private var player: Player? = null
private var selectedAvatar: Avatar? = null
var a = getContext()
override fun onCreate(savedInstanceState: Bundle?) {
var a = context
val resources = context!!.resources
var ss = TopekaDatabaseHelper(requireActivity())
val newValues = ContentValues().apply {
// Sets the values of each column and inserts the value.
// The arguments to the "put"
// method are "column name" and "value"
}
if (savedInstanceState != null) {
val avatarIndex = savedInstanceState.getInt(KEY_SELECTED_AVATAR_INDEX)
if (avatarIndex != GridView.INVALID_POSITION) {
selectedAvatar = Avatar.values()[avatarIndex]
}
}
activity?.run {
if (isLoggedIn()) {
navigateToCategoryActivity()
Toast.makeText(requireContext(),"old", LENGTH_LONG)
} else {
maketext("new player")
login.loginPlayer(this, ::onSuccessfulLogin)
}
}
super.onCreate(savedInstanceState)
}
/**
* Called when logged in successfully.
*/
private fun onSuccessfulLogin(player: Player) {
if (login != DefaultLogin) return
this.player = player
if (edit) {
with(player) {
firstNameView?.setText(player.firstName)
lastInitialView?.run {
setText(player.lastInitial)
requestFocus()
setSelection(length())
var db = TopekaDatabaseHelper(context)
db.adduser(player.firstName,player.lastInitial)
maketext("saved new")
}
this#SignInFragment.player = player.also {
if (activity != null)
login.savePlayer(activity!!, this, { selectAvatar(it.avatar!!) })
maketext("saved new")
}
}
} else {
Toast.makeText(requireContext(),"new", LENGTH_LONG)
navigateToCategoryActivity()
}
}
private fun maketext(ss:String){
Toast.makeText(requireContext(),ss,LENGTH_LONG)
}
private fun navigateToCategoryActivity() {
activity?.run {
ActivityLaunchHelper.launchCategorySelection(this)
supportFinishAfterTransition()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
activity?.onSmartLockResult(
requestCode,
resultCode,
data,
success = {
player = it
initContents()
navigateToCategoryActivity()
},
failure = {
activity?.run {
login.loginPlayer(this, ::onSuccessfulLogin)
}
}
)
super.onActivityResult(requestCode, resultCode, data)
}
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val contentView = inflater.inflate(R.layout.fragment_sign_in, container, false)
contentView.onLayoutChange {
avatarGrid?.apply {
adapter = AvatarAdapter(activity!!)
onItemClickListener = AdapterView.OnItemClickListener { _, view, position, _ ->
selectedAvatarView = view
selectedAvatar = Avatar.values()[position]
// showing the floating action button if input data is valid
showFab()
}
numColumns = calculateSpanCount()
selectedAvatar?.run { selectAvatar(this) }
}
}
return contentView
}
/**
* Calculates spans for avatars dynamically.
* #return The recommended amount of columns.
*/
private fun calculateSpanCount(): Int {
val avatarSize = resources.getDimensionPixelSize(R.dimen.size_fab)
val avatarPadding = resources.getDimensionPixelSize(R.dimen.spacing_double)
return (avatarGrid?.width ?: 0) / (avatarSize + avatarPadding)
}
override fun onSaveInstanceState(outState: Bundle) {
outState.putInt(KEY_SELECTED_AVATAR_INDEX, (avatarGrid?.checkedItemPosition ?: 0))
super.onSaveInstanceState(outState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
firstNameView = view.findViewById<EditText>(R.id.first_name)
lastInitialView = view.findViewById<EditText>(R.id.last_initial)
doneFab = view.findViewById<FloatingActionButton>(R.id.done)
avatarGrid = view.findViewById<GridView>(R.id.avatars)
if (edit || (player != null && player!!.valid())) {
initContentViews()
initContents()
}
hideEmptyView()
super.onViewCreated(view, savedInstanceState)
}
private fun hideEmptyView() {
view?.run {
findViewById<View>(R.id.empty).visibility = View.GONE
findViewById<View>(R.id.content).visibility = View.VISIBLE
}
}
private fun initContentViews() {
val textWatcher = object : TextWatcher by TextWatcherAdapter {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
// hiding the floating action button if text is empty
if (s.isEmpty()) {
doneFab?.hide()
}
}
// showing the floating action button if avatar is selected and input data is valid
override fun afterTextChanged(s: Editable) {
if (isAvatarSelected() && isInputDataValid()) doneFab?.show()
}
}
firstNameView?.addTextChangedListener(textWatcher)
lastInitialView?.addTextChangedListener(textWatcher)
doneFab?.setOnClickListener {
if (it.id == R.id.done) {
val first = firstNameView?.text?.toString()
val last = lastInitialView?.text?.toString()
activity?.run {
val toSave = player?.apply {
// either update the existing player object
firstName = first
lastInitial = last
avatar = selectedAvatar
} ?: Player(first, last, selectedAvatar) /* or create a new one */
login.savePlayer(this, toSave) {
Toast.makeText(this,"done",LENGTH_LONG)
Log.d(TAG, "Saving login info successful.")
}
}
}
removeDoneFab {
performSignInWithTransition(selectedAvatarView
?: avatarGrid?.getChildAt(selectedAvatar!!.ordinal))
}
}
}
private fun removeDoneFab(endAction: () -> Unit) {
ViewCompat.animate(doneFab)
.scaleX(0f)
.scaleY(0f)
.setInterpolator(FastOutSlowInInterpolator())
.withEndAction(endAction)
.start()
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private fun performSignInWithTransition(v: View? = null) {
if (v == null || ApiLevelHelper.isLowerThan(Build.VERSION_CODES.LOLLIPOP)) {
// Don't run a transition if the passed view is null
activity?.run {
navigateToCategoryActivity()
}
return
}
if (ApiLevelHelper.isAtLeast(Build.VERSION_CODES.LOLLIPOP)) {
activity?.run {
window.sharedElementExitTransition.addListener(object :
Transition.TransitionListener by TransitionListenerAdapter {
override fun onTransitionEnd(transition: Transition) {
finish()
}
})
val pairs = TransitionHelper.createSafeTransitionParticipants(this, true,
Pair(v, getString(R.string.transition_avatar)))
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(this, *pairs)
ActivityLaunchHelper.launchCategorySelection(this, options)
}
}
}
private fun initContents() {
player?.run {
valid().let {
firstNameView?.setText(firstName)
lastInitialView?.setText(lastInitial)
avatar?.run { selectAvatar(this) }
}
}
}
private fun isAvatarSelected() = selectedAvatarView != null || selectedAvatar != null
private fun selectAvatar(avatar: Avatar) {
selectedAvatar = avatar
avatarGrid?.run {
requestFocusFromTouch()
setItemChecked(avatar.ordinal, true)
}
showFab()
}
private fun showFab() {
if (isInputDataValid()) doneFab?.show()
}
private fun isInputDataValid() =
firstNameView?.text?.isNotEmpty() == true &&
lastInitialView?.text?.isNotEmpty() == true &&
selectedAvatar != null
companion object {
private const val ARG_EDIT = "EDIT"
private const val KEY_SELECTED_AVATAR_INDEX = "selectedAvatarIndex"
fun newInstance(edit: Boolean = false): SignInFragment {
return SignInFragment().apply {
arguments = Bundle().apply {
putBoolean(ARG_EDIT, edit)
}
}
}
}
}
I have recently tried to use ExoPlayer from google in my android project. Exoplayer is keep playing video even I have call all the necessary stuff & player is not being released.It appear releasePlayer() doesn't works at all. Video keep playing even if i move to other activity. I have tried all the solutions available on stack or codelabs sites etc. Which makes me to put this question here on stack.
package com.android.maccino.ui
import android.content.Intent
import android.media.MediaPlayer
import android.net.Uri
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.android.maccino.R
import com.android.maccino.models.SponsorModel
import com.android.maccino.utils.AppConstants
import com.android.maccino.utils.AppUtils
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.source.ExtractorMediaSource
import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import com.kaopiz.kprogresshud.KProgressHUD
import com.orhanobut.logger.Logger
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_dashboard.*
import java.util.*
class DashboardActivity : AppCompatActivity() {
lateinit var sponsorModel: SponsorModel
lateinit var mDatabaseRef: DatabaseReference
lateinit var kProgressHud: KProgressHUD
lateinit var mSponsorList: MutableList<SponsorModel>
lateinit var player: SimpleExoPlayer
var currentWindow: Int = 0
var playbackPosition: Long = 0;
var wasPlayingBefore: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dashboard)
mDatabaseRef = FirebaseDatabase.getInstance().reference
sponsorModel = SponsorModel()
mSponsorList = ArrayList<SponsorModel>()
Logger.d(FirebaseAuth.getInstance().currentUser!!.uid)
if (intent != null &&
intent.getSerializableExtra(AppConstants.INTENT_SPONSOR_MODEL) != null) {
sponsorModel = intent.getSerializableExtra(AppConstants.INTENT_SPONSOR_MODEL) as SponsorModel
setValues()
}
btnAnswer1.setOnClickListener {
if (sponsorModel.answers.get(0).getValue(btnAnswer1.text.toString()) == true) {
makeAnsweredSponsorEntry()
startActivity(Intent(this#DashboardActivity, CorrectAnswer::class.java).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).putExtra(AppConstants.INTENT_SPONSOR_MODEL, sponsorModel))
this.finish()
} else if (sponsorModel.answers.get(0).getValue(btnAnswer1.text.toString()) == false) {
startActivity(Intent(this#DashboardActivity, WrongAnswer::class.java))
}
}
btnAnswer2.setOnClickListener {
if (sponsorModel.answers.get(1).getValue(btnAnswer2.text.toString()) == true) {
makeAnsweredSponsorEntry()
startActivity(Intent(this#DashboardActivity, CorrectAnswer::class.java).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).putExtra(AppConstants.INTENT_SPONSOR_MODEL, sponsorModel))
this.finish()
} else if (sponsorModel.answers.get(1).getValue(btnAnswer2.text.toString()) == false) {
startActivity(Intent(this#DashboardActivity, WrongAnswer::class.java))
}
}
btnAnswer3.setOnClickListener {
if (sponsorModel.answers.get(2).getValue(btnAnswer3.text.toString()) == true) {
makeAnsweredSponsorEntry()
startActivity(Intent(this#DashboardActivity, CorrectAnswer::class.java).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).putExtra(AppConstants.INTENT_SPONSOR_MODEL, sponsorModel))
this.finish()
} else if (sponsorModel.answers.get(2).getValue(btnAnswer3.text.toString()) == false) {
startActivity(Intent(this#DashboardActivity, WrongAnswer::class.java))
}
}
tvSearch.setOnClickListener { startActivity(Intent(this#DashboardActivity, SearchActivity::class.java).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)) }
}
override fun onResume() {
super.onResume()
initializePlayer()
}
override fun onPause() {
super.onPause()
if (Util.SDK_INT <= 23) {
releasePlayer();
}
}
private fun setValues() {
try {
tvQuestion.setText(sponsorModel.question)
sponsorModel.answers.get(0).keys.forEach { key: String ->
btnAnswer1.setText(key)
}
sponsorModel.answers.get(1).keys.forEach { key: String ->
btnAnswer2.setText(key)
}
sponsorModel.answers.get(2).keys.forEach { key: String ->
btnAnswer3.setText(key)
}
tvSponsorName.setText(sponsorModel.sponsor_name)
Picasso.with(this#DashboardActivity).load(sponsorModel.logo).into(ivSponsorLogo)
ivFlag.setOnClickListener { startActivity(Intent(Intent.ACTION_VIEW).setDataAndType(Uri.parse(sponsorModel.video_url), "video/*")) }
initializePlayer()
} catch (e: Exception) {
e.printStackTrace()
}
}
//Player implementation
private fun initializePlayer() {
try {
player = ExoPlayerFactory.newSimpleInstance(
DefaultRenderersFactory(this#DashboardActivity),
DefaultTrackSelector(), DefaultLoadControl())
player.repeatMode = Player.REPEAT_MODE_ALL
playerView.player = player
playerView.hideController()
player.setPlayWhenReady(true)
player.seekTo(currentWindow, playbackPosition);
val uri = Uri.parse(sponsorModel.video_url)
val mediaSource = buildMediaSource(uri)
player.prepare(mediaSource, true, false)
wasPlayingBefore = true
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun buildMediaSource(uri: Uri): MediaSource {
return ExtractorMediaSource.Factory(
DefaultHttpDataSourceFactory("exoplayer-maccino")).createMediaSource(uri)
}
private fun releasePlayer() {
if (player != null) {
playbackPosition = player.currentPosition
currentWindow = player.currentWindowIndex
player.playWhenReady = false
player.setRepeatMode(Player.REPEAT_MODE_OFF)
player.stop()
player.release()
playerView.player = null
// player = null
}
}
}