Create a real-time line chart by using kotlin - android

I'm trying to create a chart that displays sensor data from a cell phone in real time. I wrote a code for this, but the data was recorded, but the graph was recorded only on the same x-axis. The code is shown below. How should I solve this? If I need to create a separate thread, where should I add it?
package com.example.ex_linear_acc_graph
import android.content.Context
import android.graphics.Color
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.widget.LinearLayout
import android.widget.TextView
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.components.Legend
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.components.YAxis
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
import com.github.mikephil.charting.formatter.ValueFormatter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import kotlin.concurrent.timer
class linearActivity : AppCompatActivity(), SensorEventListener {
private val mSensorManager by lazy {
getSystemService(Context.SENSOR_SERVICE) as SensorManager
}
private lateinit var chart: LineChart
private lateinit var data: LineData
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_linear)
chart = findViewById(R.id.chart_line)
chart.description.isEnabled = false
chart.setTouchEnabled(true)
chart.isDragEnabled = true
chart.setScaleEnabled(true)
chart.setPinchZoom(false)
chart.legend.form = Legend.LegendForm.LINE
chart.xAxis.position = XAxis.XAxisPosition.BOTTOM
chart.xAxis.setDrawLabels(true)
chart.xAxis.axisMaximum = 0f
chart.xAxis.setDrawAxisLine(true)
chart.xAxis.setDrawGridLines(false)
chart.axisRight.isEnabled = false
chart.legend.textColor = Color.WHITE
chart.animateXY(2000, 2000)
chart.invalidate()
data = LineData()
chart.data = data
}
override fun onResume() {
super.onResume()
mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)?.also{
linearacceleration -> mSensorManager.registerListener(
this,
linearacceleration,
SensorManager.SENSOR_DELAY_NORMAL,
SensorManager.SENSOR_DELAY_UI
)}
}
override fun onPause() {
super.onPause()
mSensorManager.unregisterListener(this)
}
override fun onSensorChanged(event: SensorEvent) {
var second : Float = 0f
timer(period = 1000, initialDelay = 1000){
second++
}
if(event.sensor.type == Sensor.TYPE_MAGNETIC_FIELD){
val mag_x = event.values[0]
val mag_y = event.values[1]
val mag_z = event.values[2]
val tv_mag : TextView = findViewById(R.id.tv_linear_acc)
tv_mag.text = "mag_x : ${mag_x}\nmag_y : ${mag_y}\nmag_z : ${mag_z}"
val dataSet = LineDataSet(listOf(Entry(second, mag_x), Entry(second, mag_y), Entry(second, mag_z)), "Accelerometer Data")
data.addDataSet(dataSet)
chart.notifyDataSetChanged()
}
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
// Do nothing
}
}

Related

Android Studio: Import not being recognized

I'm having an issue where I've imported an import in order for a piece of code to work but no matter how many times I import the import, the code isn't recognizing that it's there. I've already tried invalidating and restarting, multiple times. I've read that another solution to this is to Sync with File System, but I don't appear to have that option under File.
The import in question is import java.text.MessageFormat.format
import android.content.ContentValues.TAG
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import com.squareup.okhttp.internal.http.HttpDate.format
import java.math.BigDecimal
import java.sql.Time
import java.sql.Timestamp
import java.text.DateFormat
import java.text.MessageFormat.format
import java.util.*
import kotlin.collections.ArrayList
class RemindersActivity : AppCompatActivity() {
lateinit var petID: String
val db = Firebase.firestore
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_reminders)
displayReminders()
petID = intent.getStringExtra("petID").toString()
val fab: View = findViewById(R.id.fab_reminders)
fab.setOnClickListener {
val intent = Intent(this, AddReminderActivity::class.java)
intent.putExtra("petID", petID)
startActivity(intent)
}
}
override fun onStart() {
super.onStart()
displayReminders()
}
private fun displayReminders() {
val recyclerview = findViewById<RecyclerView>(R.id.recyclerview_reminders)
recyclerview.layoutManager = LinearLayoutManager(this)
db.collection("pets").document(petID).collection("reminders").get().addOnSuccessListener { result ->
val data = mutableListOf<RemindersData>()
for (document in result) {
val title = document.data["title"].toString()
val timestamp = document.data["timestamp"] as Long
val cal = Calendar.getInstance()
cal.timeInMillis = timestamp * 1000L
val date = DateFormat.format("dd-MM-yyyy hh:mm:ss aa", cal).toString() //<- code note recognizing import is format
val frequency = document.data["frequency"].toString()
data.add(RemindersData(title, date, frequency))
}
val adapter = RemindersAdapter(data)
recyclerview.adapter = adapter
}.addOnFailureListener { e->
Log.w(TAG, "Error getting documents", e)
}
}
}
It just seems that you have added a few imports from the java packages instead of the android packages. It can happen when you use auto import in the IDE and there are multiple options and you click the wrong one.
When that happens you either have to undo the import or fix it manually.
Remove the import for
import java.text.DateFormat
Add the import for
import android.text.format.DateFormat
Afterwards, if there are any unused imports left, you can remove those as well.

Kotlin livedata observer not triggered

i'm practising a bit with kotlin and was testing Room and livedata, my app gets data from a json and the stores it in room, i want to move this network call to its own file and class, but if i do so the observer i set to get the changes don't trigger anymore, any help would be appreciated
here is a snipped of my mainactivity, if more is needed to know what happens please let me know
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import android.widget.Toast
import androidx.activity.viewModels
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope
import androidx.room.Room
import com.optiva.videoplayer.data.*
import com.optiva.videoplayer.network.GetData
import com.optiva.videoplayer.network.Networking
import com.optiva.videoplayer.network.RetrofitConnect
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dbcategories = Room.databaseBuilder(applicationContext, CategoriesDatabase::class.java,"categories.db").build()
val dbvideo = Room.databaseBuilder(applicationContext, VideosDatabase::class.java,"videos.db").build()
val retrofitData = RetrofitConnect.retrofitInst?.create(GetData::class.java)
val categoriesList = retrofitData?.getAll()
categoriesList?.enqueue(object: Callback<DataList> {
override fun onResponse(
call: Call<DataList>,
response: Response<DataList>
) {
val test = response?.body()
val cat = test?.categories
val vid = test?.videos
lifecycleScope.launch(Dispatchers.IO) {
if (cat != null) {
for(c in cat){
dbcategories.categoriesDAO().insertAll(CategoriesEntity(c.id,c.title,c.type))
}
}
if (vid != null) {
for(v in vid){
dbvideo.VideosDAO().insertAll(VideosEntity(v.id,v.thumb,v.videoUrl,v.categoryId,v.name))
}
}
}
}
override fun onFailure(call: Call<DataList>, t: Throwable) {
Toast.makeText(applicationContext,"error", Toast.LENGTH_LONG).show()
}
})
val textView: TextView = findViewById(R.id.test) as TextView
dbcategories.categoriesDAO().getALL().observeForever({categories ->
if(categories.size>0){
textView.text= categories[0].title
}
})
dbcategories.categoriesDAO().getALL().observe(this, {categories ->
if(categories.size>0){
textView.text= categories[0].title
}
}
} ```

How to stop running worker on android?

I created a worker that runs on connecting audio jack but I can't stop the running worker on audio jack disconnection which is triggered by Broadcast Receiver.
I want to keep track of headset usage limit with the help of worker which will only trigger when there is headset connection and will stop the worker whenever the audio jack/headset is detached.
Here is the Broadcast Reciver Code
package com.xanjit.focusly.broadcast_receivers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.util.Log
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.work.*
import com.xanjit.focusly.workers.GetHeadsetUsageTimeWorker
import java.sql.Timestamp
import java.time.Duration
class AudioInputBroadcastReceiver : BroadcastReceiver() {
// lateinit var workManager: WorkManager
// lateinit var workRequest: WorkRequest
#RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context?, intent: Intent?) {
val isConnected = intent!!.getIntExtra("state", 0) === 1
val workManager = WorkManager.getInstance(context!!)
if (isConnected) {
var startTime = System.currentTimeMillis()
Toast.makeText(context,"Connected",Toast.LENGTH_SHORT).show()
val data = Data.Builder()
data.putLong("startTime", startTime)
val workRequest = OneTimeWorkRequest.Builder(
GetHeadsetUsageTimeWorker::class.java,
).setInputData(data.build())
.build()
workManager.enqueue(workRequest)
} else {
Toast.makeText(context,"Disconnected",Toast.LENGTH_SHORT).show()
// val data = Data.Builder()
//
// data.putBoolean("isStopped", true)
// val workRequest = OneTimeWorkRequest.Builder(
// GetHeadsetUsageTimeWorker::class.java,
// ).setInputData(data.build()).build()
workManager.cancelAllWork()
}
}
override fun peekService(myContext: Context?, service: Intent?): IBinder {
return super.peekService(myContext, service)
}
}
Worker Code
package com.xanjit.focusly.workers
import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.graphics.BitmapFactory
import android.media.AudioAttributes
import android.net.Uri
import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.work.ListenableWorker
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.xanjit.focusly.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.sql.Timestamp
import kotlin.time.seconds
var TAG = "EarGuard"
class GetHeadsetUsageTimeWorker(context: Context, workerParams: WorkerParameters) : Worker(
context,
workerParams,
) {
#RequiresApi(Build.VERSION_CODES.O)
override fun doWork(): Result {
// Log.d("EarGuard", "StartTime Worker")
var startTime = inputData.getLong("startTime", System.currentTimeMillis())
// var stopped = inputData.getBoolean("isStopped", false)
// if (!isStopped and !stopped) {
// Log.d("EarGuard", "StartTime Worker" + startTime)
Log.d(TAG, isStopped.toString())
Thread {
while (!isStopped) {
Thread.sleep(1000)
var usageTime = System.currentTimeMillis()
usageTime -= startTime
Log.d(TAG, usageTime.toString())
if ((usageTime / 1000) == 5L) {
CoroutineScope(Dispatchers.Main).launch(Dispatchers.Main)
{
// Toast.makeText(
// applicationContext,
// "Time limit exceeded", Toast.LENGTH_LONG
// ).show()
val notificationChannel = NotificationChannel(
"123",
"EarGuard",
NotificationManager.IMPORTANCE_HIGH
)
notificationChannel.description =
"You have exceeded the maximum usage limit of listening on headset"
notificationChannel.name = "EarGuard"
notificationChannel.lockscreenVisibility = 1
notificationChannel.shouldShowLights()
notificationChannel.enableVibration(true)
notificationChannel.setSound(
Uri.parse("R.raw.sad"),
AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH).build()
)
notificationChannel.shouldVibrate()
var notificationManager =
applicationContext.getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(notificationChannel)
notificationManager.notify(
123, NotificationCompat.Builder(
applicationContext, "123"
).setSmallIcon(R.drawable.ic_launcher_foreground)
.setLargeIcon(
BitmapFactory.decodeResource(
applicationContext.resources,
R.drawable.ic_launcher_foreground
)
)
.setSound(
Uri.parse("R.raw.sad")
)
.setContentTitle("EarGuard")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentText("You have exceeded the maximum usage limit of listening on headset")
.setAutoCancel(false)
.setChannelId("123")
.build()
)
}
break
}
}
}.start()
// }
return Result.success()
}
// #SuppressLint("RestrictedApi")
// override fun isRunInForeground(): Boolean {
// return super.isRunInForeground()
// }
override fun onStopped() {
Log.d(TAG, "Stopped Worker")
super.onStopped()
}
}
MainActivity.kt
package com.xanjit.focusly
import android.content.*
import android.net.Uri
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.material.*
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.WorkRequest
import com.xanjit.focusly.broadcast_receivers.AudioInputBroadcastReceiver
import com.xanjit.focusly.services.CustomService
import com.xanjit.focusly.workers.GetHeadsetUsageTimeWorker
import java.lang.Exception
class MainActivity : ComponentActivity() {
lateinit var receiver: BroadcastReceiver
var TAG = "EarGuard"
lateinit var workManager: WorkManager
lateinit var workRequest: WorkRequest
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
receiver = AudioInputBroadcastReceiver()
setContent {
Surface() {
Scaffold(
topBar = {
TopAppBar() {
}
}
) {
}
}
}
}
override fun onStart() {
super.onStart()
var intentFilter = IntentFilter("android.intent.action.HEADSET_PLUG");
registerReceiver(receiver, intentFilter)
}
}
You could try keep you workRequest.id on your AudioInputBroadcastReceiver and in case of disconnection you can stop this work. I think its a bad practice cancel all running works if you only want to finish your audio work.
cancelAllWork()
Cancels all unfinished work. Use this method with extreme caution! By invoking it, you will potentially affect other modules or libraries in your codebase. It is strongly recommended that you use one of the other cancellation methods at your disposal.
class AudioInputBroadcastReceiver : BroadcastReceiver() {
val workerRequestId: UUID? = null
#RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context?, intent: Intent?) {
val isConnected = intent!!.getIntExtra("state", 0) === 1
val workManager = WorkManager.getInstance(context!!)
if (isConnected) {
....
val workRequest = OneTimeWorkRequest.Builder(
GetHeadsetUsageTimeWorker::class.java,
).setInputData(data.build()).build()
workerRequestId = workRequest.id
workManager.enqueue(workRequest)
} else {
Toast.makeText(context,"Disconnected",Toast.LENGTH_SHORT).show()
workerRequestId?.let { workManager.cancelWorkById(it) }
}
}
...

How can I pass data (image) from RecyclerView to a separate Activity in Kotlin?

I'm trying to pass data from a RecyclerView that contains a list of photos to a separate Activity that should show Details about the selected photo.
since im new to Kotlin, i've tried a lot and failed to come up with a solution.. I'd be thankful if anyone has a word on this.
PhotosActivity.kt
package com.example.wallpaperapp
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
class PhotosActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_photos)
val recyclerPhotos = findViewById<RecyclerView>(R.id.rv_photo)
recyclerPhotos.layoutManager = LinearLayoutManager(this)
recyclerPhotos.adapter = PhotosAdapter(getPhotosData(), this)
}
private fun getPhotosData(): List<PhotoModel>{
return listOf(
PhotoModel(R.drawable.photo1),
PhotoModel(R.drawable.photo2),
PhotoModel(R.drawable.photo3),
PhotoModel(R.drawable.photo4),
PhotoModel(R.drawable.photo5),
PhotoModel(R.drawable.photo6),
PhotoModel(R.drawable.photo7),
PhotoModel(R.drawable.photo8)
)
}
}
PhotosModel.kt
package com.example.wallpaperapp
import java.io.Serializable
data class PhotoModel(
val image: Int,
): Serializable
PhotosAdapter.kt
package com.example.wallpaperapp
import android.app.Activity
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.recyclerview.widget.RecyclerView
class PhotosAdapter(val listOfPhotos: List<PhotoModel>,
val context: Activity): RecyclerView.Adapter<PhotosAdapter.ViewHolder>() {
inner class ViewHolder(view: View): RecyclerView.ViewHolder(view){
val img = view.findViewById<ImageView>(R.id.img_test)
init{
itemView.setOnClickListener {
val intent = Intent(context, PhotoDetailsActivity::class.java)
intent.putExtra("PHOTO", listOfPhotos[adapterPosition])
context.startActivity(intent)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PhotosAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_photo, parent,false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return listOfPhotos.size
}
override fun onBindViewHolder(holder: PhotosAdapter.ViewHolder, position: Int) {
holder.img.setImageResource(listOfPhotos[position].image)
}
}
PhotoDetailsActivity.kt
package com.example.wallpaperapp
import android.app.WallpaperManager
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.ViewCompat.setBackground
class PhotoDetailsActivity : AppCompatActivity() {
lateinit var arrow: ImageView
lateinit var img: ImageView
lateinit var btn_set: Button
lateinit var bitmap: Bitmap
lateinit var manager: WallpaperManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_photo_details)
val selectedPhoto = intent.extras?.getSerializable("PHOTO") as PhotoModel
arrow = findViewById(R.id.img_arrow)
arrow.setOnClickListener {
val intent = Intent(this, PhotosActivity::class.java)
startActivity(intent)
}
img = findViewById(R.id.img_detail)
btn_set = findViewById(R.id.btn_wallpaper)
btn_set.setOnClickListener(View.OnClickListener {
fun setOnClickr(l: (View) -> Unit){
setBackgroundd()
}
})
}
fun setBackgroundd() {
val bitmap = BitmapFactory.decodeResource(resources, R.layout.activity_photos)
img.setImageBitmap(bitmap)
manager = WallpaperManager.getInstance(getApplicationContext())
manager.setBitmap(bitmap)
}
}
thanks in advance!

Learning Kotlin and stuck with ArrayAdapter

I am learning Kotlin and all was going well until it stopped working, the only thing I changed were the references.
I've tried to adjust the "this" parameter and it has not worked,
Here is my code:
package com.example.myweatherapp
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.ListView
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class ForecastActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_forecast)
var retriever = WeatherRetriever()
val callback = object : Callback<Weather> {
override fun onFailure(call: Call<Weather>?, t: Throwable) {
println("It failed")
}
override fun onResponse(
call: Call<Weather>?, response: Response<Weather>?) {
println("It wORKED")
println(response?.body()?.main)
title = response?.body()?.name
var forecasts = response?.body()?.main
var castListView = findViewById<ListView>(R.id.forecastListView)
var adapter = ArrayAdapter(this#ForecastActivity,android.R.layout.simple_list_item_1,forecasts)
castListView.adapter=adapter
}
}
retriever.getForecast(callback)
}
}
I am getting the following error: "None of the following functions can be called with the arguments supplied:"
Any help for a newbie?
Thanks a lot!
Edit: Here is the weather class
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query
interface weatherAPI{
#GET("weather?id=3621224&units=metric&appid=ff2563aab36fc89bc7a3c4fe58dd7f3e")
fun getForecast() : Call<Weather>
}
class Weather(val main: WeatherForecast, val name: String )
class WeatherForecast (val main: List<main>)
class main (val temp: String, val feels_like: String, val temp_min: String, val temp_max: String)
class WeatherRetriever {
val service : weatherAPI
init {
val retrofit= Retrofit.Builder().baseUrl("https://api.openweathermap.org/data/2.5/").addConverterFactory(GsonConverterFactory.create()).build()
service = retrofit.create(weatherAPI::class.java)
}
fun getForecast(callback : Callback<Weather>){
val call = service.getForecast()
call.enqueue(callback)
}
}

Categories

Resources