Alarm manager show notification every time when i open the app - kotlin

I am using the requestj api to send and receive the data from server and setting up the alarm on time that i received from server and alarm calls two hours ago from received time but issue is that when alarm fire on exact time it also fire every time when api calls till that 2 hours didn't completed. Any one know how to prevent it?
1.API code is here
fun getAllFriendsReminders(context: Context) {
val getReminderHttpRequest = HttpRequest()
// val myList = ArrayList<FriendsRemindersListModel>()
getReminderHttpRequest.setOnResponseListener { getReminderListResponse ->
Log.e("getReminders List", getReminderListResponse.code.toString())
Log.e("getReminders List", getReminderListResponse.text)
if (getReminderListResponse.code == HttpResponse.HTTP_OK) {
Log.e("getReminders List", getReminderListResponse.code.toString())
val jsonArray = getReminderListResponse.toJSONArray()
getReminderListModel.clear()
Log.e("list", jsonArray.length().toString())
Log.e("list", jsonArray.toString())
val loggedInUser = appGlobals.getValueString("loginUsername")
for (i in 0 until jsonArray!!.length()) {
if (!onForeGround) {
progressBar!!.progress = i
}
Log.e("listi", i.toString())
val jsonObject = jsonArray.getJSONObject(i)
friendReminderText = jsonObject.getString("reminder")
friendReminderFromName = jsonObject.getString("reminder_from")
friendReminderToName = jsonObject.getString("reminder_to")
friendReminderDate = jsonObject.getString("date")
friendReminderStatus = jsonObject.getString("status")
friendReminderId = jsonObject.getString("id")
if (friendReminderFromName != loggedInUser) {
getReminderListModel.add(FriendsRemindersListModel(0, friendReminderId.toInt(),friendReminderText,
friendReminderDate, friendReminderFromName, friendReminderToName, friendReminderStatus))
//Received date time from server
val dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy hh:mm:ss a")
// val dateFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy")
// val timeFormatter = DateTimeFormatter.ofPattern("hh:mm:ss a")
val instant = Instant.ofEpochMilli(friendReminderDate.toLong())
val instant1 = Instant.ofEpochMilli(friendReminderDate.toLong() - (120 * 60 * 1000))
val date = LocalDateTime.ofInstant(instant, ZoneId.systemDefault())
val date1 = LocalDateTime.ofInstant(instant1, ZoneId.systemDefault())
// val exactDate = dateFormatter.format(date)
// val exactTime = timeFormatter.format(date)
val exactDateTime = dateTimeFormatter.format(date)
val alarmDate = Date(friendReminderDate.toLong())
//Current date time
val dates = Date()
val stringFormat = SimpleDateFormat("dd-MM-yyyy hh:mm:ss a")
val dateTimeTo = stringFormat.format(dates.time)
//Set Alarm
if (alarmDate.after(dates)) {
Log.d("D", dates.toString())
Log.d("AlarmDate", alarmDate.toString())
Log.e("2 hour ago", dateTimeFormatter.format(date1))
println(friendReminderDate.toLong() - (120 * 60 * 1000))
Log.e("Set", exactDateTime)
val alarmManager: AlarmManager = context.getSystemService(
AppCompatActivity.ALARM_SERVICE) as AlarmManager
val alarmIntent = Intent(requireContext(), AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Log.e("Alarm", "Alarm")
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(friendReminderDate.toLong() - 120*60*1000,
pendingIntent), pendingIntent)
} else {
Log.e("Alarm1", "${friendReminderDate.toLong() - (120 * 60 * 1000)}")
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
(friendReminderDate.toLong()) - 120 * 60 * 1000,
pendingIntent)
Log.e("Alarm2", "Alarm")
}
}
// if (exactDateTime > dateTimeTo) {
//
// }
}
}
if (friendReminderFromName != loggedInUser) {
if (friendReminderId != "") {
reminder = FriendsRemindersListModel(0, friendReminderId.toInt(), friendReminderText, friendReminderDate,
friendReminderFromName, friendReminderToName, friendReminderStatus)
}
}
if (getReminderListModel.size.toString() > remindersListModel.size.toString()) {
Log.e("serverListSize", getReminderListModel.size.toString())
Log.e("dbListSize", remindersListModel.size.toString())
Log.e("JsonListSize", jsonArray.length().toString())
for (i in 0 until getReminderListModel.size - 1) {
Log.e("present", getReminderListModel[i].reminderId.toString())
var isPresent = false
for (j in 0 until remindersListModel.size - 1) {
Log.e("present", remindersListModel.toString())
if (remindersListModel.isNotEmpty()) {
if (getReminderListModel[i].reminderId == remindersListModel[i].reminderId) {
isPresent = true
}
}
}
Log.e("presenting", "${!isPresent}")
if (isPresent) {
remindersViewModel.addingReminder(reminder)
}
}
}
else if (getReminderListModel.size.toString() < remindersListModel.size.toString()) {
for (i in 0 until remindersListModel.size - 1) {
for (j in 0 until getReminderListModel.size - 1) {
// var isRemoved = false
// Log.e("i's", i.toString())
Log.e("i's", getReminderListModel.size.toString())
Log.e("i'ss", remindersListModel.size.toString())
if (remindersListModel.isNotEmpty()) {
Log.e("delete3", remindersListModel[i].reminderId.toString())
Log.e("delete3", remindersListModel[i].reminderText)
Log.e("delete4", getReminderListModel[j].reminderId.toString())
Log.e("delete4", getReminderListModel[j].reminderText)
if (remindersListModel[i].reminderId != getReminderListModel[i].reminderId ) {
Log.e("delete2", remindersListModel[i].reminderId.toString())
remindersViewModel.deleteReminder(remindersListModel[i].reminderId)
// getReminderListAdapter.notifyItemRemoved(i)
}
}
}
}
}
// if (getReminderListModel.size.toString() != getRemindersDBList.size.toString()) {
// remindersViewModel.deleteReceivedReminders()
// remindersViewModel.addReminder(getReminderListModel)
// }
if (progressBar!= null) {
progressBar!!.visibility = View.GONE
}
}
}
getReminderHttpRequest.setOnErrorListener {
if (progressBar != null) {
progressBar!!.visibility = View.GONE
}
Log.e("getReminders error", "$it")
Log.e("Alarm1", "${friendReminderDate.toLong() - (120 * 60 * 1000)}")
}
val token = appGlobals.getValueString("userToken")
val headers = HttpHeaders("Authorization", "Token $token")
getReminderHttpRequest.get(AppGlobals.GET_REMINDERS_LIST_API, headers)
}
2. Alarm receiver class:
class AlarmReceiver: BroadcastReceiver() {
#RequiresApi(Build.VERSION_CODES.O)
#SuppressLint("UnsafeProtectedBroadcastReceiver")
override fun onReceive(context: Context?, intent: Intent?) {
showNotification(context!!, MessagingServiceFirebase.title, MessagingServiceFirebase.body)
Log.e("Checking notify", "Notification")
// Toast.makeText(context, "Alarm", Toast.LENGTH_SHORT).show()
Log.e("Checking ", "Notification")
// ringTone(context)
}
// private fun ringTone(context: Context) {
// val alert: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)
// val ringtone: Ringtone = RingtoneManager.getRingtone(context, alert)
//
// ringtone.play()
// Toast.makeText(context, "Alarm Called", Toast.LENGTH_SHORT).show()
// }
fun showNotification(ctx: Context, title: String, message: String) {
val notificationManager =
ctx.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = "channel"
val name: CharSequence = "channel"
val description = "The channel"
val importance = NotificationManager.IMPORTANCE_HIGH
val mChannel = NotificationChannel(channelId, name, importance)
mChannel.description = description
mChannel.enableLights(true)
mChannel.lightColor = Color.RED
mChannel.enableVibration(true)
mChannel.vibrationPattern = longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400)
mChannel.setShowBadge(false)
notificationManager.createNotificationChannel(mChannel)
}
val builder: NotificationCompat.Builder = NotificationCompat.Builder(ctx, "channel")
.setSmallIcon(R.drawable.ic_baseline_access_alarm_24)
.setContentTitle(title)
.setContentText(message)
val resultIntent = Intent(ctx, HomeActivity::class.java)
val stackBuilder: TaskStackBuilder = TaskStackBuilder.create(ctx)
stackBuilder.addParentStack(HomeActivity::class.java)
resultIntent.putExtra("NotifyTitle", title)
resultIntent.putExtra("NotifyMessage", message)
stackBuilder.addNextIntent(resultIntent)
val resultPendingIntent: PendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
builder.setContentIntent(resultPendingIntent)
builder.setAutoCancel(true)
notificationManager.notify(12, builder.build())
}
}
3. Manifest code
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver
android:name=".AlarmReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
</intent-filter>
</receiver>

You pull date from the JSON, and set an alarm for 2 hours before that? So if date is 6pm, you set an alarm for 4pm?
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
friendReminderDate.toLong()) - 120 * 60 * 1000, // date - 2hrs
pendingIntent)
If it's 5pm right now, and you set an alarm for 4pm, it will still set, and fire immediately:
If the stated trigger time is in the past, the alarm will be triggered immediately. If there is already an alarm for this Intent scheduled (with the equality of two intents being defined by Intent#filterEquals), then it will be removed and replaced by this one.
So if you only want to set the alarm if now <= alarmTime, and just skip it if now > alarmTime, you need to do that check before you set the alarm.
It looks like you're trying to do that:
if (alarmDate.after(dates)) {
but alarmDate is "date", not "date - 2hrs" (you're using 6pm instead of 4pm):
val alarmDate = Date(friendReminderDate.toLong())
So during that 2-hour period, you're always setting alarms that fire immediately. You need to use your actual alarm time instead:
// seriously, just do this calculation once and refer to the variable
val alarmTime = friendReminderDate.toLong() - (120 * 60 * 1000)
val alarmDate = Date(alarmTime)
You have a lot of date variables piling up in there, it's confusing and hard to tell what's going on - that's probably how this alarmDate bug crept in.
Also just in case, you know your "alarm receiver" also fires and shows a notification when the device boots and when it first unlocks, right?

The (-2hrs) above is only correct, when you are in:
(UTC +1) zone AND there is SUMMER (+1) or
(UTC +2) zone AND there is WINTER (+0)
The correct datetime is in millis (kotlin datetime to millisecond convert using local zone and daylight offset):
val myalarmdatetime: String = "2022-05-31 23:59:59"
val myalarmdatetimemillis: Long =
ZonedDateTime.of(
LocalDateTime.parse(
myalarmdatetime,
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
), ZoneId.systemDefault()
).toInstant().toEpochMilli()

Related

Remove redundant also calls

I'm working with TCP communication and use Ktor library.
I have packets that come, and the first byte is the packet's lengths.
Likewise, I read the packet from what is documented on the protocol API, and sometimes I have to skip the remaining bytes of the packet, so I subtract what I have read to this message length.
At the present time, I call also { messageLength -= length } on each reading, but the code is unreadable.
#Test
fun ktorTests() {
runBlocking {
val selectorManager = SelectorManager(Dispatchers.IO)
val socket = aSocket(selectorManager).tcp().connect("server.slsknet.org", 2242)
val openReadChannel = socket.openReadChannel()
val openWriteChannel = socket.openWriteChannel(autoFlush = true)
val login = "Test"
val pwd = "159753"
openWriteChannel.write {
it.put(
ByteMessage().writeInt32(1)
.writeStr(login)
.writeStr(pwd)
.writeInt32(160)
.writeStr((login + pwd).toMD5())
.writeInt32(1)
.getBuff()
)
}
while (true) {
var messageLength = openReadChannel.readIntLittleEndian()
val code = openReadChannel.readIntLittleEndian()
println("ServerClient received: Message code:" + code + " Packet Size:" + (messageLength + 4))
when (code) {
1 -> {
if (openReadChannel.readBoolean().also { messageLength -= 1 }) {
val greetingLength = openReadChannel.readIntLittleEndian().also { messageLength -= 4 }
val greeting = ByteArray(greetingLength)
openReadChannel.readFully(greeting, 0, greetingLength)
.also { messageLength -= greetingLength }
val ip = openReadChannel.readIntLittleEndian().also { messageLength -= 4 }
println("Logged In.")
}
openReadChannel.discardExact(messageLength.toLong())
}
}
}
Any ideas on ho could it be done ?

Get Address from current location Kotlin

I get the current location like this:
val fusedLocationClient: FusedLocationProviderClient =
LocationServices.getFusedLocationProviderClient(LocalContext.current)
fun getLastKnownLocation() {
fusedLocationClient.lastLocation.addOnSuccessListener { location ->
if (location != null) {
longitude.value = location.longitude
latitude.value = location.latitude
}
}
}
How I can get the Address from it?
Update
I implemented like this:
fun getLastKnownLocation() {
fusedLocationClient.lastLocation.addOnSuccessListener { location ->
if (location != null) {
longitude.value = location.longitude
latitude.value = location.latitude
val geocoder = Geocoder(app)
if (Build.VERSION.SDK_INT >= 33) {
geocoder.getFromLocation(
location.latitude, location.longitude, 1
) { addresses ->
address.value = addresses.first().toString()
}
}
else {
try {
val addresses = geocoder.getFromLocation(location.latitude, location.longitude, 1
)?.firstOrNull()
address.value = addresses.toString()
} catch (Exp: Exception) {
address.value = "No Address found"
println("$Exp")
}
}
}
}
}
But got this exception: java.io.IOException: eccc: DEADLINE_EXCEEDED: deadline exceeded after 4.907678698s
val geocoder = Geocoder(this, Locale.getDefault())
val addresses = geocoder.getFromLocation(location.latitude, location.longitude, 1)
https://developer.android.com/reference/kotlin/android/location/Geocoder

I tried to run this code and every time I run it shows this result

private fun moveMarkerAnimation(key: String, newData: AnimationModel, marker: Marker?, from: String, to: String) {
if (!newData.isRun)
{
compositeDisposable.add(
iGoogleAPI.getDirections(
"driving",
"less_driving",
from, to,
getString(R.string.google_api_key1)
)!!.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { returnResult ->
Log.d("API_RETURN",returnResult,)
try {
val jsonObject = JSONObject(returnResult)
val jsonArray = jsonObject.getJSONArray("routes")
for ( i in 0 until jsonArray.length())
{
val route = jsonArray.getJSONObject(i)
val poly = route.getJSONObject("overview_polyLine")
val polyLine = poly.getString("points")
polylineList = Common.decodePoly(polyLine) as java.util.ArrayList<LatLng?>
}
handler = Handler()
index = -1
next = 1
val runnable = object :Runnable{
override fun run() {
if (polylineList!!.size > 1)
{
if (index< polylineList!!.size)
{
index ++
next = index+1
start = polylineList!![index] !!
end = polylineList!![next]!!
}
val valueAnimator = ValueAnimator.ofInt(0,1)
valueAnimator.duration = 3000
valueAnimator.interpolator = LinearInterpolator()
valueAnimator.addUpdateListener { value ->
v = value.animatedFraction
lat = v*end !!.latitude + (1-v) * start!!.latitude
lng = v*end !!.longitude+ (1-v) * start!!.longitude
val newPos = LatLng(lat,lng)
marker!!.position = newPos
marker!!.setAnchor(0.5f,0.5f)
marker!!.rotation = Common.getBearing(start!!,newPos)
}
valueAnimator.start()
if (index < polylineList!!.size-2)
{
handler!!.postDelayed(this,1500)
}else if (index < polylineList!!.size-1)
{
newData.isRun = false
Common.driversSubscrib.put(key,newData)
}
}
}
}
handler!!.postDelayed(runnable,1500)
}
catch (e:java.lang.Exception){
Snackbar.make(requireView(),e.message!!,Snackbar.LENGTH_LONG).show()
}
When the site changes from from firebase this result appears
022-04-26 13:19:30.912 23482-23482/com.example.bustrackerriderapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.bustrackerriderapp, PID: 23482
io.reactivex.exceptions.OnErrorNotImplementedException: The exception was not handled due to missing onError handler in the subscribe() method call. Further reading
what should I do to fix this problem

Koltin : ACTION_BOND_STATE_CHANGED not returning BluetoothDevice.BOND_BONDED

So I have a device where I need to put in a pin code, this all works however I can't detect when the bond has completed, only when bonding has started.
Android 10
if (action == BluetoothDevice.ACTION_BOND_STATE_CHANGED) {
val state = intent.extras?.get(BluetoothDevice.EXTRA_BOND_STATE) as Int
val device = getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
val previousBondState = getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1)
val bondState = getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1)
val bondTransition = "${previousBondState.toBondStateDescription()} to " +
bondState.toBondStateDescription()
Timber.w("${device?.address} bond state changed | $bondTransition ${state.toBondStateDescription()}")
}
fun listenToBondStateChanges(context: Context) {
context.applicationContext.registerReceiver(
viewModel.btConnectionManager.broadcastReceiver,
IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)
)
}

Cannot format given Object as a Number in Kotlin

An error occurred while using the ConverPrice function as follows for information about the price.
The price of the item in the recycler view adapter onBindViewHolder.
As a result of debugging, the error occurs in the following code.
priceText =
"${dec.format(priceMin)} ~ ${dec.format(priceMax)}"
Please check my code and answer.
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is DataViewHolder -> {
val item = dataList[position]
item.price.let {
holder.price.text = ConvertPrice(item, holder.price)
}
}
}
}
fun ConvertPrice(productDetail: ProductDetail?, tv: TextView? = null, setPrice: Boolean = false): String {
val disableColor = Color.parseColor("#aaaaaa")
val enableColor = Color.parseColor("#3692ff")
tv?.setTextColor(disableColor)
if (ProductDetail != null) {
val priceMin = productDetail.priceMin
val priceMax = productDetail.priceMax
var priceText = ""
val dec = DecimalFormat("##,###")
productDetail.enabledRetail?.let {
if (productDetail.enabledRetail == true) {
if (setPrice) {
priceText = if (priceMin == null || priceMax == null) {
"No pricing information"
} else {
"${dec.format(priceMin)} ~ ${dec.format(priceMax)}"
}
tv?.setTextColor(disableColor)
}
else {
priceText = dec.format(wineDetail.price).toString()
tv?.setTextColor(enableColor)
}
return priceText
} else if (productDetail.cntRating!! > 0) {
if ((priceMin == null && priceMax == null) || (priceMin == 0 && priceMax == 0)) {
priceText = "No pricing information"
} else {
priceText =
"${dec.format(priceMin)} ~ ${dec.format(priceMax)}"
tv?.setTextColor(disableColor)
}
return priceText
}
}
}
return "No pricing information"
}
DecimalFormat.format() only works fine with long or double. You should convert "priceMin" and "priceMax" to Long.
val priceMin = productDetail.priceMin.toLong()
val priceMax = productDetail.priceMax.toLong()
I recommend to use NumberFormat instead of DecimalFormat because it is locale-sensitive
val decFormat = NumberFormat.getInstance() // or getCurrencyInstance()
decFormat.maximumFractionDigits = 3
decFormat.format(priceMin)
decFormat.format(priceMax)