androidkotlinpermissionsnotificationsalarmmanager

Need to show notification at specified time, android kotlin


Created class Notification : BroadcastReceiver():

const val notificationID = 0
const val channelID = "com.example.avnotification.MyUIRoom"
const val titleExtra = "titleExtra"
const val messageExtra = "messageExtra"

class Notification : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d("MyLog", "Notification: onReceive ")
        val activityToOpen = intent.getSerializableExtra("activity") as Class<*>
        //val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        //val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, Intent(context, activityToOpen), PendingIntent.FLAG_IMMUTABLE)
        val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, Intent(context, activityToOpen), 0)
        val notification = NotificationCompat.Builder(context, channelID)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle(intent.getStringExtra(titleExtra))
            .setContentText(intent.getStringExtra(messageExtra))
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)
            .build()
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//            val channel = NotificationChannel(
//                channelID,
//                "Notif Channel",
//                NotificationManager.IMPORTANCE_DEFAULT
//            )
//            notificationManager.createNotificationChannel(channel)
//        }
        val  manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        manager.notify(notificationID, notification)
    }



}

here in this snippet I set the date and time, check permissions and try to see the notification but it doesn't come:

@RequiresApi(Build.VERSION_CODES.O)
    class PanelEditTask : BottomSheetDialogFragment(),  View.OnClickListener{
    private var binding: PanelEditTaskBinding? = null
    private var nameFormParent: String? = ""
    private var taskAction: String? = ""
    private var complet: String? = null

    private var idTask: Int? = null
    private var email: String? = "test"
    private var typeTask: String? = null

    private var taskRepository: TaskRepository? = null
    private var taskViewModel: TaskViewModel? = null
    private var taskFactory: TaskFactory? = null

    private var firstStart: Boolean = true
    private var currentDate = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        LocalDate.now()
    } else {
        TODO("VERSION.SDK_INT < O")
    }


    private val dateFormatter: DateTimeFormatter
    init {
        dateFormatter = DateTimeFormatterBuilder()
            .appendValue(ChronoField.YEAR, 4)
            .appendLiteral('-')
            .appendValue(ChronoField.MONTH_OF_YEAR, 2)
            .appendLiteral('-')
            .appendValue(ChronoField.DAY_OF_MONTH, 2)
            .toFormatter()
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        binding = PanelEditTaskBinding.inflate(inflater, container, false)
        taskAction = arguments?.getString("taskAction").toString()
        nameFormParent = arguments?.getString("nameForm").toString()
        binding?.DateStartTask?.setText(arguments?.getString("dateStart").toString())
        complet = arguments?.getString("completed").toString()
        if (complet == "true"){

            binding?.checkBoxCompleted?.isChecked = true
            binding?.DateEndTask?.setText(arguments?.getString("dateEnd").toString())
        }
        else {
            binding?.DateEndTask?.setText(getString(R.string.enter_end_start))
            binding?.checkBoxCompleted?.isChecked = false}
        if(taskAction == "Edit") {
            idTask = arguments?.getString("idTask")?.toInt()
            binding?.editNameTask?.setText(arguments?.getString("nameTask").toString())
            email = arguments?.getString("email")?.toString()
            typeTask = arguments?.getString("typeTask")?.toString()
            binding?.editInfoTask?.setText(arguments?.getString("infoTask").toString())

        }
        else{
            val sharedPreferences = requireContext().getSharedPreferences("MyPrefs", Context.MODE_PRIVATE)
            val savedValue = sharedPreferences.getString("email", "default value")
            if(savedValue != "default value") {
                email = savedValue
            }
        }

        val taskDao = Database.getInstance((context as FragmentActivity).application).taskDao
        taskRepository = TaskRepository(taskDao)
        taskFactory = TaskFactory(taskRepository!!)
        taskViewModel = ViewModelProvider(this, taskFactory!!).get(TaskViewModel::class.java)
        spinerProcessing()


       // createNotification()
        binding?.finishEdit?.setOnClickListener(this)


        binding?.checkBoxCompleted?.setOnCheckedChangeListener{ buttonView, isChecked ->
          if(isChecked){
              binding?.DateEndTask?.setText(currentDate.toString())
          }

          else {
              binding?.DateEndTask?.setText(getString(R.string.enter_end_start))}
        }

        binding?.DateEndTask?.setOnClickListener{
            showDatePickerDialog("End")
        }

        binding?.DateStartTask?.setOnClickListener{
            showDatePickerDialog("Start")
        }
        createNotification()
        binding?.greateNotif?.setOnClickListener{scheduleNotification()}

        return binding?.root
    }

    private fun createNotification() {
        val name = "Notif Channel"
        val desc = "A description of the Channel"
        val importance = NotificationManager.IMPORTANCE_HIGH
        val channel = NotificationChannel(channelID, name, importance)
        channel.description = desc

        // Set notification sound

        channel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), null)
        channel.enableVibration(true)
        channel.enableLights(true)
        val notificationManager = requireContext().getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        notificationManager?.createNotificationChannel(channel)


    }


    @RequiresApi(Build.VERSION_CODES.O)
    private fun showDatePickerDialog(type:String) {
        val calendar = Calendar.getInstance()
        val year = calendar.get(Calendar.YEAR)
        val month = calendar.get(Calendar.MONTH)
        val day = calendar.get(Calendar.DAY_OF_MONTH)

        var dateTextView: AppCompatTextView? = null

        if(type == "End"){
        dateTextView = binding?.DateEndTask as AppCompatTextView
        }
        else if(type == "Start"){
            dateTextView = binding?.DateStartTask as AppCompatTextView
        }

        if(dateTextView != null) {
            val datePickerDialog = DatePickerDialog(
                context as FragmentActivity,
                { _, selectedYear, selectedMonth, selectedDay ->
                    val selectedDate = LocalDate.of(selectedYear, selectedMonth + 1, selectedDay)
                    val formattedDate = selectedDate.format(dateFormatter)
                    dateTextView.setText(formattedDate)
                },
                year,
                month,
                day
            )

            datePickerDialog.show()
        }
//                { _, selectedYear, selectedMonth, selectedDay ->
//                    val selectedDate = "$selectedYear-${selectedMonth + 1}-$selectedDay"
//                    dateTextView.setText(selectedDate)
//                },

    }

    fun spinerProcessing(){
        val taskTypeSpinner = binding?.taskTypeSpinner
        val taskTypes = resources.getStringArray(R.array.type)
        val adapter = ArrayAdapter(context as FragmentActivity, android.R.layout.simple_spinner_item, taskTypes)
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        taskTypeSpinner?.adapter = adapter

        if (firstStart && typeTask != null){
            val position = adapter.getPosition(typeTask)
            taskTypeSpinner?.setSelection(position)
            firstStart = false
        }

        taskTypeSpinner?.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
            override fun onItemSelected(
                parent: AdapterView<*>?,
                view: View?,
                position: Int,
                id: Long
            ) {
                typeTask = parent?.getItemAtPosition(position).toString()
            }

            override fun onNothingSelected(parent: AdapterView<*>?) {
                TODO("Not yet implemented")
            }

        }

    }

    override fun onClick(view: View) {

        if(binding?.checkBoxCompleted?.isChecked == true){
            complet = "true"
        }
        else{
            complet = ""
        }
    if(binding?.editNameTask?.text?.toString()!!.isNotEmpty() and
        email.toString().isNotEmpty() and typeTask.toString().isNotEmpty() and
        binding?.editInfoTask?.text?.toString()!!.isNotEmpty() and
        binding?.DateStartTask?.text?.toString()!!.isNotEmpty() and
        binding?.DateEndTask?.text?.toString()!!.isNotEmpty()) {


    if (nameFormParent == "TaskAll" && taskAction != "Edit") {

    taskViewModel?.startInsert(binding?.editNameTask?.text?.toString()!!,
        email.toString(), typeTask.toString(),binding?.editInfoTask?.text?.toString()!!,binding?.DateStartTask?.text?.toString()!!,
        binding?.DateEndTask?.text?.toString()!!, complet.toString())
        dismiss()
        (context as FragmentActivity).supportFragmentManager.beginTransaction().replace(R.id.content, TaskAll()).commit()
    }
        else if(nameFormParent == "TaskAll" && taskAction == "Edit"){
            if(idTask != null) {
                taskViewModel?.startUpdateTask(
                    idTask?.toInt()!!,
                    binding?.editNameTask?.text?.toString()!!,
                    email.toString(),
                    typeTask.toString(),
                    binding?.editInfoTask?.text?.toString()!!,
                    binding?.DateStartTask?.text?.toString()!!,
                    binding?.DateEndTask?.text?.toString()!!,
                    complet.toString()
                )
            }
        dismiss()
        (context as FragmentActivity).supportFragmentManager.beginTransaction().replace(R.id.content, TaskAll()).commit()
        }
    else if(nameFormParent == "TaskForType" && taskAction == "Edit"){
        if(idTask != null) {
            taskViewModel?.startUpdateTask(
                idTask?.toInt()!!,
                binding?.editNameTask?.text?.toString()!!,
                email.toString(),
                typeTask.toString(),
                binding?.editInfoTask?.text?.toString()!!,
                binding?.DateStartTask?.text?.toString()!!,
                binding?.DateEndTask?.text?.toString()!!,
                complet.toString()
            )
        }
        dismiss()
        (context as FragmentActivity).supportFragmentManager.beginTransaction().replace(R.id.content, TaskForType()).commit()
    }
       else if (nameFormParent == "TaskForType" && taskAction != "Edit") {

            taskViewModel?.startInsert(binding?.editNameTask?.text?.toString()!!,
                email.toString(), typeTask.toString(),binding?.editInfoTask?.text?.toString()!!,binding?.DateStartTask?.text?.toString()!!,
                binding?.DateEndTask?.text?.toString()!!, complet.toString())
            dismiss()
            (context as FragmentActivity).supportFragmentManager.beginTransaction().replace(R.id.content, TaskForType()).commit()
        }

   //     scheduleNotification()
}
        else
        Toast.makeText(context, getString(R.string.error), Toast.LENGTH_SHORT).show()

    }

    @RequiresApi(Build.VERSION_CODES.M)
    private fun scheduleNotification() {

        Log.d("MyLog", "scheduleNotification: ")
        val intent = Intent(requireContext(), Notification::class.java)
        val title = binding?.editNameTask?.text.toString()
        val message = getString(R.string.close_task)
        intent.putExtra(titleExtra, title)
        intent.putExtra(messageExtra, message)
        intent.putExtra("activity", MainActivity::class.java)

        val pendingIntent = PendingIntent.getBroadcast(
            requireContext(),
            notificationID,
            intent,
            PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
        )
        val alarmManager = requireContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val time = getTime()
        val result_SCHEDULE = requireContext().checkCallingOrSelfPermission("android.permission.SCHEDULE_EXACT_ALARM")
        Log.d("MyLog", "test SCHEDULE_EXACT_ALARM, premission $result_SCHEDULE ")
        val result_POST = requireContext().checkCallingOrSelfPermission("android.permission.POST_NOTIFICATIONS")
        Log.d("MyLog", "test result_POST, premission $result_POST ")
        //alarmManager.set(AlarmManager.RTC_WAKEUP, time, pendingIntent)
            alarmManager.setExactAndAllowWhileIdle(
                AlarmManager.RTC_WAKEUP,
                time,
                pendingIntent
            )


           showAlert(time, title, message)


    }

    private fun showAlert(time: Long, title: String, message: String) {
        val date = Date(time)
        val dateFormat = android.text.format.DateFormat.getLongDateFormat(requireContext())
        val timeFormat = android.text.format.DateFormat.getTimeFormat(requireContext())

        AlertDialog.Builder(context as FragmentActivity)
            .setTitle("Notification Scheuled")
            .setMessage(
                "Title: " + title +
                        "\nMessage: " + message +
                        "\nAt: " + dateFormat.format(date) + " " + timeFormat.format(date)
            )
            .setPositiveButton("Okay"){_,_ ->}
            .show()
    }

    private fun getTime(): Long {
        val minute = binding?.timePicker?.minute
        val hour = binding?.timePicker?.hour
        val day = binding?.datePicker?.dayOfMonth
        val month = binding?.datePicker?.month
        val year = binding?.datePicker?.year

        val calendar = Calendar.getInstance()
        calendar.set(year!!, month!!,day!!,hour!!,minute!!)
        return calendar.timeInMillis

    }
}

AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.myuiroom">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyUIRoom"
        tools:targetApi="31"
        android:usesCleartextTraffic="true">
        <receiver
            android:name=".notices.Notification"/>
        <activity
            android:name=".MainActivity"
            android:screenOrientation="portrait"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

I have set permissions for this app in my phone, help, where could be the problem?

Everything I've done : I simplified the code, just calling the notification on the button press, and removed the activity passing

        private fun testNotification() {

        Log.d("MyLog", "scheduleNotification: ")
        val intent = Intent(requireContext(), Notification::class.java)
        val title = binding?.editNameTask?.text.toString()
        val message = getString(R.string.close_task)
        intent.putExtra(titleExtra, title)
        intent.putExtra(messageExtra, message)
        requireContext().sendBroadcast(intent)

    }

I wrote in BroadcastReceiver itself, the call of my fragment, but still in the log does not appear an entry on the

line Log.d("MyLog", "Notification: onReceive ").
    const val notificationID = 0
const val channelID = "com.example.avnotification.MyUIRoom"
const val titleExtra = "titleExtra"
const val messageExtra = "messageExtra"

class Notification : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d("MyLog", "Notification: onReceive ")

        val openFragmentIntent = Intent(context, MainActivity::class.java).apply {
            putExtra("openFragment", "TaskForType")
        }
        val pendingIntent = PendingIntent.getActivity(
            context,
            0,
            openFragmentIntent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
        val notification = NotificationCompat.Builder(context, channelID)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle(intent.getStringExtra(titleExtra))
            .setContentText(intent.getStringExtra(messageExtra))
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)
            .build()

        val  manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        manager.notify(notificationID, notification)
    }
}

Solution

  • found the answer. Everything is fine in the code, I created a Notification class earlier for BroadcastReceiver. In the standard libraries there is the same class, instead of my class I imported it "import android.app.Notification", instead of my class I imported it "import com.example.myuiroom.Notification". And everything worked at once.