Skip to Content
Dial v1 live šŸŽ‰
SdkAndroid SDK (Kotlin)

Android SDK (Kotlin)

Native Android SDK built with Kotlin for optimal performance and native Android integration.

Status

šŸ”„ Coming Q3 2025 - Currently in development

Join the waitlistĀ  to be notified when available.

Planned Features

Core Features

  • āœ… Wallet-to-wallet calls (audio/video)
  • āœ… Native ConnectionService integration
  • āœ… Push notifications (FCM)
  • āœ… Messaging
  • āœ… Voicemail
  • āœ… Call history

Android-Specific

  • āœ… ConnectionService integration
  • āœ… Notification channels
  • āœ… Picture-in-Picture mode
  • āœ… Android Auto support
  • āœ… Widgets
  • āœ… Material Design 3 components
  • āœ… Jetpack Compose support

Requirements

  • Android 8.0+ (API 26+)
  • Kotlin 1.9+
  • Android Studio Hedgehog or later

Planned Installation

Gradle (Kotlin DSL)

dependencies { implementation("wtf.dial:sdk-android:1.0.0") }

Gradle (Groovy)

dependencies { implementation 'wtf.dial:sdk-android:1.0.0' }

Planned API

Setup

import wtf.dial.sdk.DialClient val dial = DialClient( context = applicationContext, apiKey = "your-api-key", walletAddress = "0x..." )

Authentication

// Sign message with wallet val signature = wallet.signMessage("Authenticate with Dial") dial.authenticate( walletAddress = "0x...", signature = signature )

Making Calls

val call = dial.calls.start( to = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", type = CallType.VIDEO )

ConnectionService Integration

import android.telecom.ConnectionService import wtf.dial.sdk.DialConnectionService class MyConnectionService : DialConnectionService() { override fun onCreateIncomingConnection( connectionManagerAccount: PhoneAccountHandle, request: ConnectionRequest ): Connection { // Automatically integrates with Android's native call UI return createDialConnection(request) } }

Add to AndroidManifest.xml:

<service android:name=".MyConnectionService" android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"> <intent-filter> <action android:name="android.telecom.ConnectionService" /> </intent-filter> </service>

Jetpack Compose Integration

import androidx.compose.runtime.* import wtf.dial.sdk.compose.* @Composable fun CallScreen() { val callState = rememberDialCallState() val dial = LocalDial.current Column { if (callState.currentCall != null) { when (callState.currentCall.status) { CallStatus.RINGING -> IncomingCallView(callState.currentCall) CallStatus.ACTIVE -> ActiveCallView(callState.currentCall) else -> {} } } else { Button(onClick = { callState.startCall( to = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", type = CallType.VIDEO ) }) { Text("Make Call") } } } } @Composable fun IncomingCallView(call: DialCall) { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Text( text = "Incoming call from", style = MaterialTheme.typography.bodyLarge ) Text( text = call.from, style = MaterialTheme.typography.headlineMedium ) Row( modifier = Modifier.padding(top = 32.dp), horizontalArrangement = Arrangement.spacedBy(32.dp) ) { FloatingActionButton( onClick = { call.decline() }, containerColor = MaterialTheme.colorScheme.error ) { Icon(Icons.Default.CallEnd, "Decline") } FloatingActionButton( onClick = { call.answer() }, containerColor = MaterialTheme.colorScheme.primary ) { Icon(Icons.Default.Call, "Answer") } } } }

Traditional View System

import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import wtf.dial.sdk.DialClient import wtf.dial.sdk.DialCallListener class CallActivity : AppCompatActivity(), DialCallListener { private lateinit var dial: DialClient private var currentCall: DialCall? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_call) dial = DialClient.getInstance() dial.addCallListener(this) } fun makeCall(recipient: String) { lifecycleScope.launch { currentCall = dial.calls.start( to = recipient, type = CallType.VIDEO ) } } override fun onIncomingCall(call: DialCall) { currentCall = call showIncomingCallUI(call) } }

Messaging

// Send message dial.messages.send( to = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", content = "Hello!", type = MessageType.TEXT ) // Listen for messages dial.messages.onReceived { message -> println("New message from ${message.from}: ${message.content}") }

Push Notifications (FCM)

import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage import wtf.dial.sdk.DialNotificationHandler class MyFirebaseMessagingService : FirebaseMessagingService() { override fun onMessageReceived(remoteMessage: RemoteMessage) { DialNotificationHandler.handleNotification( context = this, data = remoteMessage.data ) } override fun onNewToken(token: String) { DialClient.getInstance().registerPushToken(token) } }

Coroutines Support

Full support for Kotlin Coroutines:

// All API calls are suspend functions lifecycleScope.launch { val call = dial.calls.start(to = "0x...", type = CallType.AUDIO) val messages = dial.messages.getHistory(with = "0x...") val voicemails = dial.voicemail.getAll() }

Flow Support

Reactive streams with Kotlin Flow:

import kotlinx.coroutines.flow.* class CallViewModel : ViewModel() { val currentCall: StateFlow<DialCall?> = dial.callFlow.stateIn( viewModelScope, SharingStarted.Lazily, null ) val messages: StateFlow<List<DialMessage>> = dial.messagesFlow.stateIn( viewModelScope, SharingStarted.Lazily, emptyList() ) }

Android Auto Integration

import androidx.car.app.CarContext import androidx.car.app.Screen import wtf.dial.sdk.auto.DialAutoScreen class DialAutoCallScreen(carContext: CarContext) : DialAutoScreen(carContext) { override fun onGetTemplate(): Template { return createCallTemplate() } }

Add to AndroidManifest.xml:

<meta-data android:name="com.google.android.gms.car.application" android:resource="@xml/automotive_app_desc" />

Widgets

import android.appwidget.AppWidgetProvider import wtf.dial.sdk.widget.CallHistoryWidget class DialWidget : CallHistoryWidget() { override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray ) { // Automatically displays recent calls super.onUpdate(context, appWidgetManager, appWidgetIds) } }

Picture-in-Picture

import android.app.PictureInPictureParams import android.util.Rational fun enterPipMode() { val params = PictureInPictureParams.Builder() .setAspectRatio(Rational(16, 9)) .build() enterPictureInPictureMode(params) } override fun onPictureInPictureModeChanged( isInPictureInPictureMode: Boolean, newConfig: Configuration ) { if (isInPictureInPictureMode) { // Hide UI elements hideCallControls() } else { // Show UI elements showCallControls() } }

Permissions

Add to AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- For ConnectionService --> <uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />

Runtime permission handling:

val permissions = arrayOf( Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO ) ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE)

ProGuard Rules

Add to proguard-rules.pro:

-keep class wtf.dial.sdk.** { *; } -keepclassmembers class wtf.dial.sdk.** { *; }

Performance

  • Native Kotlin implementation
  • Hardware-accelerated codecs
  • Battery optimization
  • Background execution limits handling
  • Low memory footprint

Material Design 3

Full Material You support:

@Composable fun DialTheme( darkTheme: Boolean = isSystemInDarkTheme(), dynamicColor: Boolean = true, content: @Composable () -> Unit ) { val colorScheme = when { dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { if (darkTheme) dynamicDarkColorScheme(LocalContext.current) else dynamicLightColorScheme(LocalContext.current) } darkTheme -> darkColorScheme() else -> lightColorScheme() } MaterialTheme( colorScheme = colorScheme, content = content ) }

Roadmap

Q3 2025 - Alpha Release

  • Core calling features
  • ConnectionService integration
  • Push notifications
  • Messaging

Q4 2025 - Beta Release

  • Video conferencing
  • Android Auto support
  • Widgets
  • Picture-in-Picture

Q1 2026 - Stable Release

  • Full feature parity
  • Material Design 3
  • Production-ready
  • Complete documentation

Example App

A complete example app will be available:

  • GitHub RepositoryĀ 
  • Jetpack Compose implementation
  • Traditional Views implementation
  • Best practices
  • Material Design 3 patterns

Get Notified

Want early access?

Next Steps

Last updated on