Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions webtrit_callkeep/lib/src/webtrit_callkeep_permissions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,24 @@ class WebtritCallkeepPermissions {
return platform.getBatteryMode();
}

/// Returns how incoming calls are delivered on this device.
///
/// On devices without `android.software.telecom` this reports
/// [CallkeepAndroidCallDeliveryMode.standalone], a limited path the system may
/// throttle. On non-Android platforms returns
/// [CallkeepAndroidCallDeliveryMode.unknown].
Future<CallkeepAndroidCallDeliveryMode> getCallDeliveryMode() {
if (kIsWeb) {
return Future.value(CallkeepAndroidCallDeliveryMode.unknown);
}

if (!Platform.isAndroid) {
return Future.value(CallkeepAndroidCallDeliveryMode.unknown);
}

return platform.getCallDeliveryMode();
}

/// Requests the specified [permissions] on Android.
///
/// Returns a [Map] where:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,19 @@ enum class PCallkeepAndroidBatteryMode(
}
}

enum class PCallkeepAndroidCallDeliveryMode(
val raw: Int,
) {
TELECOM(0),
STANDALONE(1),
UNKNOWN(2),
;

companion object {
fun ofRaw(raw: Int): PCallkeepAndroidCallDeliveryMode? = values().firstOrNull { it.raw == raw }
}
}

enum class PHandleTypeEnum(
val raw: Int,
) {
Expand Down Expand Up @@ -968,6 +981,12 @@ private open class GeneratedPigeonCodec : StandardMessageCodec() {
}
}

155.toByte() -> {
return (readValue(buffer) as Long?)?.let {
PCallkeepAndroidCallDeliveryMode.ofRaw(it.toInt())
}
}

else -> {
super.readValueOfType(type, buffer)
}
Expand Down Expand Up @@ -1109,6 +1128,11 @@ private open class GeneratedPigeonCodec : StandardMessageCodec() {
writeValue(stream, value.toList())
}

is PCallkeepAndroidCallDeliveryMode -> {
stream.write(155)
writeValue(stream, value.raw)
}

else -> {
super.writeValue(stream, value)
}
Expand Down Expand Up @@ -1325,6 +1349,8 @@ interface PHostPermissionsApi {

fun getBatteryMode(callback: (Result<PCallkeepAndroidBatteryMode>) -> Unit)

fun getCallDeliveryMode(callback: (Result<PCallkeepAndroidCallDeliveryMode>) -> Unit)

fun requestPermissions(
permissions: List<PCallkeepPermission>,
callback: (Result<List<PPermissionResult>>) -> Unit,
Expand Down Expand Up @@ -1419,6 +1445,24 @@ interface PHostPermissionsApi {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.webtrit_callkeep_android.PHostPermissionsApi.getCallDeliveryMode$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
api.getCallDeliveryMode { result: Result<PCallkeepAndroidCallDeliveryMode> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(GeneratedPigeonUtils.wrapError(error))
} else {
val data = result.getOrNull()
reply.reply(GeneratedPigeonUtils.wrapResult(data))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.webtrit_callkeep_android.PHostPermissionsApi.requestPermissions$separatedMessageChannelSuffix", codec)
if (api != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import androidx.core.content.ContextCompat
import com.webtrit.callkeep.common.ActivityHolder
import com.webtrit.callkeep.common.BatteryModeHelper
import com.webtrit.callkeep.common.PermissionsHelper
import com.webtrit.callkeep.common.TelephonyUtils
import com.webtrit.callkeep.common.toAndroidPermissions
import com.webtrit.callkeep.common.toPPermissionResults
import io.flutter.plugin.common.PluginRegistry
Expand Down Expand Up @@ -75,6 +76,23 @@ class PermissionsApi(
callback.invoke(Result.success(mode))
}

/**
* Reports whether incoming calls are delivered via the Telecom
* [android.telecom.ConnectionService] path or the limited standalone
* foreground-service path used when the device lacks
* `android.software.telecom`. Mirrors the same feature gate the router uses,
* so the value reflects the actually active delivery path.
*/
override fun getCallDeliveryMode(callback: (Result<PCallkeepAndroidCallDeliveryMode>) -> Unit) {
val mode =
if (TelephonyUtils.isTelecomSupported(context)) {
PCallkeepAndroidCallDeliveryMode.TELECOM
} else {
PCallkeepAndroidCallDeliveryMode.STANDALONE
}
callback.invoke(Result.success(mode))
}

/**
* Requests the given permissions from the user.
* @param permissions The list of permissions to request.
Expand Down
36 changes: 36 additions & 0 deletions webtrit_callkeep_android/lib/src/common/callkeep.pigeon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ enum PSpecialPermissionStatusTypeEnum { denied, granted, unknown }

enum PCallkeepAndroidBatteryMode { unrestricted, optimized, restricted, unknown }

enum PCallkeepAndroidCallDeliveryMode { telecom, standalone, unknown }

enum PHandleTypeEnum { generic, number, email }

enum PCallInfoConsts { uuid, dtmf, isVideo, number, name }
Expand Down Expand Up @@ -816,6 +818,9 @@ class _PigeonCodec extends StandardMessageCodec {
} else if (value is PCallkeepConnection) {
buffer.putUint8(154);
writeValue(buffer, value.encode());
} else if (value is PCallkeepAndroidCallDeliveryMode) {
buffer.putUint8(155);
writeValue(buffer, value.index);
} else {
super.writeValue(buffer, value);
}
Expand Down Expand Up @@ -886,6 +891,9 @@ class _PigeonCodec extends StandardMessageCodec {
return PCallkeepDisconnectCause.decode(readValue(buffer)!);
case 154:
return PCallkeepConnection.decode(readValue(buffer)!);
case 155:
final int? value = readValue(buffer) as int?;
return value == null ? null : PCallkeepAndroidCallDeliveryMode.values[value];
default:
return super.readValueOfType(type, buffer);
}
Expand Down Expand Up @@ -1198,6 +1206,34 @@ class PHostPermissionsApi {
}
}

Future<PCallkeepAndroidCallDeliveryMode> getCallDeliveryMode() async {
final String pigeonVar_channelName =
'dev.flutter.pigeon.webtrit_callkeep_android.PHostPermissionsApi.getCallDeliveryMode$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(null);
final List<Object?>? pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
throw PlatformException(
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else if (pigeonVar_replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
return (pigeonVar_replyList[0] as PCallkeepAndroidCallDeliveryMode?)!;
}
}

Future<List<PPermissionResult>> requestPermissions(List<PCallkeepPermission> permissions) async {
final String pigeonVar_channelName =
'dev.flutter.pigeon.webtrit_callkeep_android.PHostPermissionsApi.requestPermissions$pigeonVar_messageChannelSuffix';
Expand Down
13 changes: 13 additions & 0 deletions webtrit_callkeep_android/lib/src/common/converters.dart
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,19 @@ extension PCallkeepAndroidBatteryModeConverter on PCallkeepAndroidBatteryMode {
}
}

extension PCallkeepAndroidCallDeliveryModeConverter on PCallkeepAndroidCallDeliveryMode {
CallkeepAndroidCallDeliveryMode toCallkeep() {
switch (this) {
case PCallkeepAndroidCallDeliveryMode.telecom:
return CallkeepAndroidCallDeliveryMode.telecom;
case PCallkeepAndroidCallDeliveryMode.standalone:
return CallkeepAndroidCallDeliveryMode.standalone;
case PCallkeepAndroidCallDeliveryMode.unknown:
return CallkeepAndroidCallDeliveryMode.unknown;
}
}
}

extension CallkeepLifecycleTypeConverter on CallkeepLifecycleEvent {
PCallkeepLifecycleEvent toPigeon() {
switch (this) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ class WebtritCallkeepAndroid extends WebtritCallkeepPlatform {
return _permissionsApi.getBatteryMode().then((value) => value.toCallkeep());
}

@override
Future<CallkeepAndroidCallDeliveryMode> getCallDeliveryMode() {
return _permissionsApi.getCallDeliveryMode().then((value) => value.toCallkeep());
}

@override
Future<Map<String, dynamic>> getDiagnosticReport() async {
final rawData = await _diagnosticsApi.getDiagnosticReport();
Expand Down
7 changes: 7 additions & 0 deletions webtrit_callkeep_android/pigeons/callkeep.messages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class PPermissionResult {

enum PCallkeepAndroidBatteryMode { unrestricted, optimized, restricted, unknown }

enum PCallkeepAndroidCallDeliveryMode { telecom, standalone, unknown }

enum PHandleTypeEnum { generic, number, email }

enum PCallInfoConsts { uuid, dtmf, isVideo, number, name }
Expand Down Expand Up @@ -261,6 +263,11 @@ abstract class PHostPermissionsApi {
@async
PCallkeepAndroidBatteryMode getBatteryMode();

/// How incoming calls are delivered: Telecom `ConnectionService` vs the
/// limited standalone foreground service (device without `android.software.telecom`).
@async
PCallkeepAndroidCallDeliveryMode getCallDeliveryMode();

@async
List<PPermissionResult> requestPermissions(List<PCallkeepPermission> permissions);

Expand Down
18 changes: 18 additions & 0 deletions webtrit_callkeep_android/test/converters_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,24 @@ void main() {
});
});

// ---------------------------------------------------------------------------
// PCallkeepAndroidCallDeliveryModeConverter
// ---------------------------------------------------------------------------

group('PCallkeepAndroidCallDeliveryModeConverter.toCallkeep()', () {
test('telecom maps to CallkeepAndroidCallDeliveryMode.telecom', () {
expect(PCallkeepAndroidCallDeliveryMode.telecom.toCallkeep(), CallkeepAndroidCallDeliveryMode.telecom);
});

test('standalone maps to CallkeepAndroidCallDeliveryMode.standalone', () {
expect(PCallkeepAndroidCallDeliveryMode.standalone.toCallkeep(), CallkeepAndroidCallDeliveryMode.standalone);
});

test('unknown maps to CallkeepAndroidCallDeliveryMode.unknown', () {
expect(PCallkeepAndroidCallDeliveryMode.unknown.toCallkeep(), CallkeepAndroidCallDeliveryMode.unknown);
});
});

// ---------------------------------------------------------------------------
// CallkeepLifecycleTypeConverter (CallkeepLifecycleEvent -> PCallkeepLifecycleEvent)
// ---------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,21 @@ void main() {
expect(await WebtritCallkeepPlatform.instance.getBatteryMode(), CallkeepAndroidBatteryMode.restricted);
});

test('getCallDeliveryMode returns telecom', () async {
_mockPigeon('$_prefix.PHostPermissionsApi.getCallDeliveryMode', PCallkeepAndroidCallDeliveryMode.telecom);
expect(await WebtritCallkeepPlatform.instance.getCallDeliveryMode(), CallkeepAndroidCallDeliveryMode.telecom);
});

test('getCallDeliveryMode returns standalone', () async {
_mockPigeon('$_prefix.PHostPermissionsApi.getCallDeliveryMode', PCallkeepAndroidCallDeliveryMode.standalone);
expect(await WebtritCallkeepPlatform.instance.getCallDeliveryMode(), CallkeepAndroidCallDeliveryMode.standalone);
});

test('getCallDeliveryMode returns unknown', () async {
_mockPigeon('$_prefix.PHostPermissionsApi.getCallDeliveryMode', PCallkeepAndroidCallDeliveryMode.unknown);
expect(await WebtritCallkeepPlatform.instance.getCallDeliveryMode(), CallkeepAndroidCallDeliveryMode.unknown);
});

test('requestPermissions maps readPhoneState to granted', () async {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMessageHandler(
'$_prefix.PHostPermissionsApi.requestPermissions',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/// How incoming calls are delivered on Android.
///
/// - [telecom]: the device supports `android.software.telecom`, so calls go
/// through the system Telecom `android.telecom.ConnectionService` path (full integration).
/// - [standalone]: the device lacks Telecom, so calls use a limited standalone
/// foreground service. Delivery may be throttled by the system (Doze,
/// background restrictions) and outgoing calls, hold and Bluetooth/wired
/// headset selection are not available.
/// - [unknown]: the mode could not be determined or the platform is not Android.
enum CallkeepAndroidCallDeliveryMode { telecom, standalone, unknown }
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export 'callkeep_android_battery_mode.dart';
export 'callkeep_android_call_delivery_mode.dart';
export 'callkeep_incoming_call_metadata.dart';
export 'callkeep_audio_device.dart';
export 'callkeep_call_request_error.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ abstract class WebtritCallkeepPlatform extends PlatformInterface {
throw UnimplementedError('getBatteryMode() has not been implemented.');
}

/// Returns how incoming calls are delivered (Telecom vs limited standalone).
Future<CallkeepAndroidCallDeliveryMode> getCallDeliveryMode() {
throw UnimplementedError('getCallDeliveryMode() has not been implemented.');
}
Comment thread
SERDUN marked this conversation as resolved.

/// Requests the specified [permissions] on Android.
///
/// Returns a [Map] where:
Expand Down
3 changes: 3 additions & 0 deletions webtrit_callkeep_web/lib/webtrit_callkeep_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ class WebtritCallkeepWeb extends WebtritCallkeepPlatform {
@override
Future<CallkeepAndroidBatteryMode> getBatteryMode() async => CallkeepAndroidBatteryMode.unknown;

@override
Future<CallkeepAndroidCallDeliveryMode> getCallDeliveryMode() async => CallkeepAndroidCallDeliveryMode.unknown;

@override
Future<Map<CallkeepPermission, CallkeepSpecialPermissionStatus>> requestPermissions(
List<CallkeepPermission> permissions,
Expand Down
Loading