Android not opening camera using zxing - android

I'm trying to make the basic ZXing functionality to scan qr codes using their basic instructions, but my camera does not open it just goes to the blank ScanActivity.
I've already added the "implementation" on module app dependency
implementation 'me.dm7.barcodescanner:zxing:1.9'
and permission on AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA"/>
I've also manually allowed its permission on the settings of the android phone i'm testing it on
My main activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tvResult = tvresult
btn.setOnClickListener {
val intent = Intent(this#MainActivity, ScanActivity::class.java)
startActivity(intent)
}
}
companion object {
var tvResult: TextView? = null
}
}
ScanActivity Class
class ScanActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
private var mScannerView: ZXingScannerView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mScannerView = ZXingScannerView(this)
setContentView(R.layout.activity_scan)
mScannerView!!.setResultHandler(this) // Register ourselves as a handler for scan results.
}
public override fun onResume() {
super.onResume()
mScannerView!!.setResultHandler(this) // Register ourselves as a handler for scan results.
mScannerView!!.startCamera() // Start camera on resume
}
public override fun onPause() {
super.onPause()
mScannerView!!.stopCamera() // Stop camera on pause
}
override fun handleResult(rawResult: Result) {
// Do something with the result here
// Log.v("tag", rawResult.getText()); // Prints scan results
// Log.v("tag", rawResult.getBarcodeFormat().toString()); // Prints the scan format (qrcode, pdf417 etc.)
MainActivity.tvResult!!.setText(rawResult.text)
onBackPressed()
// If you would like to resume scanning, call this method below:
//mScannerView.resumeCameraPreview(this);
}}
after i click on the Scan barcode button it just goes to this
(im expecting the camera will open because of the startCamera()

I had a similar issue, it was permission related.
Try adding the following within the onCreate(..)
if (ContextCompat.checkSelfPermission(this#MainActivity, Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this#MainActivity, arrayOf(Manifest.permission.CAMERA), 123)
}

Late answer, by the way if someone else has this problem, you forgot to add mScannerView in your Layout

Related

Camera freezes after scanning QR code with Zxing library

I implemented QR code scanner with result handler. It is scanning well. But, after first scanning is complete I show a popup. When I close the popup, camera gets stuck.
I tried using resume camera but it doesn't work.
Here is some of my code
private fun startCamera() {
binding.scanner.setResultHandler(this)
binding.scanner.setAspectTolerance(0.5f)
binding.scanner.startCamera()
binding.scanner.resumeCameraPreview(this)
}
override fun onResume() {
super.onResume()
mScannerView?.setResultHandler(this)
}
override fun onStart() {
super.onStart()
startCamera()
}
override fun handleResult(rawResult: Result?) {
val result = rawResult?.text ?: return
liveMasterclass?.id?.let {
viewModel.getAttendance(it, result)
mScannerView?.resumeCameraPreview(this)
}
}

How to launch implicit intent from a QR Code result?

I have built a QR scanning application (written in Kotlin, for Android). It scans for a QR code and then returns the URL after its scanned like so.
However, I wish to take it a step further and actually launch the return value of the QR code into a search engine of an internet application and have it display the results of what the QR code had intended. How would I get the application to get the returned URL and redirect the user to the intended place?
Here is my MainActivity.kt for reference:
class MainActivity : AppCompatActivity() {
private lateinit var codeScanner: CodeScanner
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val scannerView = findViewById<CodeScannerView>(R.id.scanner_view)
codeScanner = CodeScanner(this, scannerView)
codeScanner.camera = CodeScanner.CAMERA_BACK
codeScanner.formats = CodeScanner.ALL_FORMATS
codeScanner.autoFocusMode = AutoFocusMode.SAFE
codeScanner.scanMode = ScanMode.SINGLE
codeScanner.isAutoFocusEnabled = true
codeScanner.isFlashEnabled = false
codeScanner.decodeCallback = DecodeCallback {
runOnUiThread {
Toast.makeText(this, "Scan result: ${it.text}", Toast.LENGTH_LONG).show()}
}
scannerView.setOnClickListener {
codeScanner.startPreview()
}
}
override fun onResume() {
super.onResume()
codeScanner.startPreview()
}
override fun onPause() {
codeScanner.releaseResources()
super.onPause()
}
}
I used this answer to build a searchWeb function within my MainActivity.kt class like so;
fun searchWeb(query: String) {
val url = "http://www.google.com"
val intent = Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url))
startActivity(intent)
}
I then called the function within my codeScanner.decodeCallback like so;
codeScanner.decodeCallback = DecodeCallback {
runOnUiThread {
Toast.makeText(this, "Scan result: ${it.text}", Toast.LENGTH_LONG).show()
}
searchWeb(it.text)
}
After doing this, the implicit intent was launched and the QR application launched the internet browser.

Play music automatically when starting app

I was wondering how to make the music play automatically when starting the app and how to make it stop playing in the background when pressing the home button. Right now, it starts and stops by pressing the toggle button. I was also wondering if its possible to automatically switch to other music when going to another activity?
MainActivity.kt
private lateinit var player: MediaPlayer
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val secondActivity = findViewById<Button>(R.id.secondActivity)
secondActivity.setOnClickListener {
val intent = Intent(this, MainActivity2::class.java)
startActivity(intent)
}
val toggle: ToggleButton = findViewById(R.id.toggleButton)
toggle.setOnCheckedChangeListener { _, isChecked ->
val svc = Intent(this, MusicService::class.java)
if (isChecked) {
startService(svc)
} else {
stopService(svc)
}
}
}
MusicService.kt
class MusicService : Service() {
private lateinit var player: MediaPlayer
override fun onBind(intent: Intent?): IBinder? {
TODO("Return the communication channel to the service.")
return null
}
override fun onCreate() {
super.onCreate()
player = MediaPlayer.create(this, R.raw.music)
player.setLooping(true)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
player.start()
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
player.stop()
}
}
Depending on your specific requirements, you should or shouldn't use a MediaService as part of your solution.
To be more clear, a Service should only be used if you want the audio to keep going whenever you're outside the app. This solution will usually be accompanied by a media Notification which you should populate with controls, image assets, etc. (Think of Spotify or SoundCloud) If this is the solution you're looking for, take a look at this doc page from Google and follow it through. Beware that this is a longer and tougher process to maintain.
On the other hand, if all you want to do is play music/sounds while your user is inside your app, then a simple
private lateinit var localMedia: MediaPlayer
override fun onCreate() {
...
localMedia = MediaPlayer.create(context, R.raw.your_audio_file)
}
override fun onResume() {
...
localMedia.start()
}
override fun onPause() {
...
localMedia.release()
}
Furthermore, if you want different audio files to be played on different Activities/Fragments, you might want to abstract the code I provided above into it's own Manager class or so and access it the same but changing the specific .mp3 file (or whatever format) as you see fit.
EDIT:
For a Manager class, you'll have to create your own functions and handle the MediaPlayer inside of it
private class MediaPlayerManager(private val context: Context) {
private lateinit var mediaPlayer: MediaPlayer
fun setupPlayer() {
mediaPlayer = MediaPlayer.create(context, R.raw.your_audio_file)
}
fun play() {
mediaPlayer.start()
}
fun stop() {
mediaPlayer.stop()
}
}
And call these functions from their respective lifecycle method inside your Activity/Fragment, depending on your specific needs
class YourActivity {
val mediaPlayerManager = MediaPlayerManager(context)
override onCreate() {
...
mediaPlayerManager.setupPlayer()
}
override fun onResume() {
...
mediaPlayerManager.play()
}
override fun onPause() {
...
mediaPlayerManager.stop()
}
}
I should add that I'm not necessarily providing a fully-fledged answer here, but a starting point for you to massage to your own needs. The Manager class is nothing but an abstraction of the concept I'm trying to communicate. Lastly, if you want to use a different audio resource file in another Activity/Fragment, you would have to create a method to re-assign the MediaPlayer object inside it with the appropriate file.
E.g.
fun setupPlayer(audioRes: Int) {
mediaPlayer = MediaPlayer.create(context, audioRes)
}
I have done this before
create a Class and named it (for example I named it C) and extend that from Application like following (don't forget put android:name=".C" in <application> tag in manifest.xml):
class C:Application() {
fun onCreate() {
super.onCreate()
context = getApplicationContext()
app = this
}
companion object {
private val context:Context
var currentActivity:Activity
var currentActivities:ArrayList<Activity> = ArrayList()
var handler:Handler
var app:C
fun get():C {
return app
}
fun getContext():Context {
if (currentActivity != null)
{
return currentActivity
}
return context
}
}
}
I created a class for parent of AppCompatActivity and (named UAppCompactActivity)extend it form AppCompatActivity then extend all activities from UAppCompactActivity:
abstract class UAppCompatActivity:AppCompatActivity() {
fun onCreate(#Nullable savedInstanceState:Bundle, #Nullable persistentState:PersistableBundle) {
super.onCreate(savedInstanceState, persistentState)
}
protected fun onResume() {
super.onResume()
C.setCurrentActivity(this)
C.currentActivities.add(this)
/* you can play your music here or do any action you desired */
}
protected fun onPause() {
super.onPause()
C.currentActivities.remove(this)
/*
you can stop your music here or do any action you desired
if (UBase.currentActivities.size() === 0)
G.backgroundMusics.get(G.app.musicNumberBackAndNowPlay).pause()
else
play music or switch to new music
*/
}
}

Fatal error LifecycleOwners must call register before they are STARTED on registerForActivityResult

I have a simple empty activity that checks if permissions need to be requested. When registerForActivityResult is called, it crashes with the error java.lang.IllegalStateException: LifecycleOwner com.example.app.PermsRequester#41a30da is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED. From my research, I think I need to check if savedInstanceState is null and if so, create a new fragment? I'm not sure if that is the correct solution or how to implement. Below is the code:
class PermsRequester : AppCompatActivity() {
requestPerms = false
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.AppTheme)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_perms_requester)
findViewById<Button>(R.id.acceptButton).setOnClickListener { accepted() }
}
private fun accepted() {
//There is code here to check if rationale dialog needs to be displayed
//There is code here to build a mutable list of permissions that need to be requested and sets requestPerms = true
if(requestPerms)
requestPermissions()
}
private fun requestPermissions() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//app crashes on the following line
val requestMultiplePermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
permissions -> permissions.entries.forEach {
//Handles permission result
}
}
}
}
}
You need to registerForActivityResult before onStart of the Activity.
private lateinit var requestMultiplePermissionsLauncher:
ActivityResultLauncher<Array<String>>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestMultiplePermissionsLauncher =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
permissions.entries.forEach {
//Handles permission result
}
}
}
private fun accepted() {
if(requestPerms) {
val permissions = arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.CAMERA)
requestMultiplePermissionsLauncher.launch(permissions)
}
}

Android M ask for permission in onSurfaceTextureAvailable callback not in Activity

Symptoms: upon first start my app crashes with java.lang.SecurityException: Lacking privileges to access camera service. I am getting "Unfortunately your app has crashed" dialog, clicking "OK", under this dialog there are two dialogs asking for the necessary permissions. I say "OK" to both and from now on my app works. Next starts are without the crash.
Causes: After some time of reading and debugging I came to understanding that my app problem is that it wants to do some Camera related logic before it obtains the required permissions (onSurfaceTextureAvailable callback in my CameraHandler class) or before camera surface view comes to foreground.
There's a lot of questions regarding similar errors on SO and Github, but still it's hard for me to figure out.
I tried to go through this answer, but my setup is a bit different, i.e. I have my Camera logic inside a different class that isn't an Activity, and I would really like to keep it that way not to clutter my CameraActivity class. Is there a good way to deal with this?
How to make sure that when onSurfaceTextureAvailable in my CameraHandler class is fired, the permissions are already granted, so that I am not getting java.lang.SecurityException: Lacking privileges to access camera service on the first run?
This is my SurfaceTextureListener located in CameraHandler class:
private val surfaceTextureListener = object : TextureView.SurfaceTextureListener {
override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
openCamera(width, height) //this line here makes my app crash
}
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
configureTransform(width, height)
}
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
return true
}
override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
}
}
My CameraActivity onCreate, onResume() and onPause():
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!canAccessCamera() || !canRecordAudio()) {
requestPermissions(INITIAL_PERMISSIONS, INITIAL_REQUEST)
}
}
}
override fun onResume() {
super.onResume()
cameraHandler.startHandler()
}
override fun onPause() {
cameraHandler.stopHandler()
super.onPause()
}
permission checking inside CameraActivity
#RequiresApi(api = Build.VERSION_CODES.M)
private fun canAccessCamera() : Boolean {
return (hasPermission(android.Manifest.permission.CAMERA))
}
#RequiresApi(api = Build.VERSION_CODES.M)
private fun canRecordAudio() : Boolean {
return (hasPermission(android.Manifest.permission.RECORD_AUDIO))
}
#RequiresApi(api = Build.VERSION_CODES.M)
private fun hasPermission(perm : String) : Boolean{
return (PackageManager.PERMISSION_GRANTED == checkSelfPermission(perm))
}
#RequiresApi(Build.VERSION_CODES.M)
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == INITIAL_REQUEST) {
if (canAccessCamera() && canRecordAudio()) {
recordButton2.setOnClickListener {
if (isRecording) {
cameraHandler.endRecording()
} else {
currentFileName = generateTimestampName()
createCSVFile(currentFileName)
cameraHandler.startStopRecording()
}
isRecording = !isRecording
}
} else {
Toast.makeText(this, "We need it to perform magic", Toast.LENGTH_SHORT).show()
}
}
}
I've written myself a little PermissionRequestHandler for exactly this purpose, you can find it here: https://gist.github.com/Hikaru755/0ae45a4184bdbc28dcc5c1af659b4508
You simply create an instance of it in your Activity, and make sure that any calls to onRequestPermissionsResult are passed to it, like in the example BaseActivity in the gist. Then you can pass it around to other classes, request permission through it and get callbacks where you need them without cluttering your Activity. Be careful not to create memory leaks by holding it longer than the Activity lives, though!

Categories

Resources