From 95f747280ab5703ad63b7cd385fddb365ec15e5d Mon Sep 17 00:00:00 2001 From: AlexisDanlos <91090088+AlexisDanlos@users.noreply.github.com> Date: Fri, 27 Jun 2025 15:33:13 +0200 Subject: [PATCH] feat: add SIM name handling to call history and display in UI --- .../icing/dialer/activities/MainActivity.kt | 51 ++++++++++++- .../features/history/history_page.dart | 74 +++++++++++++++++-- 2 files changed, 119 insertions(+), 6 deletions(-) diff --git a/dialer/android/app/src/main/kotlin/com/icing/dialer/activities/MainActivity.kt b/dialer/android/app/src/main/kotlin/com/icing/dialer/activities/MainActivity.kt index d7b54b5..e157dc1 100644 --- a/dialer/android/app/src/main/kotlin/com/icing/dialer/activities/MainActivity.kt +++ b/dialer/android/app/src/main/kotlin/com/icing/dialer/activities/MainActivity.kt @@ -10,6 +10,8 @@ import android.os.Build import android.os.Bundle import android.provider.CallLog import android.telecom.TelecomManager +import android.telephony.SubscriptionManager +import android.telephony.SubscriptionInfo import android.util.Log import androidx.core.content.ContextCompat import com.icing.dialer.KeystoreHelper @@ -321,12 +323,30 @@ class MainActivity : FlutterActivity() { val type = it.getInt(it.getColumnIndexOrThrow(CallLog.Calls.TYPE)) val date = it.getLong(it.getColumnIndexOrThrow(CallLog.Calls.DATE)) val duration = it.getLong(it.getColumnIndexOrThrow(CallLog.Calls.DURATION)) + + // Extract subscription ID (SIM card info) if available + var subscriptionId: Int? = null + var simName: String? = null + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { + val subIdColumnIndex = it.getColumnIndex("subscription_id") + if (subIdColumnIndex >= 0) { + subscriptionId = it.getInt(subIdColumnIndex) + // Get the actual SIM name + simName = getSimNameFromSubscriptionId(subscriptionId) + } + } + } catch (e: Exception) { + Log.w(TAG, "Failed to get subscription_id: ${e.message}") + } val map = mutableMapOf( "number" to number, "type" to type, "date" to date, - "duration" to duration + "duration" to duration, + "subscription_id" to subscriptionId, + "sim_name" to simName ) logsList.add(map) } @@ -334,6 +354,35 @@ class MainActivity : FlutterActivity() { return logsList } + private fun getSimNameFromSubscriptionId(subscriptionId: Int?): String? { + if (subscriptionId == null) return null + + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { + val subscriptionManager = getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager + val subscriptionInfo: SubscriptionInfo? = subscriptionManager.getActiveSubscriptionInfo(subscriptionId) + + return subscriptionInfo?.let { info -> + // Try to get display name first, fallback to carrier name, then generic name + when { + !info.displayName.isNullOrBlank() && info.displayName.toString() != info.subscriptionId.toString() -> { + info.displayName.toString() + } + !info.carrierName.isNullOrBlank() -> { + info.carrierName.toString() + } + else -> "SIM ${info.simSlotIndex + 1}" + } + } + } + } catch (e: Exception) { + Log.w(TAG, "Failed to get SIM name for subscription $subscriptionId: ${e.message}") + } + + // Fallback to generic name + return "SIM ${subscriptionId + 1}" + } + private fun handleIncomingCallIntent(intent: Intent?) { intent?.let { if (it.getBooleanExtra("isIncomingCall", false)) { diff --git a/dialer/lib/presentation/features/history/history_page.dart b/dialer/lib/presentation/features/history/history_page.dart index 968acfb..868ac17 100644 --- a/dialer/lib/presentation/features/history/history_page.dart +++ b/dialer/lib/presentation/features/history/history_page.dart @@ -19,6 +19,7 @@ class History { final String callType; // 'incoming' or 'outgoing' final String callStatus; // 'missed' or 'answered' final int attempts; + final String? simName; // Name of the SIM used for the call History( this.contact, @@ -26,6 +27,7 @@ class History { this.callType, this.callStatus, this.attempts, + this.simName, ); } @@ -158,6 +160,22 @@ class HistoryPageState extends State return null; } + /// Helper: Get SIM name from subscription ID + String? _getSimNameFromSubscriptionId(int? subscriptionId) { + if (subscriptionId == null) return null; + + // Map subscription IDs to SIM names + // These values might need to be adjusted based on your device + switch (subscriptionId) { + case 0: + return "SIM 1"; + case 1: + return "SIM 2"; + default: + return "SIM ${subscriptionId + 1}"; + } + } + /// Request permission for reading call logs. Future _requestCallLogPermission() async { var status = await Permission.phone.status; @@ -247,8 +265,22 @@ class HistoryPageState extends State ); } + // Extract SIM information if available + String? simName; + if (entry.containsKey('sim_name') && entry['sim_name'] != null) { + simName = entry['sim_name'] as String; + print("DEBUG: Found sim_name: $simName for number: $number"); // Debug print + } else if (entry.containsKey('subscription_id')) { + final subId = entry['subscription_id']; + print("DEBUG: Found subscription_id: $subId for number: $number, but no sim_name"); // Debug print + simName = _getSimNameFromSubscriptionId(subId); + print("DEBUG: Mapped to SIM name: $simName"); // Debug print + } else { + print("DEBUG: No SIM info found for number: $number"); // Debug print + } + callHistories - .add(History(matchedContact, callDate, callType, callStatus, 1)); + .add(History(matchedContact, callDate, callType, callStatus, 1, simName)); // Yield every 10 iterations to avoid blocking the UI. if (i % 10 == 0) await Future.delayed(Duration(milliseconds: 1)); } @@ -345,8 +377,22 @@ class HistoryPageState extends State ); } + // Extract SIM information if available + String? simName; + if (entry.containsKey('sim_name') && entry['sim_name'] != null) { + simName = entry['sim_name'] as String; + print("DEBUG: Found sim_name: $simName for number: $number"); // Debug print + } else if (entry.containsKey('subscription_id')) { + final subId = entry['subscription_id']; + print("DEBUG: Found subscription_id: $subId for number: $number, but no sim_name"); // Debug print + simName = _getSimNameFromSubscriptionId(subId); + print("DEBUG: Mapped to SIM name: $simName"); // Debug print + } else { + print("DEBUG: No SIM info found for number: $number"); // Debug print + } + callHistories - .add(History(matchedContact, callDate, callType, callStatus, 1)); + .add(History(matchedContact, callDate, callType, callStatus, 1, simName)); // Yield every 10 iterations to avoid blocking the UI. if (i % 10 == 0) await Future.delayed(Duration(milliseconds: 1)); } @@ -559,9 +605,22 @@ class HistoryPageState extends State _obfuscateService.obfuscateData(contact.displayName), style: const TextStyle(color: Colors.white), ), - subtitle: Text( - DateFormat('MMM dd, hh:mm a').format(history.date), - style: const TextStyle(color: Colors.grey), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + DateFormat('MMM dd, hh:mm a').format(history.date), + style: const TextStyle(color: Colors.grey), + ), + if (history.simName != null) + Text( + history.simName!, + style: const TextStyle( + color: Colors.blue, + fontSize: 12, + ), + ), + ], ), trailing: Row( mainAxisSize: MainAxisSize.min, @@ -771,6 +830,11 @@ class CallDetailsPage extends StatelessWidget { label: 'Attempts:', value: '${history.attempts}', ), + if (history.simName != null) + DetailRow( + label: 'SIM Used:', + value: history.simName!, + ), const SizedBox(height: 24), if (contact.phones.isNotEmpty) DetailRow(