How to force the notification to use the Alarmsound and not the Ringtone? - kotlin

My Problem: i have set the notification as an alarm.When the sound on the cellphone is on, the cellphone takes the sound as an alarmsound. But if the cellphone is muted, the cellphone vibrates, but there is no sound./no alarmsound/no ringtone. I cant even see the volume/sound level for the alarm, only the volume of the ringtone is visible on the cellphone.The alarm works fine on different emulator-> So the question is: Is there a way to force the notification to use the Alarmsound and not the Ringtone? An idea would be appreciated.(PS: i have tried it also as a service with notification)Thank you!here is my my code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelImportance = if (playSound) {
NotificationManager.IMPORTANCE_HIGH
} else {
NotificationManager.IMPORTANCE_LOW
}
val audioAttribute = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build()
val notificationSound: Uri =
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)
val notyChannel =
NotificationChannel(channelID, channelName, channelImportance)
notyChannel.enableLights(true)
notyChannel.lightColor = Color.RED
notyChannel.setSound(notificationSound,audioAttribute)
notyChannel.enableVibration(true)
notyChannel.vibrationPattern = longArrayOf(
1000,100,100,100,1000,100,100,100,1000)
this.createNotificationChannel(notyChannel)

this works:
val audio =
context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
if (mode == 0) audio.ringerMode =
AudioManager.RINGER_MODE_SILENT else if (mode == 1) audio.ringerMode =
AudioManager.RINGER_MODE_VIBRATE else if (mode == 2) audio.ringerMode =
AudioManager.RINGER_MODE_NORMAL

Related

How to get filepath for Documents from Uri in android 10 and android 11

I am creating an app where users will upload pdf or doc files.
I have used default file chooser which returns Uri , now i need to upload those selected files to server
Its working fine upto android 9 ,i am facing issues in android 10 and 11 (i have used android:requestLegacyExternalStorage="true" for android 10 )
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
.apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*"
putExtra(Intent.EXTRA_MIME_TYPES, supportedDocumentTypes.keys.toTypedArray())
}
resultLauncher.launch(intent)
In Activity Result
if (data != null) {
var path = ""
val id = data.data?.lastPathSegment!!
val selection = "_id=?"
if (id.startsWith("msf:") && Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
path = FileHelper(requireContext()).getRealPathFromUri(data.data!!.toString()
.replace("msf:","").toUri())!!
}else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q){
path = FileHelper(requireContext()).getRealPathFromUri(data.data!!)!!
}else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
path = getDataColumn(context, MediaStore.Downloads.EXTERNAL_CONTENT_URI,
selection, arrayOf(getPath(data.data!!)))
} else {
data.data?.also { uri ->
path = FileHelper(requireContext()).getRealPathFromUri(uri)!!
}
}
Log.e("Doc Path ::",path)
AppUtils.CustomToast(requireActivity(),path)
uploadDocs(path)
}
For getting Document_ID
private fun getPath(uri : Uri) : String {
val contentResolver = requireActivity().applicationContext.contentResolver
val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
// Check for the freshest data.
contentResolver.takePersistableUriPermission(uri, takeFlags)
val cursor: Cursor? = contentResolver.query(
uri, null, null, null, null, null)
var id = ""
cursor?.use { cursor1 ->
if (cursor1.moveToFirst()) {
val displayName: String = cursor1.getString(cursor1.getColumnIndex(OpenableColumns.DISPLAY_NAME))
Log.i(TAG, "Display Name: $displayName")
val names = cursor1.columnNames.joinToString(",") { it }
Log.e("names ^^^^^",names)
val sizeIndex: Int = cursor1.getColumnIndex(OpenableColumns.SIZE)
val size: String = if (!cursor1.isNull(sizeIndex)) {
cursor1.getString(sizeIndex)
} else { "Unknown" }
Log.i(TAG, "Size: $size")
id = cursor1.getString(cursor1.getColumnIndex(cursor1.columnNames[0]))
Log.e("DocId",id)
}
}
return id
}
Uploading file to server using Retrofit
val builder = MultipartBody.Builder()
builder.setType(MultipartBody.FORM)
val file = File(docPaths)
builder.addFormDataPart("documents", file.name,
RequestBody.create("multipart/form-data".toMediaTypeOrNull(), file))
val requestBody: MultipartBody = builder.build()
I am expecting some code for getting file to upload to server
Thanks In Advance

Alarm manager show notification every time when i open the app

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()

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)
)
}

Setting local variables inside a function for unit testing kotlin

I'm trying to testing a function in android.For the function to be tested ,have to set local variable inside the function. Heres the code:
fun needToBeTested(serviceContext: Context):Int
{
val manager = serviceContext.getSystemService(Context.USB_SERVICE) as UsbManager
val deviceList = manager.deviceList
if(deviceList.size != 0){
val deviceIterator = deviceList.values.iterator()
while (deviceIterator.hasNext()) {
val device = deviceIterator.next()
if ((device != null)&&(device.deviceClass == 255)) { // USB_CLASS_VENDOR_SPEC - HUB
val permitToRead:Boolean = manager.hasPermission(device)
if(permitToRead){
setUpConnection(device,serviceContext)
} else{
manager.requestPermission(device, permissionIntent)
}
deviceConnectionStatus = 1
} else if((device != null) &&(device.deviceClass == 0)){ // USB_CLASS_PER_INTERFACE - USB STICK
}
}
} else (deviceList.size == 0){
connectionStatus = 0
}
}
Test class
class Test {
val mockContext = ApplicationProvider.getApplicationContext<Context>()
#Test
fun needTobeTested_returnOne(){
asserThat(sample.needToBeTested(mockContext)==1) //successcase
}
}
For testing this class,need to set the value of deviceList.Is there any way to set the value of 'x' from the test class for testing this function. Im new to android and testing.Any help would be really helpful.

Using SoundPool for games

class SoundPlayer(context: Context) {
// For sound FX
private val soundPool: SoundPool = SoundPool(10, // Here
AudioManager.STREAM_MUSIC,
0)
companion object {
var playerExplodeID = -1
var invaderExplodeID = -1
var shootID = -1
var damageShelterID = -1
var uhID = -1
var ohID = -1
}
init {
try {
// Create objects of the 2 required classes
val assetManager = context.assets
var descriptor: AssetFileDescriptor
// Load our fx in memory ready for use
descriptor = assetManager.openFd("shoot.ogg")
shootID = soundPool.load(descriptor, 0)
descriptor = assetManager.openFd("invaderexplode.ogg")
invaderExplodeID = soundPool.load(descriptor, 0)
descriptor = assetManager.openFd("damageshelter.ogg")
damageShelterID = soundPool.load(descriptor, 0)
descriptor = assetManager.openFd("playerexplode.ogg")
playerExplodeID = soundPool.load(descriptor, 0)
descriptor = assetManager.openFd("damageshelter.ogg")
damageShelterID = soundPool.load(descriptor, 0)
descriptor = assetManager.openFd("uh.ogg")
uhID = soundPool.load(descriptor, 0)
descriptor = assetManager.openFd("oh.ogg")
ohID = soundPool.load(descriptor, 0)
} catch (e: IOException) {
// Print an error message to the console
Log.e("error", "failed to load sound files")
}
}
fun playSound(id: Int){
soundPool.play(id, 1f, 1f, 0, 0, 1f)
}
}
i have a problem with SoundPool cant use it is says constructor SoundPool is deprecated
i'm kinda new so don't know how to fix this (watched many videos and searched everywhere but i cant fix it)
so maybe someone can help me out tell me what to do
When something is deprecated, there always should be a hint what to use instead.
So you need to use SoundPool.Builder to create new instance of an object.
But there is one issue if you target API level that was release before SoundPool.Builder then you will get ClassNotFoundException.
So general approach is to check the API level and do things in old way before API X(when new feature was introduced), and a new way after API X:
#Suppress("DEPRECATION")
fun buildSoundPool(maxStreams: Int):SoundPool =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val attrs = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build()
SoundPool.Builder()
.setAudioAttributes(attrs)
.setMaxStreams(maxStreams)
.build()
} else {
SoundPool(maxStreams, AudioManager.STREAM_MUSIC, 0)
}
Then:
private val soundPool: SoundPool = buildSoundPool(10)
Also I do recommend to use my custom implementation of SoundPool because lots of platform dependent issues that was introduced in original SoundPool on different versions on Android.