# Enabling seamless cross-device interactions
- Speakers: Yacine Rezgui (Developer Relations Engineer), Hanrui Gao (Developer Relations Engineer), Nataraj K R (Developer Relations Engineer)
- Track: Apps foundation
- Video: https://www.youtube.com/watch?v=2-EfHHa_NxE
- Page: https://developer.android.com/events/dev-summit/talks/enabling-seamless-cross-device-interactions
## About the talk
As users move between phones, wearables, and audio peripherals, delivering fluid cross-device experiences has become essential for engagement. However, relying on standard networking approaches often leads to battery drain, latency spikes, and fragmented user sessions.
This deep dive introduces specialized Android APIs built for multi-device communication, offering memory- and power-efficient patterns to keep transitions between devices instant, reliable, and intuitive.
## Summary
- Companion Device Manager replaces foreground services for Bluetooth peripherals by waking apps based on presence and managing connections without draining battery. Android 17 adds new profiles specifically for medical devices and fitness trackers.
- Jetpack Telecom acts as a system call coordinator for VoIP apps across connected devices like watches and cars, working back to Android 8. It also synchronizes mute and hangup actions via CallControlScope.
- Upcoming Jetpack Telecom 1.1.0 features include unified call histories in the system dialer (SDK 36.1+) and automatic 5G network slicing on supported carrier networks.
- Quick Share SDK is launching next year so developers can embed local, end-to-end encrypted file sharing directly into Android and iOS apps. Tap to share (launched with Pixel 11) can even automatically wake a closed receiving app.
## Resources
- [Devices per person in 2023 chart](https://www.statista.com/chart/32691/average-number-of-devices-and-connections-per-capita/)
## Topics
cross-device, companion-device-manager, jetpack-telecom, quick-share, bluetooth, voip, peer-to-peer
## Transcript
### Introduction to cross-device interactions
[00:05](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=5s) Hi, everyone.
[00:06](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=6s) Welcome to Enabling Seamless Cross-Device Interactions.
[00:11](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=11s) I'm Hanrui, and today I'm joined by my colleagues, Yacine and Nataraj.
[00:17](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=17s) When we talk about connectivity, what often comes to mind is a basic network link or Bluetooth headsets.
[00:24](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=24s) On Android, connectivity is much broader than that.
[00:28](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=28s) It's really about making devices work better together.
[00:33](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=33s) Today, we will walk through common cross-device scenarios and show you which API is right for each one.
[00:41](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=41s) For quite a long time, we used to build apps for a single device, phone only.
[00:48](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=48s) Then wearables took off.
[00:50](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=50s) Soon it became very common to have a smartwatch paired with a phone, syncing data in the background or taking calls directly.
[01:00](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=60s) Add ear-- add wireless earbuds.
[01:03](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=63s) Now, users switch audio device mid-call, from watch to phone to earbuds or over to their cars.
[01:11](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=71s) More recently, many users also carry a second big screen device, like a foldable or tablet.
[01:18](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=78s) They expect the app to work smoothly across these devices.
[01:24](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=84s) And that extends to laptops and Chromebooks, where user can run Android apps and stay connected right from their desk.
[01:34](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=94s) Even back in 2023, an average user owned between three to four devices.
[01:40](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=100s) Users expect more than just standalone functionality on these devices.
[01:46](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=106s) They look for an extraordinarily better-together experience.
[01:50](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=110s) That better-together experience is especially clear when people are in the same room like us today and want an easy way to share photos, links, or apps to the people next to them.
[02:06](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=126s) Looking at the numbers, the ecosystem is huge and growing fast.
[02:12](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=132s) In this year, there are around 22 billion IoT devices worldwide, growing 14% year-over-year.
[02:19](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=139s) And among all these end points, Wi-Fi makes up a third and Bluetooth makes up a quarter.
[02:28](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=148s) Cross-device connectivity is no longer an edge case.
[02:32](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=152s) It's part of our everyday life.
[02:35](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=155s) Yet today, most apps still build their cross-device features on low-level network and Bluetooth APIs, which creates three challenges.
[02:45](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=165s) First, battery and memory.
[02:48](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=168s) Keeping background scans and services running drains battery and memory.
[02:53](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=173s) Second, latency.
[02:55](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=175s) Unpredictable delays disrupt real-time calls and data sync.
[03:00](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=180s) And third, connection friction.
[03:02](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=182s) Managing discovery, pairing, and reconnection across all devices is complex and easily leads to broken user experience.
[03:12](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=192s) To get rid of those headaches, we've built purpose-built APIs across three major areas to make cross-device features really simple.
[03:22](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=202s) I'll start with companion apps, and then Nataraj will cover VoIP apps, and later Yacine will talk about P2P sharing.
### Overview of companion apps
[03:32](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=212s) Let's take a look at companion apps first.
[03:35](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=215s) A companion app is an app you install on your phone so that a companion device, like a smartwatch or glucose sensor, can work well with it.
[03:46](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=226s) In this section, we will focus on Bluetooth-connected devices.
[03:51](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=231s) There are typically four categories of companion devices.
[03:55](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=235s) First, medical devices, like glucose sensors and vital signs monitors.
[04:02](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=242s) And wearables, like smartwatch and fitness bands.
[04:08](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=248s) Headsets, with Fast Pairing and smart controls.
[04:11](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=251s) And car kits, for things like digital car keys and hands-free calling.
[04:18](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=258s) Each category has its own key user journeys, but for all of them, they all depend on a reliable connection between the device and the phone.
[04:28](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=268s) For medical devices, that connection can even be life-critical.
[04:33](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=273s) Let's walk through four common needs we see across these categories.
[04:38](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=278s) First, device management.
[04:41](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=281s) The app needs to find the right device among everything nearby, like the watch here, not the earbud or the speaker, and then start the pairing flow to connect.
[04:54](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=294s) Second, presence checking.
[04:56](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=296s) The app needs to know when the device is nearby and when it's gone.
[05:00](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=300s) And when the device shows up, the app needs a way to be woken up so it can do its job even the user hasn't opened it.
[05:11](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=311s) Third, connection maintenance.
[05:13](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=313s) Once connected, apps want the connection to be reliable and persistent.
[05:20](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=320s) If the connection drops, say the user walks out of range and then comes back, the app needs to reconnect automatically, even it is not running at that time.
[05:33](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=333s) And fourth, data sync and transfer.
[05:37](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=337s) This is where the real value is.
[05:40](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=340s) Syncing sensor readings, pushing firmware updates, or sending settings to the device.
[05:46](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=346s) For medical devices, this can be critical.
[05:50](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=350s) A missed reading can mean a missed alert.
[05:54](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=354s) All of these need the app process to be alive and connected at the right time.
[06:02](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=362s) So, how have apps met all these needs?
[06:05](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=365s) Traditionally, apps relied heavily on foreground service.
[06:10](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=370s) Here is a typical implementation.
[06:12](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=372s) If you have ever built a companion app before, this may look familiar.
[06:17](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=377s) You declare Bluetooth scan and connect permissions, foreground service permissions, and foreground service type of connected device, and then notification permission because a foreground service has to show a persistent notification.
```xml
```
[06:34](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=394s) Then you run a sticky service to keep the app process alive.
```kotlin
class BleForegroundService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
…
return START_STICKY
}
}
```
[06:39](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=399s) You know, this works, but it costs battery and memory because the service runs all the time, even when the device is not nearby.
[06:52](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=412s) That's why we build Companion Device Manager, or CDM in short.
[06:57](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=417s) First, it can wake up your app based on device presence, and as long as the device stays in range, the system will keep your app process alive.
[07:06](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=426s) No foreground service needed.
[07:09](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=429s) Second, CDM supports device profiles.
[07:13](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=433s) With a device profile, the user grants all the permissions your app needs with a single tap instead of a chain of permission dialogs.
[07:23](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=443s) This greatly improves user experience and conversion rate.
[07:29](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=449s) The watch profile has been available since Android 12, glasses since Android 14.
[07:35](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=455s) In Android 17, we've added two new profiles specifically for medical device and fitness trackers.
[07:43](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=463s) There are also some privileged profiles for system apps only today.
[07:48](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=468s) If we hear a broader need from the ecosystem, we may consider opening them up to more developers.
### Implementation using Companion Device Manager
[07:57](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=477s) Using CDM is really easy.
[08:00](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=480s) Let's use a medical device as an example.
[08:03](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=483s) First, declare the necessary permissions: one for medical device, one to run in background, and one to observe device presence.
```xml
```
[08:13](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=493s) One thing to call out, unlike the permissions we just saw with foreground service implementation, all the permissions listed here, they are normal permissions, meaning they will be granted at install, no prompt dialog.
[08:29](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=509s) The only thing the user has to approve is the association.
[08:35](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=515s) Let's see how to create that association.
[08:38](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=518s) Here we build an association request with a device filter so only the right device shows up.
```kotlin
val paringRequest = AssociationRequest.Builder()
.addDeviceFilter(deviceFilter)
.setSingleDevice(true)
.setDeviceProfile(AssociationRequest.DEVICE_PROFILE_MEDICAL)
.build()
companionDeviceManager.associate(paringRequest, ContextCompat.getMainExecutor(this),
object : CompanionDeviceManager.Callback() {
override fun onAssociationPending(intentSender: IntentSender) {
intentSenderLauncher.launch(IntentSenderRequest.Builder(intentSender).build())
}
override fun onAssociationCreated(associationInfo: AssociationInfo) { … }
override fun onFailure(error: CharSequence?) { … }
}
)
```
[08:46](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=526s) `setSingleDevice` to true because we only want one match, and set the profile to medical.
[08:54](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=534s) Then call associate.
[08:56](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=536s) CDM handles the scanning.
[08:59](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=539s) In `onAssociationPending`, we will get an `IntentSender`.
[09:03](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=543s) Launch it, the system shows an association dialog.
[09:08](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=548s) With a medical profile, this one tap here not only approves the association itself, it also grants all the permissions the profile needs, even bypassing Do Not Disturb, which is critical for critical alerts.
[09:24](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=564s) Once user tap on Allow, we will get on `onAssociationCreated` with `AssociationInfo`, which includes an asso-- an association ID.
[09:37](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=577s) Then we can observe device pres-- then we can observe device presence by calling startObservingDevicePresence with that association ID.
[09:47](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=587s) And you also need to implement a service that extends `CompanionDeviceService`.
```kotlin
class BleCompanionDeviceService : CompanionDeviceService() {
override fun onDevicePresenceEvent(event: DevicePresenceEvent) {
when (event.event) {
DevicePresenceEvent.EVENT_BLE_APPEARED -> onDeviceAppeared(event.associationId)
DevicePresenceEvent.EVENT_BLE_DISAPPEARED -> onDeviceDisappeared(event.associationId)
}
}
private fun onDeviceAppeared(associationId: Int) { … }
private fun onDeviceDisappeared(associationId: Int) { … }
}
```
[09:52](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=592s) When the device comes into range, the system binds to your service even if your app isn't running.
[09:59](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=599s) And the system will call `onDevicePresenceEvent` with `EVENT_BLE_APPEARED`.
[10:06](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=606s) Then you can connect and sync.
[10:09](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=609s) When the device leaves, you will get `EVENT_BLE_DISAPPEARED`.
[10:13](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=613s) Then, you can do the cleanup.
[10:15](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=615s) No always-on service and no notification just to stay alive.
[10:22](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=622s) Now, we have to admit CDM does have a few limitations that developers have to keep in mind.
[10:28](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=628s) First, OS versions.
[10:30](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=630s) Most CDM features arrived in Android 12 and 13.
[10:34](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=634s) But some cool improvements landed in Android 16 and the new profiles in Android 17.
[10:41](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=641s) So, check the OS version at runtime and keep a fallback for older versions.
[10:47](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=647s) That said, Target SDK goes up every year and min SDK tends to follow.
[10:53](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=653s) To tackle the memory pressure apps are facing now and will face, we highly encourage apps to migrate from foreground service to CDM as soon as possible.
[11:04](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=664s) And if you have a use case that cannot be supported by CDM today, let us know.
[11:11](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=671s) Second, today, CDM supports background scanning, but not background advertising.
[11:17](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=677s) We rarely hear a need for this.
[11:19](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=679s) But if your app needs the phone to act as a peripheral and advertise continuously in the background, we'd be happy to learn more about it.
[11:30](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=690s) Third, CDM uses low-power scan mode.
[11:34](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=694s) It trades a bit of real-time responsiveness for battery and memory.
[11:38](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=698s) So, don't expect instant wakeups.
[11:42](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=702s) Finally, no payload peeking.
[11:45](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=705s) You cannot register for a specific characteristic or advertisement data.
[11:51](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=711s) But once the device is in range, your app gets woken up.
[11:56](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=716s) So, it can connect and check the payload as needed.
[12:00](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=720s) That's all about companion apps and CDM.
[12:03](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=723s) I'll hand it over to Nataraj for VoIP apps.
### Challenges with cross-device VoIP calls
[12:06](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=726s) CompanionDeviceManager is the right tool if your app owns a dedicated peripheral and continuously talk over it.
[12:19](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=739s) Hello, everyone.
[12:20](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=740s) I'm Nataraj K R.
[12:21](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=741s) Now, I'll talk about the next cross-device scenario, which is real-time calling.
[12:28](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=748s) Nowadays, how people handle calls is changing.
[12:32](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=752s) More than 40% of the calls are happening over VoIP networks.
[12:37](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=757s) And Android is playing a major part in that.
[12:41](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=761s) In fact, 71% of those calls are happening on Android devices, which is like every other call.
[12:47](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=767s) It's not just the calls.
[12:49](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=769s) The ecosystem of devices people are owning is also growing massively.
[12:55](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=775s) There are over 250 million plus cars with Android Auto running on the roads out there, and we're also shipping more than a billion Bluetooth devices to the users.
[13:09](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=789s) Earbuds, Wear OS watches, Android-- cars with Android Auto, Bluetooth speakers are all the devices users are owning around the phone, and they want their call to flow across all these devices seamlessly.
[13:26](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=806s) For example, user would get a call, they would take take a glance at their watch to know the caller information.
[13:33](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=813s) They would answer the call on their watch.
[13:36](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=816s) They would mute or unmute as necessary, and they would pop in their earbuds, continue their call.
[13:43](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=823s) If they want to go out, they would pop into their call-- they would pop into their car, and they would expect their call to seamlessly switch to car's cabin.
[13:53](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=833s) So, this has become a normal routine for the user, and this is no premium experience.
[13:59](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=839s) User for a user, this is a basic requirement, and it's on us Android developers to provide that seamless experience in our VoIP apps to the users.
[14:12](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=852s) But if you try to build this all by yourself from scratch, you would end up with three major problems.
[14:19](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=859s) One, fragmentation with Blue-- Bluetooth sockets.
[14:25](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=865s) Because system does not know that your call is handling a call, you would end up building custom Bluetooth sockets and custom media sessions so that your call can be projected onto the watch or Android Auto.
[14:40](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=880s) The second problem is audio focus.
[14:43](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=883s) Because you have to deal with low-level AudioManager APIs and Bluetooth APIs, audio leaks happen, and it's not a priority for the system, right?
[14:54](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=894s) Your app having a VoIP call, so whenever a carrier call comes in, it interrupts, and modem seizes the audio, leaving your app with no audio.
[15:03](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=903s) Worst, whenever the call Even though the call cellular call ends, audio focus won't be returned back to your app.
[15:10](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=910s) And the third problem is synchronization.
[15:14](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=914s) User would tap mute on their watch, but the phone UI would still show the call as unmuted.
[15:20](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=920s) That creates great confusion.
[15:22](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=922s) User would disconnect the call from their car steering column, but the phone would still show a still show an ongoing call notification.
[15:30](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=930s) It's great frustration for the user, right, when that happens.
### Introducing Jetpack Telecom
[15:34](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=934s) So, to exactly solve all these issues, we have built Jetpack Telecom.
[15:40](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=940s) So, you register your call once with Jetpack Telecom using the `CallsManager`, and Jetpack Telecom acts as a central system call coordinator.
[15:52](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=952s) It takes the responsibility of projecting your call onto the watch and Android Auto and other remote surfaces user own.
[16:01](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=961s) And it also takes care of handling the audio focus.
[16:06](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=966s) And most importantly, all of this works seamlessly, all the way back to Android 8.
[16:15](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=975s) Projecting the call onto the watch or car screen is just half the story, right, because user obviously want to control the state of the call from these devices.
[16:26](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=986s) They would want to mute the call from their watch or unmute as needed.
[16:32](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=992s) They would want to hang up the call from their car steering column or by double-tapping on their earbuds.
[16:39](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=999s) So, Jetpack Telecom listens to this hardware events and present them as callbacks all in one place, which is `CallControlScope`.
[16:48](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1008s) All you need to do is just listen to these callbacks, handle your call engine and update the call state accordingly.
[16:54](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1014s) And Jetpack Telecom takes the responsibility of synchronizing that this call state between the devices.
[17:02](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1022s) So, under the hood, the library gives back benefits in two buckets.
[17:09](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1029s) One, obviously, it solves all the issues that we have talked about.
[17:14](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1034s) So, instead of you dealing with low-level AudioManager APIs, library gives declarative call endpoints, it manages the audio focus, it synchronizes between the devices.
[17:28](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1048s) It takes responsibility of hand handing the call between the devices.
[17:33](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1053s) And it takes care whenever a cellular com- call comes as well.
[17:37](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1057s) But the other benefit that comes with the library is because the library is built on top of Kotlin, whenever you add a call with the Jetpack Telecom, it opens up a Kotlin coroutine scope.
[17:49](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1069s) So, that so it takes advantage of Kotlin coroutines, and that Kotlin coroutine stays alive exactly until the duration of the call.
[17:59](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1079s) So, any job you have run with respect to the call gets cleaned up automatically as soon as the call gets disconnected.
[18:07](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1087s) So, you'd be left with no rogue jobs, and call lifecycle is also taken care by the library.
[18:16](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1096s) So, now, you'd be wondering that this awesome library is great and you want to implement it, right?
[18:23](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1103s) And it's as simple as 1 2 3.
[18:25](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1105s) Step 1 is, you should obviously declare the dependency.
[18:29](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1109s) After that, declare the required permission, which is `MANAGE_OWN_CALLS`, and then, instantiate a `CallsManager` object.
```xml
```
[18:36](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1116s) After instantiating the `CallsManager` object, register your app with the capabilities that you want to provide with the app, such as video calling or call streaming.
```kotlin
// Initialize CallsManager & register supported capabilities once
val callsManager = CallsManager(context)
callsManager.registerAppWithTelecom(
capabilities = CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING or
CallsManager.CAPABILITY_SUPPORTS_CALL_STREAMING
)
```
[18:47](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1127s) After that, step number 2.
[18:49](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1129s) Now that you have registered your app with Jetpack Telecom, now, it's time to handle incoming and outgoing calls.
[18:55](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1135s) For that, you need to build a `CallAttributesCompat` object, which holds the metadata of the call, such as the `displayName` of the caller or callee, address, which is the caller endpoint, direction, specifying whether the call is incoming call or outgoing call so that Jetpack Telecom can present respective UI onto this remote surfaces, and then, `callType`, whether it is an audio call or video call so that you would get required resources.
```kotlin
val attributes = CallAttributesCompat(
displayName = "Kukk Nat",
address = Uri.parse("tel:+16505550199"),
direction = CallAttributesCompat.DIRECTION_INCOMING,
callType = CallAttributesCompat.CALL_TYPE_AUDIO_CALL
)
callsManager.addCall(
attributes, onAnswer, onDisconnect, onSetActive, onSetInactive
) {
// Coroutine CallControlScope active for the duration of the call
}
```
[19:25](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1165s) Once you have the metadata object ready, add it to add it using `callsManager.addCall` method.
[19:32](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1172s) This opens up a call call control coroutine scope.
[19:38](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1178s) So, once you are done with adding your call, now, step 3.
[19:43](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1183s) Step Step 3 is listening to the actions user going to perform from those remote surfaces.
[19:49](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1189s) So, because you have `CallControlScope`, all you need to do is just collect the Kotlin flows.
```kotlin
callsManager.addCall(attributes, onAnswer, onDisconnect, onSetActive, onSetInactive) {
// 1. React to hardware mute toggles from Watch, Car, or Headset
launch {
isMuted.collect { muted -> audioEngine.setMicMuted(muted) }
}
// 2. Observe available endpoints & request declarative switches
launch {
currentCallEndpoint.collect { endpoint -> updateUi(endpoint) }
}
requestEndpointChange(preferredBluetoothEndpoint)
}
```
[19:56](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1196s) You collect `isMuted` to react whenever user mutes the call from those remote surfaces, and accordingly, you can update your call state.
[20:07](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1207s) Collect `currentCallEndpoint` to know what endpoint the call is currently happening so that you can update your UI accordingly.
[20:16](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1216s) You can show that particular devices that particular device on your phone UI.
[20:22](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1222s) And whenever user wants to change from one device to another device, just call `requestEndpointChange` method with whatever preferred preferred endpoint user wants.
[20:32](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1232s) It's as simple as that.
[20:35](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1235s) With these three steps, your app is good to go and have integrated Jetpack Telecom.
[20:42](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1242s) But that's not it.
[20:43](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1243s) With Jetpack Telecom 1.1.0, we are bringing much more features such as unified call histories, which means all your VoIP calls will now show up natively on the system dialer.
[20:56](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1256s) So, the advantage of the of that is your users will be able to instantiate one-tap call back right from your system dialer into your app.
[21:06](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1266s) So, no need of going and searching for your particular app amongst all the apps.
[21:10](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1270s) They can just instantiate call back from their from the system dialer that they are all used to.
[21:18](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1278s) But for some, but if you, but we are also providing granular controls.
[21:22](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1282s) If you don't want a call, a particular call to be logged into the system, you just need to make `isLogExcluded` flag as true inside of `CallAttributesCompat` object.
[21:33](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1293s) The meta data object I spoke about earlier, you just make it as true and your call will not be logged with the system and it does it will not show up in the system dialer.
[21:45](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1305s) And the second awesome feature that's gonna come up with 1.1.0 is 5G network slicing.
[21:51](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1311s) So, on supported carrier networks, what happens is networks provide you with premium network slices, which means for a particular use case, the carrier would give you a network slice which has low latency and no other interruptions, so that you'll have better quality and better experience over that.
[22:12](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1332s) So, on supported carrier networks, you'll get this feature out-of-the-box, so there is no extra effort required from your side, not even a single line of code.
[22:22](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1342s) Once you integrate your integrate the library, your calls will take advantage of those network slices and you'll get better latency and better performance.
[22:34](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1354s) But for some reason, if you don't want this feature, you can opt out of that as well using `CAPABILITY_OPT_OUT_OF_PREMIUM_NETWORK` flag.
[22:46](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1366s) Jetpack Telecom has already been implemented by the top global communication apps like Google Meet, WhatsApp, KakaoTalk, and Zoho Arattai.
[22:56](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1376s) So, now it's up to you, it's So, now it's on you to integrate this library in your app and provide that seamless better experience for the user.
[23:05](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1385s) With that, now that real-time calling is covered, I would like to hand over mic to my amazing colleague Yacine for tap to share.
[23:15](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1395s) Thank you.
### Peer-to-peer sharing challenges
[23:17](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1397s) All right folks, I know you are a bit tired, so don't worry, it's the last section.
[23:22](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1402s) So, I'm going to cover peer-to-peer sh- file sharing, but other use cases we can do also with peer-to-peer sharing.
[23:30](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1410s) What we've seen across the mobile ecosystem is we have more than 14 billion photos and videos shared on social media and messaging apps every single day, so that's a huge amount.
[23:41](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1421s) And all of those files are shared most of the time through the cloud, so you take the picture, you upload it through your favorite service and then the person has to download it the same way through the other side.
[23:55](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1435s) And same thing happen actually when you try to invite someone or a friend to a social network to invite someone to collaborate on a playlist or document, you have to usually type their username or their email, which takes a bit of a while on a your keyboard.
[24:09](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1449s) You might make a mistake and that's not actually a great experience, especially when both of you are literally sitting next to each other, so it's like, oh, I have to send through the cloud, I have to wait.
[24:17](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1457s) It's just not great.
[24:19](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1459s) And nowadays, we all have kind of fancy phones, devices, tablets, foldables, and we have amazing pictures being taken on them.
[24:27](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1467s) But when you're sharing through some of those social medias or some of them some of these messaging apps, obviously for performance issues and storage, they're getting compressed, which in the end, on your amazing screen, they end up quite pixelated or just not the best quality.
[24:44](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1484s) That's not the best experience you would like to have on your premium device.
[24:49](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1489s) Second thing, files now are actually quite big.
[24:52](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1492s) A single picture is easily 10 MB, a 5 minutes video is like 500 MB, so all of that takes quite a while just to upload and download.
[25:01](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1501s) And lastly, on the other side, you have to wait for that latency.
[25:04](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1504s) So, sometimes you might be hopping on a bus, it's crowded and as the bus is moving on, you're not having the best latency, the best network coverage and sometimes the file transfer is dropped, sometimes because of that really long latency, you might have a timeout and the file transfer is canceled, which is really, it's frustrating for a user.
[25:27](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1527s) So, instead of relying on the cloud to be able to share all of those files and having to wait on all of that, why not using actually local network, like Bluetooth or Wi-Fi?
[25:37](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1537s) But if you try to do that yourself, obviously, you have to deal with the Bluetooth Bluetooth manager, the Wi-Fi manager, having to write your own protocol, I mean, not everyone wants to have some time doing that.
[25:49](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1549s) But actually, there's something already existing on Android.
[25:52](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1552s) It's already out of the box and you may have heard it, Quick Share.
### Quick Share overview
[25:57](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1557s) Quick Share on Android allows you to have this abstraction already in place in the system and you can just share files with another device and you don't have to manage all of that.
[26:08](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1568s) It's already available in your share sheet and it's switching throughout which protocol is the best for your device between both devices and it's on Marshmallow and higher, which is, these days, quite a huge audience, right?
[26:24](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1584s) And lastly, that familiar UI and UX you see on the side, really helps your own users.
[26:29](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1589s) So, they know what's the UI, they can't they don't have to learn how to use it, they already have seen it in the past.
[26:37](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1597s) But we know developers, they all they also wants to own the experience.
[26:43](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1603s) You know your app, you know your users better than us probably.
[26:46](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1606s) So, why not having Quick Share directly in your app?
[26:51](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1611s) So, we started to talk with developers and we've seen that Quick Share is already quite widespread.
[26:57](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1617s) It's available on Android, on Chromebooks, recently Google Books and also on Windows, that's more than 3 billion devices, it's huge.
[27:05](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1625s) And we also brought with Pixel 11, the ability to tap to share.
[27:10](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1630s) So, rather than having to choose the device that you want to share with, you can just tap and with NFC, we're doing that discoverability directly for you.
[27:19](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1639s) So, you can select a photo, but you can also select a file, you just tap two devices and they're shared directly with a bump.
[27:27](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1647s) And again, we know developers who wants to own the experience.
[27:30](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1650s) We know it's the best way for your users to be able to use a specific feature, in this case, file sharing.
[27:35](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1655s) So, why not having Quick Share in your app, embedded?
[27:39](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1659s) So, that's why next year, we're bringing Quick Share SDK directly for you.
[27:43](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1663s) You'll be able to use it directly in your app and it comes with security already baked-in, as end-to-end encryption between both devices.
[27:53](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1673s) As the transfers happen between those local networks, you'll have the full speed, obviously in your home Wi-Fi, but also between both of you can just have a hotspot being created automatically, you don't have to deal that with you.
[28:06](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1686s) And for devices that support Wi-Fi Direct, it's already included.
[28:11](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1691s) And the files that you've taken with your amazing camera, they will keep their best resolution and details, so like that you can see them nicely on your big large screen.
[28:24](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1704s) And given that it's relying on local networks, you can use that in the tube, even in the really deepest part of it, you'll still have network to be able to share with your friend.
[28:35](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1715s) In the plane as well, you'll be, I don't know how many thousand of feet above, in the sky, and you'll still be able to share those files.
[28:42](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1722s) And lastly, for you as a developer, it's a huge cost-saving in terms of data, because first, your users don't have to use that data plan and it's a big deal when they're traveling as tourists.
[28:54](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1734s) But also, on your own servers, you don't have to maintain that.
[28:59](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1739s) And last year, we mentioned to developers and also users that with Quick Share, they will be able to share files with iPhone devices through AirDrop.
[29:10](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1750s) Well, with Quick Share, we're bringing the same thing for developers.
[29:12](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1752s) We are going to have a Quick Share iOS SDK for developers that have iOS apps to be able to share, regardless of the device, files between both platforms.
[29:24](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1764s) So, all of that is fancy presentation, now, let's have a look quickly at the code.
[29:29](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1769s) We tried to make it as simple as possible.
[29:31](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1771s) You obviously initiate a `QuickShareClient`, you have to attach the files that you want to share with, and then once you start the session, you'll have this beautiful modal window you're seeing on the side, the bottom sheet where the users will be able to see the files that are being sent as previews, and if you consider the content being being sensitive, you can also enable that with the option seeing on the screen.
```kotlin
// Final API may undergo further updates
val quickShareClient = QuickShareClient.create(activity)
val attachment = FileAttachment(
fileName = "report.pdf",
size = 1_048_576L,
uri = fileUri,
mimeType = "application/pdf",
// Sensitive content will be masked in preview
isSensitiveContent = false,
)
val content = ShareableContent.withFiles(listOf(attachment))
val request = SharingRequest.withContent(content)
val session = quickShareClient.startSharingSession(request, lifecycleOwner)
```
[29:57](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1797s) When you want to receive a file, again, within your app, same thing, of course, in this case, you're not adding an attachment, and then as soon as the session is being started, you don't have to deal with any of that.
```kotlin
// Final API may undergo further updates
val quickShareClient = QuickShareClient.create(activity)
val request = SharingRequest.withoutContent()
val session = quickShareClient.startSharingSession(request, lifecycleOwner)
// Open the Quick Share overlay in receive mode
session.launchWindow(activity, contentSelectionIntent = null)
```
[30:08](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1808s) So far, you've seen is literally just 20 lines of code on both sides.
[30:15](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1815s) We know, with Quick Share and tap to share, the ability to share files by just touching devices also actually enable a new use case.
[30:23](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1823s) Your app could be closed down on the other device, and by tapping, as soon as the file is transferred, your app will be automatically opened and you will receive the URI to be able to do some in on-device processing, for example, or display something to the user directly within your app.
```kotlin
// Final API may undergo further updates
val quickShareClient = QuickShareClient.create(activity)
val urlAttachment = TextAttachment(
text = groupAddUrl,
type = TextAttachment.Type.URL,
)
val content = ShareableContent.withText(urlAttachment)
val appLink = AppLink("https://myapp.com/group/invite")
val request = SharingRequest.withContent(content, appLink)
val session = quickShareClient.startSharingSession(request, lifecycleOwner)
```
[30:41](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1841s) So, again, you don't have to open your app on the receiving device.
[30:44](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1844s) With tap to share, it will open that automatically.
[30:49](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1849s) And of course, if you want your UI to react to that file transfer, you're just having a Kotlin Flow, and you will have all the events for you to be able to process that.
```kotlin
// Final API may undergo further updates
scope.launch {
for (event in session.sharingEvents) {
when (event) {
is SharingEvent.SendComplete ->
println("Send finished")
is SharingEvent.ReceiveComplete ->
println("Received, files=${event.content?.files?.size}")
else -> println("other event")
}
}
}
```
### Summary and wrap up
[31:00](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1860s) So, we've seen a lot today so far, so I'm wrapping up.
[31:04](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1864s) And don't worry, you're going to have some minutes to take a break.
[31:06](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1866s) CompanionDeviceManager is being the best API for you to handle any Bluetooth interactions, continuous Bluetooth interactions, as Hanrui presented as earlier.
[31:20](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1880s) If your app has any voice over IP calls, it doesn't have to be its main use case, it can be, for example, you have support clients part of your app where the user is able to call the support.
[31:33](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1893s) In this case, again, the best way to handle voice over IP calls on Android, Jetpack Com-- Jetpack Telecom is the solution.
[31:40](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1900s) And lastly, for any peer-to-peer file sharing or opening app, as I mentioned, with tap to share, Quick Share is the solution.
[31:49](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1909s) So, thank you everyone, and before you go, just a quick thing, we will be outside afterwards to answer your questions.
[31:57](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1917s) We have office hours if you have any questions, you know, across all the use cases we've presented.
[32:02](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1922s) And don't forget to share any of your any learning from your talk or other sessions, obviously, on social media.
[32:09](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1929s) We have #AndroidDevSummit.
[32:12](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1932s) Again, it's super important for us to know that we have engagement, we have people really enjoying the event.
[32:17](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1937s) It help us to know that we have definitely a community that we want to see again.
[32:22](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1942s) And collect your social charm that you can add to your Android bot keyring from the infodesk.
[32:28](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1948s) Did I do it right?
[32:29](https://www.youtube.com/watch?v=2-EfHHa_NxE&t=1949s) Thank you.