package com.example.sergey.notify import android.app.Notification import android.app.NotificationManager import android.app.PendingIntent import android.content.Intent import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.support.v4.app.NotificationCompat import android.view.View import android.app.NotificationChannel import android.content.Context import android.graphics.Color import android.provider.Settings import android.util.Log class MainActivity : AppCompatActivity() { var notificationID = 1 var channelId : String = "" // set in createChannel, only used in API >= 26 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) createChannel() } fun onClick(view: View) { displayNotification() } private fun displayNotification() { // Intent to launch another activity if the user clicks // this notification. To be wrapped in a PendingIntent, because // it will be sent from whatever activity manages notifications; // this activity may not even be running. // ---So I had a weird bug that took me hours to understand. // These do NOT work, because they produce an _implicit_ intent with the string // argument taken to be the name of the action! E.g., // Intent { act=class com.example.sergey.notify.NotificationActivity } // This intent simply gets lost, the intended activity never gets called. // // val i : Intent = Intent( NotificationActivity::class.toString() ) // val i : Intent = Intent( NotificationActivity::class.java.toString() ) // // This was a sneaky typo, because it made this intent look explicit, although it wasn't! // ---end bug // This creates an explicit intent and works: // Note that we need to pass a Java class, not a Kotlin class, to match the API's signature, // which requires a Java class val i : Intent = Intent(this, NotificationActivity::class.java ) // This works too, and produces Intent { cmp=com.example.sergey.notify/.NotificationActivity } //val i : Intent = Intent() //i.setClass(this, NotificationActivity::class.java) // If we wanted to send an implicit intent, we'd need to match the intent-filter // of NotificationActivity in the Manifest. This would result in many apps // being offered up, because this implicit intent matches almost any app's filters. //val i = Intent() //i.setAction(Intent.ACTION_MAIN) //i.addCategory(Intent.CATEGORY_DEFAULT) Log.d("INTENT", i.toString()) i.putExtra("notificationID", notificationID) val pendingIntent : PendingIntent = PendingIntent.getActivity(this, 0, // on some SDK versions, the code should NOT be 0, or else it won't work i, 0) // flags are important, see https://developer.android.com/reference/android/app/PendingIntent.html val nm : NotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager // Using the approved constructor for 26, which mandates that Channels be used; // the older channel-less constructor is deprecated. val notiBuilder = if ( android.os.Build.VERSION.SDK_INT >= 26 ) Notification.Builder(this, channelId) else Notification.Builder(this) notiBuilder.setSmallIcon(R.mipmap.ic_launcher) .setContentTitle("Meeting Reminder") .setContentText("Reminder: Meeting starts in 5 minutes") .setContentIntent(pendingIntent) // .setAutoCancel(true) --if not set, the notification needs to be // cancelled explicitly, or else it sticks in the notification bar. // See cancellation logic in NotificationActivity. val n = notiBuilder.build() // API >= 16, otherwise use NotificationCompat // Sound & vibration: // This is deprecated, but works on API < 26 to vibrate & chime. // For API >= 26, these settings belong on the Channel, not on the Notification or Builder; // see createChannel() below. n.defaults = n.defaults or Notification.DEFAULT_VIBRATE n.defaults = n.defaults or Notification.DEFAULT_SOUND // OR these, also deprecated: //notiBuilder.setVibrate(longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400)) //notiBuilder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI); nm.notify(notificationID, n) } // https://stackoverflow.com/questions/45668079/notificationchannel-issue-in-android-o // http://www.vogella.com/tutorials/AndroidNotifications/article.html private fun createChannel() { if (android.os.Build.VERSION.SDK_INT >= 26) { val mNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager // The id of the channel. channelId = "my_channel_01" // The user-visible name of the channel. Look for it in Android's configs! val name = getString(R.string.channel_name) // The user-visible description of the channel. val description = getString(R.string.channel_description) val importance = NotificationManager.IMPORTANCE_LOW val mChannel = NotificationChannel(channelId, name, importance) // Configure the notification channel. mChannel.description = description mChannel.enableLights(true) // Sets the notification light color for notifications posted to this // channel, if the device supports this feature. mChannel.lightColor = Color.RED // Sets vibration if the device supports it mChannel.enableVibration(true) mChannel.vibrationPattern = longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400) mNotificationManager.createNotificationChannel(mChannel) } } }