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