feat: add SIM name handling to call history and display in UI
This commit is contained in:
parent
10728ad6e0
commit
95f747280a
@ -10,6 +10,8 @@ import android.os.Build
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.CallLog
|
import android.provider.CallLog
|
||||||
import android.telecom.TelecomManager
|
import android.telecom.TelecomManager
|
||||||
|
import android.telephony.SubscriptionManager
|
||||||
|
import android.telephony.SubscriptionInfo
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.icing.dialer.KeystoreHelper
|
import com.icing.dialer.KeystoreHelper
|
||||||
@ -321,12 +323,30 @@ class MainActivity : FlutterActivity() {
|
|||||||
val type = it.getInt(it.getColumnIndexOrThrow(CallLog.Calls.TYPE))
|
val type = it.getInt(it.getColumnIndexOrThrow(CallLog.Calls.TYPE))
|
||||||
val date = it.getLong(it.getColumnIndexOrThrow(CallLog.Calls.DATE))
|
val date = it.getLong(it.getColumnIndexOrThrow(CallLog.Calls.DATE))
|
||||||
val duration = it.getLong(it.getColumnIndexOrThrow(CallLog.Calls.DURATION))
|
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<String, Any?>(
|
val map = mutableMapOf<String, Any?>(
|
||||||
"number" to number,
|
"number" to number,
|
||||||
"type" to type,
|
"type" to type,
|
||||||
"date" to date,
|
"date" to date,
|
||||||
"duration" to duration
|
"duration" to duration,
|
||||||
|
"subscription_id" to subscriptionId,
|
||||||
|
"sim_name" to simName
|
||||||
)
|
)
|
||||||
logsList.add(map)
|
logsList.add(map)
|
||||||
}
|
}
|
||||||
@ -334,6 +354,35 @@ class MainActivity : FlutterActivity() {
|
|||||||
return logsList
|
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?) {
|
private fun handleIncomingCallIntent(intent: Intent?) {
|
||||||
intent?.let {
|
intent?.let {
|
||||||
if (it.getBooleanExtra("isIncomingCall", false)) {
|
if (it.getBooleanExtra("isIncomingCall", false)) {
|
||||||
|
@ -19,6 +19,7 @@ class History {
|
|||||||
final String callType; // 'incoming' or 'outgoing'
|
final String callType; // 'incoming' or 'outgoing'
|
||||||
final String callStatus; // 'missed' or 'answered'
|
final String callStatus; // 'missed' or 'answered'
|
||||||
final int attempts;
|
final int attempts;
|
||||||
|
final String? simName; // Name of the SIM used for the call
|
||||||
|
|
||||||
History(
|
History(
|
||||||
this.contact,
|
this.contact,
|
||||||
@ -26,6 +27,7 @@ class History {
|
|||||||
this.callType,
|
this.callType,
|
||||||
this.callStatus,
|
this.callStatus,
|
||||||
this.attempts,
|
this.attempts,
|
||||||
|
this.simName,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,6 +160,22 @@ class HistoryPageState extends State<HistoryPage>
|
|||||||
return null;
|
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.
|
/// Request permission for reading call logs.
|
||||||
Future<bool> _requestCallLogPermission() async {
|
Future<bool> _requestCallLogPermission() async {
|
||||||
var status = await Permission.phone.status;
|
var status = await Permission.phone.status;
|
||||||
@ -247,8 +265,22 @@ class HistoryPageState extends State<HistoryPage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
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.
|
// Yield every 10 iterations to avoid blocking the UI.
|
||||||
if (i % 10 == 0) await Future.delayed(Duration(milliseconds: 1));
|
if (i % 10 == 0) await Future.delayed(Duration(milliseconds: 1));
|
||||||
}
|
}
|
||||||
@ -345,8 +377,22 @@ class HistoryPageState extends State<HistoryPage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
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.
|
// Yield every 10 iterations to avoid blocking the UI.
|
||||||
if (i % 10 == 0) await Future.delayed(Duration(milliseconds: 1));
|
if (i % 10 == 0) await Future.delayed(Duration(milliseconds: 1));
|
||||||
}
|
}
|
||||||
@ -559,9 +605,22 @@ class HistoryPageState extends State<HistoryPage>
|
|||||||
_obfuscateService.obfuscateData(contact.displayName),
|
_obfuscateService.obfuscateData(contact.displayName),
|
||||||
style: const TextStyle(color: Colors.white),
|
style: const TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Column(
|
||||||
DateFormat('MMM dd, hh:mm a').format(history.date),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
style: const TextStyle(color: Colors.grey),
|
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(
|
trailing: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@ -771,6 +830,11 @@ class CallDetailsPage extends StatelessWidget {
|
|||||||
label: 'Attempts:',
|
label: 'Attempts:',
|
||||||
value: '${history.attempts}',
|
value: '${history.attempts}',
|
||||||
),
|
),
|
||||||
|
if (history.simName != null)
|
||||||
|
DetailRow(
|
||||||
|
label: 'SIM Used:',
|
||||||
|
value: history.simName!,
|
||||||
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
if (contact.phones.isNotEmpty)
|
if (contact.phones.isNotEmpty)
|
||||||
DetailRow(
|
DetailRow(
|
||||||
|
Loading…
Reference in New Issue
Block a user