Camera not working on surfaceView once permission is given - kotlin

class ScanScopeFragment : Fragment() {
private val TAG: String = "ScanScopeFragment"
private lateinit var binding: FragmentScanScopeBinding
private lateinit var mainContext: Context
private lateinit var mainActivity: Activity
private lateinit var surfaceView: SurfaceView
private val REQUEST_CAMERA_PERMISSION = 201
//private val requestCodeCameraPermission = 1001
private lateinit var cameraSource: CameraSource
private lateinit var barcodeDetector: BarcodeDetector
private lateinit var barcodeText: TextView
private var scannedValue = ""
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentScanScopeBinding.inflate(inflater, container, false)
mainContext = requireContext()
mainActivity = requireActivity()
surfaceView = binding.cameraSurfaceView
barcodeText = binding.barcodeText
initialiseDetectorsAndSources()
return binding.root
}
private fun initialiseDetectorsAndSources() {
//Toast.makeText(getApplicationContext(), "Barcode scanner started", Toast.LENGTH_SHORT).show();
barcodeDetector = BarcodeDetector.Builder(mainContext)
.setBarcodeFormats(Barcode.ALL_FORMATS)
.build()
cameraSource = CameraSource.Builder(mainContext, barcodeDetector)
.setRequestedPreviewSize(1920, 1080)
.setAutoFocusEnabled(true) //you should add this feature
.build()
surfaceView.getHolder().addCallback(object : SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder) {
try {
if (ActivityCompat.checkSelfPermission(
mainContext,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED
) {
cameraSource.start(surfaceView.getHolder())
} else {
ActivityCompat.requestPermissions(
mainActivity,
arrayOf(Manifest.permission.CAMERA),
REQUEST_CAMERA_PERMISSION
)
}
} catch (e: IOException) {
e.printStackTrace()
}
}
override fun surfaceChanged(
holder: SurfaceHolder,
format: Int,
width: Int,
height: Int
) {
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
cameraSource.stop()
}
})
barcodeDetector.setProcessor(object : Detector.Processor<Barcode> {
override fun release() {
// Toast.makeText(getApplicationContext(), "To prevent memory leaks barcode scanner has been stopped", Toast.LENGTH_SHORT).show();
}
override fun receiveDetections(detections: Detector.Detections<Barcode>) {
val barcodes = detections.detectedItems
if (barcodes.size() != 0) {
barcodeText.post(Runnable {
scannedValue = barcodes.valueAt(0).displayValue
barcodeText.setText(scannedValue)
})
}
}
})
}
/*
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_CAMERA_PERMISSION && grantResults.isNotEmpty()) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initialiseDetectorsAndSources()
} else {
// Toast.makeText(applicationContext, "Permission Denied", Toast.LENGTH_SHORT).show()
}
}
}
*/
override fun onPause() {
super.onPause()
cameraSource.release()
}
override fun onResume() {
super.onResume()
initialiseDetectorsAndSources()
}
}
I am hoping once the permission is given the camera will open on the surfaceView

Related

Cannot create an instance of class error in Kotlin ViewModel

I am trying to create a ViewModel in my Kotlin app, but I am getting the following error: java.lang.RuntimeException: Cannot create an instance of class com.ri.movieto.presentation.home.HomeViewModel. Also, I am using Hilt.
And here is the code for my HomeFragment:
#AndroidEntryPoint
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val homeViewModel: HomeViewModel by viewModels()
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
contentLayout = binding.contentLayout
dataLoading = binding.dataLoading
subscribeToObservables()
return binding.root
}
private fun subscribeToObservables() {
lifecycleScope.launchWhenStarted {
homeViewModel.state.collectLatest {
Log.e("++++", it.response?.page.toString())
}
}
}
}
Here is the code for my HomeViewModel:
#HiltViewModel
class HomeViewModel #Inject constructor(
private val getTrendingMoviesUseCase: GetTrendingMoviesUseCase
) : ViewModel() {
private val _state = MutableStateFlow(TrendingMoviesState())
val state = _state.asStateFlow()
init {
getTrendingMovies()
}
private fun getTrendingMovies() {
getTrendingMoviesUseCase().onEach { result ->
when (result) {
is Resource.Success -> {
_state.value = TrendingMoviesState(response = result.data)
}
is Resource.Error -> {
_state.value =
TrendingMoviesState(error = result.message ?: "An unexpected error occurred")
}
is Resource.Loading -> {
_state.value = TrendingMoviesState(isLoading = true)
}
}
}
}
}
GetTrendingMoviesUseCase.kt:
class GetTrendingMoviesUseCase #Inject constructor(
private val repository: MovieRepository,
private val movieResponseDtoToDomain: MovieResponseDtoToDomain
) {
operator fun invoke(): Flow<Resource<MovieResponse>> = flow {
try {
emit(Resource.Loading())
val movieResponseDto = repository.getTrendingMovies()
val movieResponse = movieResponseDtoToDomain.mapFrom(movieResponseDto)
emit(Resource.Success(movieResponse))
} catch (e: HttpException) {
emit(Resource.Error(e.localizedMessage ?: "Beklenmeyen bir hata oluştu"))
} catch (e: IOException) {
emit(Resource.Error("Lütfen internet bağlantınızı kontrol edin"))
}
}
}
MovieResponseDtoToDomain.kt:
#Singleton
class MovieResponseDtoToDomain #Inject constructor(private val itemDecider: MovieItemDecider) :
Mapper<MovieResponseDto, MovieResponse> {
override fun mapFrom(input: MovieResponseDto): MovieResponse {
return MovieResponse(
page = input.page,
movies = input.results.map { movie ->
MovieResponse.Movie(
release_year = itemDecider.provideReleaseYear(movie.release_date),
poster_path = itemDecider.providePosterPath(movie.poster_path),
backdrop_path = itemDecider.provideBackdropPath(movie.backdrop_path),
vote_average = itemDecider.provideRoundedAverage(movie.vote_average),
title = movie.title,
id = movie.id,
video = movie.video,
release_date = movie.release_date,
overview = movie.overview,
genre_ids = movie.genre_ids
)
},
total_pages = input.total_pages,
total_results = input.total_results
)
}
}

Kotlin - lateinit property fragmentHomeBinding has not been initialized

I am working on a kotlin application that contains fragments. I am converting an app I created using activity to fragments but I am having an issue. I get an error when running the app that the property fragmentHomeBinding has not been initialized and the app closes.
Here's the fragment Home.kt
class Home : Fragment() {
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
private lateinit var fragmentHomeBinding: FragmentHomeBinding
#SuppressLint("WrongViewCast")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
getCurrentLocation()
fragmentHomeBinding.etGetCityName.setOnEditorActionListener { v, actionId, keyEvent ->
if(actionId == EditorInfo.IME_ACTION_SEARCH)
{
getCityWeather(fragmentHomeBinding.etGetCityName.text.toString())
val view = activity?.currentFocus
if(view!=null)
{
val imm:InputMethodManager=
activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
fragmentHomeBinding.etGetCityName.clearFocus()
}
true
}
else false
}
}
private fun getCityWeather(cityName:String)
{
fragmentHomeBinding.pbLoading.visibility = View.VISIBLE
ApiUtilities.getApiInterface()?.getCityWeatherData(cityName, API_KEY)?.enqueue(
object:Callback<ModelClass>{
override fun onResponse(call: Call<ModelClass>, response: Response<ModelClass>) {
setDataOnViews((response.body()))
}
override fun onFailure(call: Call<ModelClass>, t: Throwable) {
Toast.makeText(activity?.applicationContext, "Wrong City", Toast.LENGTH_SHORT).show()
}
})
}
private fun getCurrentLocation()
{
if(checkPermission())
{
if(isLocationEnabled())
{
if(ActivityCompat.checkSelfPermission(
requireActivity(), android.Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
requireActivity(),
android.Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
){
requestPermission()
return
}
fusedLocationProviderClient.lastLocation.addOnCompleteListener(requireActivity()){ task->
val location: Location?=task.result
if(location==null)
{
fetchCurrentLocationWeather(23.76137119142536.toString(), 90.35059989467042.toString())
}
else
{
fetchCurrentLocationWeather(location.latitude.toString(),location.longitude.toString())
}
}
}
else
{
Toast.makeText(activity?.applicationContext, "Turn on Location", Toast.LENGTH_SHORT).show()
val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
startActivity(intent)
}
}
}
private fun fetchCurrentLocationWeather(latitude: String, longitude:String)
{
fragmentHomeBinding.pbLoading.visibility = View.VISIBLE
ApiUtilities.getApiInterface()?.getCurrentWeatherData(latitude, longitude, API_KEY)?.enqueue(
object : Callback<ModelClass> {
override fun onResponse(call: Call<ModelClass>, response: Response<ModelClass>) {
if(response.isSuccessful)
{
setDataOnViews(response.body())
}
}
override fun onFailure(call: Call<ModelClass>, t: Throwable) {
Toast.makeText(activity?.applicationContext, "ERROR", Toast.LENGTH_SHORT).show()
}
})
}
private fun setDataOnViews(body: ModelClass?) {
val sdf = SimpleDateFormat("dd/MM/yyyy hh:mm")
val currentDate = sdf.format(Date())
fragmentHomeBinding.tvDateTime.text = currentDate
fragmentHomeBinding.tvDayMaxTemp.text = ""+kelvinToCelsius(body!!.main.temp_max) + "°"
fragmentHomeBinding.tvDayMinTemp.text = ""+kelvinToCelsius(body!!.main.temp_min) + "°"
fragmentHomeBinding.tvTemp.text = ""+kelvinToCelsius(body!!.main.temp)
fragmentHomeBinding.tvFeelsLike.text = "Feels like: "+kelvinToCelsius(body!!.main.feels_like) + "°"
fragmentHomeBinding.tvWeatherType.text = body.weather[0].main
fragmentHomeBinding.tvPressure.text = body.main.pressure.toString()
fragmentHomeBinding.tvHumidity.text = body.main.humidity.toString() + " %"
fragmentHomeBinding.tvWindSpeed.text = body.wind.speed.toString() + " m/s"
fragmentHomeBinding.tvCityName.text = body.name
updateUI(body.weather[0].id)
}
private fun updateUI(id: Int) {
fragmentHomeBinding.pbLoading.visibility = View.GONE
fragmentHomeBinding.mainLayout.visibility = View.VISIBLE
}
private fun kelvinToCelsius(temp: Double): Double
{
var intTemp = temp
intTemp = intTemp.minus(273)
return intTemp.toBigDecimal().setScale(1, RoundingMode.UP).toDouble()
}
companion object
{
const val PERMISSION_REQUEST_ACCESS_LOCATION = 100
const val API_KEY = "3c709ccaf2730aa1c263925f75db631a"
}
private fun isLocationEnabled():Boolean{
val locationManager:LocationManager=activity?.getSystemService(Context.LOCATION_SERVICE) as LocationManager
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(
LocationManager.NETWORK_PROVIDER
)
}
private fun requestPermission(){
ActivityCompat.requestPermissions(
requireActivity(), arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION,
android.Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSION_REQUEST_ACCESS_LOCATION
)
}
private fun checkPermission():Boolean{
if(ActivityCompat.checkSelfPermission(requireActivity(),
android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(requireActivity(),
android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
{
return true
}
return false
}
#Suppress("DEPRECATION")
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if(requestCode== PERMISSION_REQUEST_ACCESS_LOCATION)
{
if(grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
Toast.makeText(activity?.applicationContext, "Granted", Toast.LENGTH_SHORT).show()
getCurrentLocation()
}
else{
Toast.makeText(activity?.applicationContext, "Denied", Toast.LENGTH_SHORT).show()
}
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
fragmentHomeBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
// Inflate the layout for this fragment
return fragmentHomeBinding.root
}
}
Here's the error that shows up on logcat:
2022-05-20 17:45:20.582 22026-22048/com.example.weather D/EGL_emulation: app_time_stats: avg=30.74ms min=18.05ms max=34.54ms count=33
2022-05-20 17:45:21.416 22026-22026/com.example.weather D/AndroidRuntime: Shutting down VM
2022-05-20 17:45:21.417 22026-22026/com.example.weather E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.weather, PID: 22026
kotlin.UninitializedPropertyAccessException: lateinit property fragmentHomeBinding has not been initialized
at com.example.weather.Home.onCreate(Home.kt:58)
at androidx.fragment.app.Fragment.performCreate(Fragment.java:2949)
at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:475)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:278)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3138)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3072)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:502)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:246)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1455)
at android.app.Activity.performStart(Activity.java:8076)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3660)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
2022-05-20 17:45:21.435 22026-22026/com.example.weather I/Process: Sending signal. PID: 22026 SIG: 9
Help's appreciated, thanks.
Your Fragment viewbinding instance fragmentHomeBinding is initialised at onCreateView() life cycle method. But you are accessing at onCreate() lifecycle method. In Fragment lifecycle, onCreate() will be called before onCreatedView().
As a result you are accessing an object which is not initialised.
To resolve the issue, move your viewbinding reference code in onCreate() to onCreateView() as below.
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
fragmentHomeBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
fragmentHomeBinding.etGetCityName.setOnEditorActionListener { v, actionId, keyEvent ->
if(actionId == EditorInfo.IME_ACTION_SEARCH)
{
getCityWeather(fragmentHomeBinding.etGetCityName.text.toString())
val view = activity?.currentFocus
if(view!=null)
{
val imm:InputMethodManager=
activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
fragmentHomeBinding.etGetCityName.clearFocus()
}
true
}
else false
}
// Inflate the layout for this fragment
return fragmentHomeBinding.root
}

How to call a method of a fragment from adapter class?

I have seen many questions like this but they are not the same as my situation and I couldn't use those solutions.
I have a fragment (OrdersByStatusFragment.kt) and the method I want to call from the adapter is getOrderStatusList()
class OrdersByStatusFragment : BaseFragment() {
private lateinit var binding: OrderStatusLayoutBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_orders_by_status, container, false)
}
override fun onResume() {
super.onResume()
getOrderStatusList()
}
fun getOrderStatusList() {
showProgressDialog(resources.getString(R.string.please_wait))
FirestoreClass().getOrderStatusList(this#OrdersByStatusFragment)
}
fun successOrderStatusList(orderStatusList: ArrayList<OrderStatus>) {
hideProgressDialog()
if (orderStatusList.size > 0) {
rv_order_by_status.visibility = View.VISIBLE
tv_no_orders_by_status_found.visibility = View.GONE
rv_order_by_status.layoutManager = LinearLayoutManager(activity)
rv_order_by_status.setHasFixedSize(true)
val orderStatusListAdapter =
OrderStatusListAdapter(requireActivity(), orderStatusList)
rv_order_by_status.adapter = orderStatusListAdapter
} else {
rv_order_by_status.visibility = View.GONE
tv_no_orders_by_status_found.visibility = View.VISIBLE
}
}
fun successNewOrderStatus() {
Toast.makeText(requireContext(), "Success", Toast.LENGTH_SHORT).show()
}
}
Adapter OrderStatusListAdapter.kt
open class OrderStatusListAdapter(
private val context: Context,
private var list: ArrayList<OrderStatus>,
) : RecyclerView.Adapter<OrderStatusListAdapter.MyViewHolder>() {
class MyViewHolder(var binding: OrderStatusLayoutBinding) :
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
OrderStatusLayoutBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val model = list[position]
if (true) {
GlideLoader(context).loadProductPicture(
model.image,
holder.itemView.iv_order_status_item_image
)
val dateFormat = "dd MMM yyyy HH:mm"
val formatter = SimpleDateFormat(dateFormat, Locale.getDefault())
val calendar: Calendar = Calendar.getInstance()
calendar.timeInMillis = model.order_datetime
val orderDateTime = formatter.format(calendar.time)
holder.itemView.tv_order_status_order_date.text = orderDateTime
holder.itemView.tv_order_status_item_name.text = model.items[0].title
holder.itemView.tv_order_status_item_price.text = "$${model.total_amount}"
holder.itemView.tv_order_status.text = model.order_status
holder.itemView.tv_order_status_order_id.text = model.id
holder.binding.spnOrderChangeStatus.onItemSelectedListener =
object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
holder.binding.tvSpinnerValue.text =
parent?.getItemAtPosition(position).toString()
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
holder.binding.btnOrderStatusChangeStatus.setOnClickListener {
Toast.makeText(context, "Button Clicked", Toast.LENGTH_SHORT).show()
FirestoreClass().updateOrderStatus(
model.id,
holder.binding.tvSpinnerValue.text.toString()
)
Toast.makeText(context, "DB Updated", Toast.LENGTH_SHORT).show()
}
holder.itemView.ib_order_status_delete_product.visibility = View.GONE
holder.itemView.setOnClickListener {
val intent = Intent(context, SoldProductDetailsActivity::class.java)
intent.putExtra(Constants.EXTRA_SOLD_PRODUCT_DETAILS, model)
context.startActivity(intent)
}
}
}
}
As you can see the fun getOrderStatusList() in the OrdersByStatusFragment.kt is actually calling a method in the FirestoreClass.kt. Following is the getOrderStatusList() in the FirestoreClass.kt
fun getOrderStatusList(fragment: OrdersByStatusFragment) {
mFireStore.collection(Constants.ORDERS)
.whereIn("order_status", listOf("Pending", "In process"))
.get()
.addOnSuccessListener { document ->
val list: ArrayList<OrderStatus> = ArrayList()
for (i in document.documents) {
val orderStatus = i.toObject(OrderStatus::class.java)!!
orderStatus.id = i.id
list.add(orderStatus)
}
fragment.successOrderStatusList(list)
}
.addOnFailureListener {
fragment.hideProgressDialog()
}
}
The way I solved something like this is to pass a reference to the method into the adapter's constructor, then you can call the method in the adapter.
See kotlin-how-to-pass-a-function-as-parameter-to-another
In general, the link shows a class containing a method called buz.
Let's say your adapter has a constructor like:
class MyAdapter (private val context: Context, val buzz: () -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>()
then you can create the adapter like
MyAdapter(applicationContext, ::buz)
In the adapter the method can be called normally:
buzz()

Get Wifi scan Result List in Kotlin

I want to receive all avaiable wifi to a ResultList using broadcastReceiver override method onReceive(). Don't know why I cannot go into my override method ( Can't catch breakpoint at println("On receive active") )
After that I checked resultList by "If" statement but it occures that resultList is empty.
What am I doing wrong ?
My code below :
class AddNewDeviceFragment : Fragment() {
var resultList = ArrayList<ScanResult>()
private var adapter: NewDeviceAdapter = NewDeviceAdapter(arrayListOf())
private lateinit var model: NewDeviceViewModel
private lateinit var rootView: View
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
rootView = inflater.inflate(R.layout.fragment_addnewdevice, container, false)
return rootView
}
override fun onStart() {
super.onStart()
var newDevicesRecycledView = rootView.findViewById(R.id.newDevicesRecycledView) as RecyclerView
newDevicesRecycledView.layoutManager = LinearLayoutManager(activity)
newDevicesRecycledView.adapter = adapter
//ViewModel
model = ViewModelProviders.of(this).get(NewDeviceViewModel::class.java)
//LiveData
model.getNewDevices()
.observe(viewLifecycleOwner, Observer<MutableList<NewDevice>> { newDevices ->
adapter.addDevice(newDevices)
})
refreshButton.setOnClickListener { startScan() }
}
fun startScan() {
model.clearAllData()
val wifiManager = context?.getSystemService(Context.WIFI_SERVICE) as WifiManager
val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(p0: Context?, p1: Intent?) {
resultList = wifiManager.scanResults as ArrayList<ScanResult>
println("On receive active")
for (result in resultList) {
model.addNewDevice(NewDevice(result.SSID.toString()))
}
}
}
if (!wifiManager.isWifiEnabled) {
Toast.makeText(activity, "Wifi is disable... We need to enable it", Toast.LENGTH_LONG).show()
wifiManager.setWifiEnabled(true)
}
context?.registerReceiver(broadcastReceiver, IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
if(resultList.isEmpty())
Toast.makeText(activity,"ResultList empty",Toast.LENGTH_LONG).show()
wifiManager.startScan()
Toast.makeText(activity,"Scanning Wifi",Toast.LENGTH_LONG).show()
}
}

Capture and show image from camera2 API, Android Studio, Kotlin

I have been following a tutorial on how to get a camera preview on a fragment to show on my app, I am new to kotlin but have been programming in Swift for 2 years. Is there a way to get an image from the preview and show it in another image view.
I created an image view called imageGotCont and this is where I want to place the images I have a button in my main activity so when I press it I need a function that gets an image fromt the preview and places it in the image view.
Below is the fragment.
class FragmentCameraPreview : Fragment() {
private val MAX_DISPLAY_WIDTH = 1280
private val MAX_DISPLAY_HEIGHT = 720
private lateinit var captureSession: CameraCaptureSession
private lateinit var captureRequestBuilder: CaptureRequest.Builder
private lateinit var imageSize: Size
private lateinit var cameraDevice: CameraDevice
private val deviceStateCallback = object : CameraDevice.StateCallback() {
override fun onOpened(camera: CameraDevice?) {
Log.d(TAG, "camera device opened")
if (camera != null) {
cameraDevice = camera
previewSession()
}
}
override fun onDisconnected(camera: CameraDevice?) {
Log.d(TAG, "camera device disconnected")
camera?.close()
}
override fun onError(camera: CameraDevice?, error: Int) {
Log.d(TAG, "camera device error")
this#FragmentCameraPreview.activity?.finish()
}
}
private lateinit var backgroundThread: HandlerThread
private lateinit var backgroundHandler: Handler
private val cameraManager by lazy {
activity?.getSystemService(Context.CAMERA_SERVICE) as CameraManager
}
companion object {
private val TAG = FragmentCameraPreview::class.qualifiedName
const val REQUEST_CAMERA_PERMISSION = 100
#JvmStatic
fun newInstance() = FragmentCameraPreview()
}
private val surfaceListner = object : TextureView.SurfaceTextureListener {
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int) {
}
override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) = Unit
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean = true
override fun onSurfaceTextureAvailable(surface: SurfaceTexture?, width: Int, height: Int) {
Log.d(TAG, "Tony texture surface width: $width height: $height")
openCamera()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
#AfterPermissionGranted(REQUEST_CAMERA_PERMISSION)
private fun checkCameraPermission() {
if (EasyPermissions.hasPermissions(activity!!, android.Manifest.permission.CAMERA)) {
Log.d(TAG, "APP has camera permission")
connectCamera()
} else {
EasyPermissions.requestPermissions(
activity!!,
getString(R.string.camera_request_rationale),
REQUEST_CAMERA_PERMISSION,
android.Manifest.permission.CAMERA
)
}
}
override fun onResume() {
super.onResume()
startBackgroundThread()
if (previewTextureView.isAvailable)
openCamera()
else
previewTextureView.surfaceTextureListener = surfaceListner
}
override fun onPause() {
closeCamera()
stopBackgroundThread()
super.onPause()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val myInflatedView = inflater.inflate(R.layout.fragment_camera_preview, container, false)
return myInflatedView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
activity?.window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
}
private fun openCamera() {
checkCameraPermission()
}
private fun <T> cameraCharacteristics(cameraId: String, key: CameraCharacteristics.Key<T>): T {
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
return when (key) {
CameraCharacteristics.LENS_FACING -> characteristics.get(key)
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP -> characteristics.get(key)
else -> throw IllegalArgumentException("Key not recognized")
}
}
private fun cameraId(lens: Int): String {
var deviceId = listOf<String>()
try {
val cameraIdList = cameraManager.cameraIdList
deviceId = cameraIdList.filter { lens == cameraCharacteristics(it, CameraCharacteristics.LENS_FACING) }
} catch (e: CameraAccessException) {
Log.e(TAG, e.toString())
}
return deviceId[0]
}
private fun connectCamera() {
val deviceID = cameraId(CameraCharacteristics.LENS_FACING_BACK)
Log.d(TAG, "deviceID: $deviceID")
try {
cameraManager.openCamera(deviceID, deviceStateCallback, backgroundHandler)
} catch (e: CameraAccessException) {
Log.e(TAG, e.toString())
} catch (e: InterruptedException) {
Log.e(TAG, "Open camera device interrupted while opening")
}
}
private fun startBackgroundThread() {
backgroundThread = HandlerThread("CameraKotlin").also { it.start() }
backgroundHandler = Handler(backgroundThread.looper)
}
private fun stopBackgroundThread() {
backgroundThread.quitSafely()
try {
backgroundThread.join()
} catch (e: InterruptedException) {
Log.e(TAG, e.toString())
}
}
private fun previewSession() {
val surfaceTexture = previewTextureView.surfaceTexture
surfaceTexture.setDefaultBufferSize(MAX_DISPLAY_WIDTH, MAX_DISPLAY_HEIGHT)
val surface = Surface(surfaceTexture)
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
captureRequestBuilder.addTarget(surface)
cameraDevice.createCaptureSession(
Arrays.asList(surface),
object : CameraCaptureSession.StateCallback() {
override fun onConfigureFailed(session: CameraCaptureSession?) {
Log.e(TAG, "creating capture session failed")
}
override fun onConfigured(session: CameraCaptureSession?) {
if (session != null) {
captureSession = session
captureRequestBuilder.set(
CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE
)
captureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null)
}
}
}, null
)
}
private fun closeCamera() {
if (this::captureSession.isInitialized)
captureSession.close()
if (this::cameraDevice.isInitialized)
cameraDevice.close()
}
}