1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.core.telecom.test 18 19 import android.R 20 import android.app.Notification 21 import android.app.NotificationChannel 22 import android.app.NotificationManager 23 import android.app.PendingIntent 24 import android.app.Person 25 import android.content.Context 26 import android.content.Intent 27 import android.os.Build 28 import android.util.Log 29 import androidx.annotation.RequiresApi 30 import androidx.core.telecom.util.ExperimentalAppActions 31 32 @ExperimentalAppActions 33 @RequiresApi(Build.VERSION_CODES.S) 34 class NotificationsUtilities { 35 companion object { 36 val TAG: String = NotificationsUtilities::class.java.getSimpleName() 37 val NOTIFICATION_CHANNEL_ID = "CoreTelecomTestVoipApp" 38 val CHANNEL_NAME = "Core Telecom Test Voip App Channel" 39 val CHANNEL_DESCRIPTION = 40 "Core Telecom Test Voip calls will post call-style" + " notifications to this channel" 41 val CALL_STYLE_INITIAL_TEXT: String = "New Call" 42 val CALL_STYLE_ONGOING_TEXT: String = "Ongoing Call" 43 val CALL_STYLE_TITLE: String = "Core-Telecom Test VoIP App" 44 val NOTIFICATION_ACTION_ANSWER = "androidx.core.telecom.test.ANSWER" 45 val NOTIFICATION_ACTION_DECLINE = "androidx.core.telecom.test.DECLINE" 46 val NOTIFICATION_ID = "androidx.core.telecom.test.ID" 47 val IS_ANSWER_ACTION = "androidx.core.telecom.test.IS_ANSWER_ACTION" 48 createInitialCallStyleNotificationnull49 fun createInitialCallStyleNotification( 50 context: Context, 51 uniqueId: Int, 52 channelId: String?, 53 callerName: String?, 54 isOutgoing: Boolean 55 ): Notification { 56 val fullScreenIntent = getDeclinePendingIntent(context, uniqueId) 57 val person: Person = Person.Builder().setName(callerName).setImportant(true).build() 58 return Notification.Builder(context, channelId) 59 .setContentText(CALL_STYLE_INITIAL_TEXT) 60 .setContentTitle(CALL_STYLE_TITLE) 61 .setSmallIcon(R.drawable.sym_def_app_icon) 62 .setStyle(getCallStyle(context, isOutgoing, person, fullScreenIntent, uniqueId)) 63 .setFullScreenIntent(fullScreenIntent, true) 64 .setOngoing(isOutgoing) 65 .build() 66 } 67 getCallStylenull68 private fun getCallStyle( 69 c: Context, 70 isOutgoing: Boolean, 71 person: Person, 72 fullScreenIntent: PendingIntent, 73 notificationId: Int, 74 ): Notification.CallStyle { 75 return if (isOutgoing) { 76 Notification.CallStyle.forOngoingCall(person, fullScreenIntent) 77 } else { 78 Notification.CallStyle.forIncomingCall( 79 person, 80 getDeclinePendingIntent(c, notificationId), 81 getAnswerPendingIntent(c, notificationId) 82 ) 83 } 84 } 85 updateNotificationToOngoingnull86 fun updateNotificationToOngoing( 87 context: Context, 88 notificationId: Int, 89 channelId: String?, 90 callerName: String?, 91 ) { 92 val endCallAction = getDeclinePendingIntent(context, notificationId) 93 val callStyleNotification = 94 Notification.Builder(context, channelId) 95 .setContentText(CALL_STYLE_ONGOING_TEXT) 96 .setContentTitle(CALL_STYLE_TITLE) 97 .setSmallIcon(R.drawable.sym_def_app_icon) 98 .setStyle( 99 Notification.CallStyle.forOngoingCall( 100 Person.Builder().setName(callerName).setImportant(true).build(), 101 endCallAction 102 ) 103 ) 104 .setFullScreenIntent(endCallAction, true) 105 .setOngoing(true) 106 .build() 107 108 val notificationManager = context.getSystemService(NotificationManager::class.java) 109 notificationManager.notify(notificationId, callStyleNotification) 110 } 111 getDeclinePendingIntentnull112 private fun getDeclinePendingIntent(context: Context, notificationId: Int): PendingIntent { 113 return PendingIntent.getActivity( 114 context, 115 notificationId, 116 getDeclineIntent(context, notificationId), 117 PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT 118 ) 119 } 120 getDeclineIntentnull121 private fun getDeclineIntent(c: Context, notificationId: Int): Intent { 122 val declineIntent = 123 Intent(c, CallingMainActivity::class.java).apply { 124 action = NOTIFICATION_ACTION_DECLINE 125 putExtra(NOTIFICATION_ID, notificationId) 126 putExtra(IS_ANSWER_ACTION, false) 127 } 128 declineIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP) 129 return declineIntent 130 } 131 getAnswerPendingIntentnull132 private fun getAnswerPendingIntent(c: Context, notificationId: Int): PendingIntent { 133 return PendingIntent.getActivity( 134 c, 135 notificationId, 136 getAnswerIntent(c, notificationId), 137 PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT 138 ) 139 } 140 getAnswerIntentnull141 private fun getAnswerIntent(c: Context, notificationId: Int): Intent { 142 val answerIntent = 143 Intent(c, CallingMainActivity::class.java).apply { 144 action = NOTIFICATION_ACTION_ANSWER 145 putExtra(NOTIFICATION_ID, notificationId) 146 putExtra(IS_ANSWER_ACTION, true) 147 } 148 answerIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP) 149 return answerIntent 150 } 151 clearNotificationnull152 fun clearNotification(c: Context, notificationId: Int) { 153 val notificationManager = c.getSystemService(NotificationManager::class.java) 154 notificationManager?.cancel(notificationId) 155 } 156 initNotificationChannelnull157 fun initNotificationChannel(c: Context) { 158 val importance = NotificationManager.IMPORTANCE_DEFAULT 159 val channel = 160 NotificationChannel(NOTIFICATION_CHANNEL_ID, CHANNEL_NAME, importance).apply { 161 description = CHANNEL_DESCRIPTION 162 } 163 val nm = c.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 164 nm.createNotificationChannel(channel) 165 } 166 deleteNotificationChannelnull167 fun deleteNotificationChannel(c: Context) { 168 val notificationManager = c.getSystemService(NotificationManager::class.java) 169 try { 170 notificationManager.deleteNotificationChannel(NOTIFICATION_CHANNEL_ID) 171 } catch (e: Exception) { 172 Log.i( 173 TAG, 174 String.format( 175 "notificationManager: hit exception=[%s] while deleting the" + 176 " call channel with id=[%s]", 177 e, 178 NOTIFICATION_CHANNEL_ID 179 ) 180 ) 181 } 182 } 183 } 184 } 185