parent
14353c7f7c
commit
c1730c3a17
|
|
@ -256,6 +256,7 @@ dependencies {
|
||||||
implementation("androidx.webkit:webkit:1.14.0")
|
implementation("androidx.webkit:webkit:1.14.0")
|
||||||
implementation("androidx.core:core-splashscreen:1.2.0-beta02")
|
implementation("androidx.core:core-splashscreen:1.2.0-beta02")
|
||||||
implementation("androidx.palette:palette-ktx:1.0.0")
|
implementation("androidx.palette:palette-ktx:1.0.0")
|
||||||
|
implementation("androidx.core:core-telecom:1.0.0")
|
||||||
|
|
||||||
// Libraries used for legacy View-based UI
|
// Libraries used for legacy View-based UI
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.2.1")
|
implementation("androidx.constraintlayout:constraintlayout:2.2.1")
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
|
||||||
|
|
||||||
<!-- Up to Android 10, we need the following to take photos from the camera. -->
|
<!-- Up to Android 10, we need the following to take photos from the camera. -->
|
||||||
<uses-permission
|
<uses-permission
|
||||||
|
|
@ -138,6 +139,11 @@
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:theme="@style/Theme.Revolt" />
|
android:theme="@style/Theme.Revolt" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".activities.voice.IncomingActivity"
|
||||||
|
android:configChanges="orientation|screenSize"
|
||||||
|
android:theme="@style/Theme.Revolt" />
|
||||||
|
|
||||||
<!-- Backport photo picker via Google Play Services -->
|
<!-- Backport photo picker via Google Play Services -->
|
||||||
<service
|
<service
|
||||||
android:name="com.google.android.gms.metadata.ModuleDependencies"
|
android:name="com.google.android.gms.metadata.ModuleDependencies"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,289 @@
|
||||||
|
package chat.revolt.activities.voice
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.compose.animation.animateColor
|
||||||
|
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||||
|
import androidx.compose.animation.core.RepeatMode
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
|
import androidx.compose.animation.core.infiniteRepeatable
|
||||||
|
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.gestures.AnchoredDraggableDefaults
|
||||||
|
import androidx.compose.foundation.gestures.AnchoredDraggableState
|
||||||
|
import androidx.compose.foundation.gestures.DraggableAnchors
|
||||||
|
import androidx.compose.foundation.gestures.Orientation
|
||||||
|
import androidx.compose.foundation.gestures.anchoredDraggable
|
||||||
|
import androidx.compose.foundation.gestures.animateTo
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.LocalContentColor
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.SideEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.draw.rotate
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.lerp
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.IntOffset
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import chat.revolt.R
|
||||||
|
import chat.revolt.composables.generic.Presence
|
||||||
|
import chat.revolt.composables.generic.RemoteImage
|
||||||
|
import chat.revolt.composables.generic.presenceColour
|
||||||
|
import chat.revolt.ui.theme.RevoltTheme
|
||||||
|
import chat.revolt.ui.theme.Theme
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
class IncomingActivity : ComponentActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
enableEdgeToEdge()
|
||||||
|
|
||||||
|
setContent {
|
||||||
|
IncomingCall()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun IncomingCall() {
|
||||||
|
RevoltTheme(
|
||||||
|
requestedTheme = if (isSystemInDarkTheme()) Theme.Revolt else Theme.Light
|
||||||
|
) {
|
||||||
|
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onBackground) {
|
||||||
|
IncomingCallInner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum class CallSwiperState {
|
||||||
|
Initial,
|
||||||
|
Accept,
|
||||||
|
Decline
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||||
|
@Composable
|
||||||
|
fun IncomingCallInner() {
|
||||||
|
val bgInfinite = rememberInfiniteTransition(label = "Background")
|
||||||
|
val bgColour by bgInfinite.animateColor(
|
||||||
|
initialValue = MaterialTheme.colorScheme.surfaceContainerHighest,
|
||||||
|
targetValue = MaterialTheme.colorScheme.surfaceContainerLowest,
|
||||||
|
label = "Background Colour",
|
||||||
|
animationSpec = infiniteRepeatable(
|
||||||
|
animation = tween(1000, 0, FastOutSlowInEasing),
|
||||||
|
repeatMode = RepeatMode.Reverse
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
var swiperLabelColourLerp by remember { mutableFloatStateOf(0f) }
|
||||||
|
val swiperLabelColourLerpAnim by animateFloatAsState(
|
||||||
|
targetValue = swiperLabelColourLerp,
|
||||||
|
animationSpec = tween(250),
|
||||||
|
label = "Swiper Label Colour Lerp state"
|
||||||
|
)
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
while (true) {
|
||||||
|
swiperLabelColourLerp = 0f
|
||||||
|
delay(1000)
|
||||||
|
swiperLabelColourLerp = 1f
|
||||||
|
delay(4000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val swiperState = remember { AnchoredDraggableState(CallSwiperState.Initial) }
|
||||||
|
val swiperWidth = 330.dp
|
||||||
|
val swiperWidthThird = swiperWidth / 3
|
||||||
|
val density = LocalDensity.current
|
||||||
|
val swiperWidthPx = with(density) { swiperWidth.toPx() }
|
||||||
|
val swiperThirdPx = with(density) { swiperWidthThird.toPx() }
|
||||||
|
SideEffect {
|
||||||
|
swiperState.updateAnchors(
|
||||||
|
DraggableAnchors {
|
||||||
|
CallSwiperState.Decline at 35f
|
||||||
|
CallSwiperState.Initial at (swiperWidthPx / 2f) - (swiperThirdPx / 2f)
|
||||||
|
CallSwiperState.Accept at swiperWidthPx - swiperThirdPx - 35f
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(swiperState.currentValue) {
|
||||||
|
when (swiperState.currentValue) {
|
||||||
|
CallSwiperState.Accept -> {
|
||||||
|
swiperState.animateTo(CallSwiperState.Initial)
|
||||||
|
}
|
||||||
|
|
||||||
|
CallSwiperState.Decline -> {
|
||||||
|
swiperState.animateTo(CallSwiperState.Initial)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val swiperRotation = remember(swiperState.offset) {
|
||||||
|
if (swiperState.offset.isNaN()) 0f
|
||||||
|
else {
|
||||||
|
val declineAnchor = 35f
|
||||||
|
val initialAnchor = (swiperWidthPx / 2f) - (swiperThirdPx / 2f)
|
||||||
|
val acceptAnchor = swiperWidthPx - swiperThirdPx - 35f
|
||||||
|
|
||||||
|
when {
|
||||||
|
swiperState.offset <= initialAnchor -> {
|
||||||
|
// Moving towards decline: interpolate from 0° to -90°
|
||||||
|
val progress =
|
||||||
|
(initialAnchor - swiperState.offset) / (initialAnchor - declineAnchor)
|
||||||
|
-225f * progress.coerceIn(0f, 1f)
|
||||||
|
}
|
||||||
|
|
||||||
|
swiperState.offset >= initialAnchor -> {
|
||||||
|
// Moving towards accept: interpolate from 0° to 90°
|
||||||
|
val progress =
|
||||||
|
(swiperState.offset - initialAnchor) / (acceptAnchor - initialAnchor)
|
||||||
|
45f * progress.coerceIn(0f, 1f)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> 0f // At initial position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(bgColour),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp, Alignment.CenterVertically),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Incoming Call on Revolt",
|
||||||
|
style = MaterialTheme.typography.headlineMedium,
|
||||||
|
fontSize = 24.sp
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
"cat",
|
||||||
|
style = MaterialTheme.typography.displayLargeEmphasized,
|
||||||
|
fontWeight = FontWeight.SemiBold
|
||||||
|
)
|
||||||
|
with(density) {
|
||||||
|
RemoteImage(
|
||||||
|
url = "https://cdn.revoltusercontent.com/attachments/K1CDpnvORz2fzUhgq47mcL7N4gccWGqNYYeGaJVvyp/image.png",
|
||||||
|
description = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(CircleShape)
|
||||||
|
.fillMaxWidth(0.5f)
|
||||||
|
.aspectRatio(1f),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(Modifier.fillMaxHeight(.33f))
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(CircleShape)
|
||||||
|
.height(84.dp)
|
||||||
|
.width(swiperWidth)
|
||||||
|
.then(
|
||||||
|
if (isSystemInDarkTheme()) Modifier
|
||||||
|
.background(MaterialTheme.colorScheme.surfaceVariant)
|
||||||
|
.background(
|
||||||
|
Brush.linearGradient(
|
||||||
|
listOf(
|
||||||
|
presenceColour(Presence.Dnd).copy(alpha = 0.05f),
|
||||||
|
presenceColour(Presence.Online).copy(alpha = 0.05f),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) else Modifier.background(MaterialTheme.colorScheme.surfaceBright)
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Decline",
|
||||||
|
color = lerp(
|
||||||
|
presenceColour(Presence.Dnd),
|
||||||
|
MaterialTheme.colorScheme.onSurface,
|
||||||
|
swiperLabelColourLerpAnim
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.CenterStart)
|
||||||
|
.padding(start = 30.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
"Accept",
|
||||||
|
color = lerp(
|
||||||
|
presenceColour(Presence.Online),
|
||||||
|
MaterialTheme.colorScheme.onSurface,
|
||||||
|
swiperLabelColourLerpAnim
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.CenterEnd)
|
||||||
|
.padding(end = 30.dp)
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.width(swiperWidthThird)
|
||||||
|
.height(64.dp)
|
||||||
|
.offset {
|
||||||
|
IntOffset(
|
||||||
|
x = swiperState.requireOffset().roundToInt(),
|
||||||
|
y = with(density) { (84.dp - 64.dp).toPx() / 2 }.roundToInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.anchoredDraggable(
|
||||||
|
swiperState,
|
||||||
|
Orientation.Horizontal,
|
||||||
|
flingBehavior =
|
||||||
|
AnchoredDraggableDefaults.flingBehavior(
|
||||||
|
swiperState,
|
||||||
|
positionalThreshold = { distance -> distance * 0.25f },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(MaterialTheme.colorScheme.tertiaryContainer)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.icn_call_24dp__fill),
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.onTertiaryContainer,
|
||||||
|
modifier = Modifier
|
||||||
|
.rotate(swiperRotation)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -219,6 +219,15 @@ fun LabsHomeScreen(navController: NavController, topNav: NavController) {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text("Telecom")
|
||||||
|
},
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
navController.navigate("sandboxes/telecom")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
HorizontalDivider()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import chat.revolt.screens.labs.ui.sandbox.GradientEditorSandbox
|
||||||
import chat.revolt.screens.labs.ui.sandbox.JBMSandbox
|
import chat.revolt.screens.labs.ui.sandbox.JBMSandbox
|
||||||
import chat.revolt.screens.labs.ui.sandbox.NewCardSandboxScreen
|
import chat.revolt.screens.labs.ui.sandbox.NewCardSandboxScreen
|
||||||
import chat.revolt.screens.labs.ui.sandbox.SettingsDslSandbox
|
import chat.revolt.screens.labs.ui.sandbox.SettingsDslSandbox
|
||||||
|
import chat.revolt.screens.labs.ui.sandbox.TelecomSandbox
|
||||||
|
|
||||||
annotation class LabsFeature
|
annotation class LabsFeature
|
||||||
|
|
||||||
|
|
@ -87,6 +88,9 @@ fun LabsRootScreen(topNav: NavController) {
|
||||||
composable("sandboxes/newcard") {
|
composable("sandboxes/newcard") {
|
||||||
NewCardSandboxScreen(labsNav)
|
NewCardSandboxScreen(labsNav)
|
||||||
}
|
}
|
||||||
|
composable("sandboxes/telecom") {
|
||||||
|
TelecomSandbox(labsNav)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
package chat.revolt.screens.labs.ui.sandbox
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import androidx.core.telecom.CallAttributesCompat
|
||||||
|
import androidx.core.telecom.CallControlScope
|
||||||
|
import androidx.core.telecom.CallsManager
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import chat.revolt.activities.voice.IncomingActivity
|
||||||
|
import chat.revolt.settings.dsl.SettingsPage
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import logcat.LogPriority
|
||||||
|
import logcat.asLog
|
||||||
|
import logcat.logcat
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TelecomSandbox(navController: NavController) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val callsManager = remember {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) CallsManager(context) else null
|
||||||
|
}
|
||||||
|
val didRegister = remember { mutableStateOf(false) }
|
||||||
|
val callControlScope = remember { mutableStateOf<CallControlScope?>(null) }
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
SettingsPage(
|
||||||
|
navController,
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
text = "Telecom Sandbox",
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val capabilities: @CallsManager.Companion.Capability Int =
|
||||||
|
(CallsManager.CAPABILITY_BASELINE or
|
||||||
|
CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING)
|
||||||
|
|
||||||
|
callsManager?.registerAppWithTelecom(capabilities)
|
||||||
|
didRegister.value = true
|
||||||
|
} else {
|
||||||
|
showSnackbar("Android version too old for Core-Telecom API")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(if (didRegister.value) "Registered" else "Register Revolt for Calls")
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val address = "revolt:01F92C5ZXBQWQ8KY7J8KY917NM".toUri()
|
||||||
|
val attr = CallAttributesCompat(
|
||||||
|
displayName = "Jennifer",
|
||||||
|
address = address,
|
||||||
|
direction = CallAttributesCompat.DIRECTION_INCOMING,
|
||||||
|
callType = CallAttributesCompat.CALL_TYPE_AUDIO_CALL,
|
||||||
|
callCapabilities = 0
|
||||||
|
)
|
||||||
|
scope.launch {
|
||||||
|
delay(5000)
|
||||||
|
try {
|
||||||
|
callsManager?.addCall(
|
||||||
|
attr,
|
||||||
|
{ someInt ->
|
||||||
|
logcat { "Call answered with $someInt" }
|
||||||
|
// answer the call here, e.g. start an activity or service...
|
||||||
|
}, // Watch needs to know if it can answer the call.
|
||||||
|
{ cause ->
|
||||||
|
logcat { "Call ended with cause $cause" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
logcat { "Call state changed to active" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
logcat { "Call state changed to inactive (hold)" }
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
// The call was successfully added once this scope runs.
|
||||||
|
callControlScope.value = this
|
||||||
|
}
|
||||||
|
} catch (addCallException: Exception) {
|
||||||
|
logcat(LogPriority.ERROR) { addCallException.asLog() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showSnackbar("Android version too old for Core-Telecom API")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text("Place incoming call in 5 seconds")
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
val intent = Intent(context, IncomingActivity::class.java)
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text("Just open incoming call activity")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M798,840Q673,840 551,785.5Q429,731 329,631Q229,531 174.5,409Q120,287 120,162Q120,144 132,132Q144,120 162,120L324,120Q338,120 349,129.5Q360,139 362,152L388,292Q390,308 387,319Q384,330 376,338L279,436Q299,473 326.5,507.5Q354,542 387,574Q418,605 452,631.5Q486,658 524,680L618,586Q627,577 641.5,572.5Q656,568 670,570L808,598Q822,602 831,612.5Q840,623 840,636L840,798Q840,816 828,828Q816,840 798,840Z"/>
|
||||||
|
</vector>
|
||||||
Loading…
Reference in New Issue