# Push Notifications

To receive push notifications, you'll need to:

1. Configure your [push notification provider](https://getstream.io/docs/platform/push-providers/) in the [Stream Dashboard](https://getstream.io/signin/?product=video).
2. Add the client-side integration for the chosen provider in your app.

We support the following providers:

- [Firebase Cloud Messaging](https://getstream.io/video/docs/android/advanced/incoming-calls/push-providers/firebase/)
- [Huawei Push Kit](https://getstream.io/video/docs/android/advanced/incoming-calls/push-providers/huawei/)
- [Xiaomi Mi Push](https://getstream.io/video/docs/android/advanced/incoming-calls/push-providers/xiaomi/)

We ship an individual artifact for each provider to make client-side integration quick and simple. See their individual documentation pages linked above for setup details.

## Customizing Push Notifications

If you want, you can also customize how push notifications work.

You can customize push notifications in the following ways:

- Adding an `intent-filter`: Lets you choose activities that will be invoked when the Push Notification is handled by the SDK
- Implementing `NotificationHandler`: Lets you fully customize how notifications are shown and dismissed
- Extending our `DefaultNotificationHandler`: Lets you partially customize the behavior or Push Notification received, but reusing some part of our default implementation.

### Adding intent filters in your Android Manifest

You need to create the activities that will be called when the push notification is handled by the SDK and declare an `intent-filter` with the actions they support.

These are the actions that we provide:

- `io.getstream.video.android.action.INCOMING_CALL`: Action used to process an incoming call. The `Activity` that handles this action should show options to accept/reject the call. You can use our [RigningCallContent](https://getstream.io/video/docs/android/ui-components/call/ringing-call/) component to build your screen. This screen can be shown when the device is locked, by adding some arguments in the manifest.
- `io.getstream.video.android.action.OUTGOING_CALL`: Action used to process an outgoing call. The `Activity` that handles this action should show options to cancel the call. You can use our [RigningCallContent](https://getstream.io/video/docs/android/ui-components/call/ringing-call/) component to build your screen.
- `io.getstream.video.android.action.ACCEPT_CALL`: Action used to accept an incoming call. The `Activity` that handles this action should accept the call and show the call screen. You can use our [CallContent](https://getstream.io/video/docs/android/ui-components/call/call-content/) component to build your screen.
- `io.getstream.video.android.action.ONGOING_CALL`: Action used to get back to an already ongoing call. The `Activity` that handles this action should show the call screen. You can use our [CallContent](https://getstream.io/video/docs/android/ui-components/call/call-content/) component to build your screen.
- `io.getstream.video.android.action.LIVE_CALL`: Action used to go into a live call. The `Activity` that handles this action should show the live call screen. You can use our [LivestreamPlayer](https://getstream.io/video/docs/android/ui-cookbook/watching-a-livestream/#livestreamplayer-ui-component) component to build your screen.

These actions need to be included in the `AndroidManifest` file:

```xml {4,8-10,13,17-19,23,25-27,31,34-36,40,42-44}
<manifest>
    <application>
        <activity
            android:name=".IncomingCallActivity"
            android:exported="false"
            android:showOnLockScreen="true"
            android:showWhenLocked="true">
            <intent-filter android:priority="1">
                <action android:name="io.getstream.video.android.action.INCOMING_CALL" />
            </intent-filter>
        </activity>
        <activity
            android:name=".OutgoingCallActivity"
            android:exported="false"
            android:showOnLockScreen="true"
            android:showWhenLocked="true">
            <intent-filter android:priority="1">
                <action android:name="io.getstream.video.android.action.OUTGOING_CALL" />
            </intent-filter>
        </activity>

        <activity
            android:name=".AcceptCallActivity"
            android:exported="false">
            <intent-filter android:priority="1">
                <action android:name="io.getstream.video.android.action.ACCEPT_CALL" />
            </intent-filter>
        </activity>

        <activity
            android:name=".CallActivity"
            android:exported="true"
            android:launchMode="singleTask">
            <intent-filter android:priority="1">
                <action android:name="io.getstream.video.android.action.ONGOING_CALL" />
            </intent-filter>
        </activity>

        <activity
            android:name=".LiveCallActivity"
            android:exported="false">
            <intent-filter android:priority="1">
                <action android:name="io.getstream.video.android.action.LIVE_CALL" />
            </intent-filter>
        </activity>
    </application>
</manifest>
```

>
> **Info:** You can handle multiple `intent-filter` within a single `Activity` if you prefer.
>

Once you have declared your activities in the manifest, including the `intent-filter` for the actions defined previously, your activities will be started when a Push Notification arrives to the device. The `Intent` that your `Activity` will receive contains the `StreamCallId` for the call you need to handle. To obtain the `StreamCallId` we provide an extension function that you can use:

```kotlin {4}
class IncomingCallActivity : AppCompatActivity {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val streamCallId = intent.streamCallId(NotificationHandler.INTENT_EXTRA_CALL_CID)
        [...]
    }
}
```

### Implementing NotificationHandler

The SDK lets you define the theming and behavior of the notification UI that users see after they receive a push notification.
To do this, implement the `NotificationHandler` interface and show your own notification.

**Kotlin**

```kotlin {7-12,15-20,23-27}
class MyNotificationHandler(private val context: Context) : NotificationHandler {
    private val notificationManager: NotificationManager by lazy {
        context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    }

    // Called when a Ringing Call arrives (outgoing or incoming)
    override fun onRingingCall(callId: StreamCallId, callDisplayName: String) {
        val notification = NotificationCompat.Builder(context, notificationChannelId)
            ... // Configure your own notification
            .build()
        notificationManager.notify(notificationId, notification)
    }

    // Called when a Live Call arrives.
    override fun onLiveCall(callId: StreamCallId, callDisplayName: String) {
        val notification = NotificationCompat.Builder(context, notificationChannelId)
            ... // Configure your own notification
            .build()
        notificationManager.notify(notificationId, notification)
    }

    // Called to create the notification for the active call
    override fun getOngoingCallNotification(callId: StreamCallId): Notification? {
        val notification = NotificationCompat.Builder(context, notificationChannelId)
        ... // Configure your own notification
        .build()
        return notification
    }

}
```

**Java**

```java
class MyNotificationHandler implements NotificationHandler {

    NotificationManager notificationManager;

    public MyNotificationHandler(Context context) {
        notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE) ;
    }

    // Called when a Ringing Call arrives.
    @Override
    public void onRingingCall(@NonNull StreamCallId callId, @NonNull String callDisplayName) {
        Notification notification = new NotificationCompat.Builder(context, notificationChannelId)
            ... // Configure your own notification
            .build();
        notificationManager.notify(notificationId, notification);
    }

    // Called when a Live Call arrives.
    @Override
    public void onLiveCall(@NonNull StreamCallId callId, @NonNull String callDisplayName) {
        Notification notification = new NotificationCompat.Builder(context, notificationChannelId)
            ... // Configure your own notification
            .build();
        notificationManager.notify(notificationId, notification);
    }

    // Called when the foreground service is started, to supply the notification
    @Override
    public Notification getOngoingCallNotification(@NonNull StreamCallId callId) {
        Notification notification = new NotificationCompat.Builder(context, notificationChannelId)
            ... // Configure your own notification
            .build();
        return notification;
    }
}
```

Finally, pass as the `NotificationHandler` implementation to the `StreamVideoBuilder` when initializing the Stream Android SDK:

**Kotlin**

```kotlin {1,6}
val notificationHandler = MyNotificationHandler(context)
val notificationConfig = NotificationConfig(
    pushDeviceGenerators = listOf(
        // PushDeviceGenerator
    ),
    notificationHandler = notificationHandler
)

StreamVideoBuilder(
    context = context,
    user = user,
    token = token,
    apiKey = apiKey,
    notificationConfig = notificationConfig,
).build()
```

**Java**

```java
NotificationHandler notificationHandler = new MyNotificationHandler(context)
List<PushDeviceGenerator> pushDeviceGeneratorList = new ArrayList<>();
NotificationConfig notificationConfig = new NotificationConfig(pushDeviceGeneratorList, notificationHandler);

new StreamVideoBuilder(
        context,
        user,
        token,
        apiKey,
        notificationConfig,
    ).build();
```

### Extending DefaultNotificationHandler

Stream Video SDK uses a default implementation of `NotificationHandler` that searches in the application manifest for activities that handle the `action`s that we detailed previously.
If you want to maintain the default behavior and UI for some notifications but modify others, you can extend the `DefaultNotificationHandler` open class and override the behavior of the desired type of notification.

```kotlin
class MyNotificationHandler(application: Application) : DefaultNotificationHandler(application) {

    // Override this method if you want a custom behavior for Ringing call notifications
    override fun onRingingCall(callId: StreamCallId, callDisplayName: String) {
        [...]
    }

    // Override this method if you want a custom behavior for default notifications
    override fun onNotification(callId: StreamCallId, callDisplayName: String) {
        [...]
    }

    // Override this method if you want a custom behavior for Live Call notifications
    override fun onLiveCall(callId: StreamCallId, callDisplayName: String) {
        [...]
    }

    // Override this method if you want a custom notification for ongoing calls
    override fun getOngoingCallNotification(callId: StreamCallId): Notification? {
        [...]
    }
}
```

## Handling Push Notification Permissions

Starting from Android API level 33 (Android 13+), all apps need to [request runtime permissions](https://developer.android.com/develop/ui/views/notifications/notification-permission) to be able to show notifications to the user.

### Runtime Permission Request

For Android 13+ (API level 33+), you need to request the `POST_NOTIFICATIONS` permission:

```kotlin {1,3-7}
import android.Manifest
import android.os.Build
import androidx.activity.result.contract.ActivityResultContracts

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    val permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
        // Permission result handled
    }
    permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
```

Don't forget to add the permission to your `AndroidManifest.xml`:

```xml
<manifest>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
</manifest>
```

### Configuring SDK Permission Behavior

When you integrate Stream Push Notification, our SDK will request permission to post notification whenever it is needed.
If you want to configure this behavior, you can configure it within the `NotificationConfig` class.

```kotlin {7}
val notificationConfig = NotificationConfig(
    pushDeviceGenerators = listOf(
        // PushDeviceGenerator
    ),
    notificationHandler = notificationHandler,
    // This lambda will be called to check if permission needs to be requested by the SDK or not.
    requestPermissionOnAppLaunch = { true }
)
```

---

For the most recent version of this documentation, visit [https://getstream.io/video/docs/android/advanced/incoming-calls/push-notifications/](https://getstream.io/video/docs/android/advanced/incoming-calls/push-notifications/).