/* * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.contacts.sdn import android.Manifest.permission import android.annotation.SuppressLint import android.content.Context import android.content.pm.PackageManager import android.telephony.CarrierConfigManager import android.telephony.SubscriptionManager import android.util.Log import com.android.contacts.model.SimCard import com.android.contacts.util.PermissionsUtil import com.android.contacts.util.PhoneNumberHelper /** Repository to fetch Sdn data from [CarrierConfigManager]. */ class SdnRepository constructor(private val context: Context) { fun isSdnPresent(): Boolean { if ( !hasTelephony() || !PermissionsUtil.hasPermission(context, permission.READ_PHONE_STATE) || !PermissionsUtil.hasPermission(context, permission.READ_PHONE_NUMBERS) || !PermissionsUtil.hasPermission(context, permission.READ_CALL_LOG) ) { return false } val simCardList = getSimCardInformation() for (simCard in simCardList) { if (fetchSdnFromCarrierConfig(simCard).isNotEmpty()) { Log.i(TAG, "Found SDN list from CarrierConfig") return true } } return false } fun fetchSdn(): List { val simCardList = getSimCardInformation() return simCardList .flatMap { fetchSdnFromCarrierConfig(it) } .distinct() .sortedBy { it.serviceName } } // Permission check isn't recognized by the linter. @SuppressLint("MissingPermission") fun getSimCardInformation(): List { val subscriptionManager = context.getSystemService(SubscriptionManager::class.java) return subscriptionManager?.activeSubscriptionInfoList?.filterNotNull()?.mapNotNull { if (it.subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { null } else { SimCard.create(it) } } ?: emptyList() } @Suppress("Deprecation", "MissingPermission") private fun fetchSdnFromCarrierConfig(simCard: SimCard): List { val carrierConfigManager = context.getSystemService(CarrierConfigManager::class.java) val carrierConfig = carrierConfigManager?.getConfigForSubId(simCard.subscriptionId) ?: return emptyList() val nameList: List = carrierConfig .getStringArray(CarrierConfigManager.KEY_CARRIER_SERVICE_NAME_STRING_ARRAY) ?.map { it?.trim() ?: "" } ?: return emptyList() val numberList: List = carrierConfig .getStringArray(CarrierConfigManager.KEY_CARRIER_SERVICE_NUMBER_STRING_ARRAY) ?.map { it?.trim() ?: "" } ?: return emptyList() if (nameList.isEmpty() || nameList.size != numberList.size) return emptyList() val sdnList = mutableListOf() nameList.zip(numberList).forEach { (sdnServiceName, sdnNumber) -> if (sdnServiceName.isNotBlank() && PhoneNumberHelper.isDialablePhoneNumber(sdnNumber)) { sdnList.add(Sdn(sdnServiceName, sdnNumber)) } } return sdnList } private fun hasTelephony(): Boolean { return context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) } companion object { private val TAG = SdnRepository::class.java.simpleName } } /** Hold the Service dialing number information to be displayed in SdnActivity. */ data class Sdn( val serviceName: String, val serviceNumber: String, ) { /** Generate lookup key that will help identify SDN when Opening QuickContact. */ fun lookupKey(): String { return "non-sim-sdn-" + hashCode() } }