1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.datausage.lib 18 19 import android.content.Context 20 import android.net.NetworkStats 21 import android.net.NetworkTemplate 22 import android.telephony.SubscriptionManager 23 import android.telephony.TelephonyManager 24 import android.util.Log 25 26 /** 27 * Lib class for data usage 28 */ 29 object DataUsageLib { 30 private const val TAG = "DataUsageLib" 31 32 /** 33 * Return mobile NetworkTemplate based on `subId` 34 */ 35 @JvmStatic getMobileTemplatenull36 fun getMobileTemplate(context: Context, subId: Int): NetworkTemplate { 37 val telephonyManager = context.getSystemService(TelephonyManager::class.java)!! 38 val mobileDefaultSubId = telephonyManager.subscriptionId 39 val subscriptionManager = context.getSystemService(SubscriptionManager::class.java)!! 40 val subInfoList = subscriptionManager.availableSubscriptionInfoList 41 if (subInfoList == null) { 42 Log.i(TAG, "Subscription is not inited: $subId") 43 return getMobileTemplateForSubId(telephonyManager, mobileDefaultSubId) 44 } 45 for (subInfo in subInfoList) { 46 if (subInfo?.subscriptionId == subId) { 47 return getNormalizedMobileTemplate(telephonyManager, subId) 48 } 49 } 50 Log.i(TAG, "Subscription is not active: $subId") 51 return getMobileTemplateForSubId(telephonyManager, mobileDefaultSubId) 52 } 53 getNormalizedMobileTemplatenull54 private fun getNormalizedMobileTemplate( 55 telephonyManager: TelephonyManager, 56 subId: Int, 57 ): NetworkTemplate { 58 val mobileTemplate = getMobileTemplateForSubId(telephonyManager, subId) 59 val mergedSubscriberIds = 60 telephonyManager.createForSubscriptionId(subId).mergedImsisFromGroup 61 if (mergedSubscriberIds.isNullOrEmpty()) { 62 Log.i(TAG, "mergedSubscriberIds is empty.") 63 return mobileTemplate 64 } 65 return normalizeMobileTemplate(mobileTemplate, mergedSubscriberIds) 66 } 67 normalizeMobileTemplatenull68 private fun normalizeMobileTemplate( 69 template: NetworkTemplate, 70 merged: Array<String?>, 71 ): NetworkTemplate { 72 val subscriberId = template.subscriberIds.firstOrNull() ?: return template 73 // In some rare cases (e.g. b/243015487), merged subscriberId list might contain 74 // duplicated items. Deduplication for better error handling. 75 val mergedSet = merged.toSet() 76 if (mergedSet.size != merged.size) { 77 Log.wtf(TAG, "Duplicated merged list detected: " + merged.contentToString()) 78 } 79 return if (mergedSet.contains(subscriberId)) { 80 // Requested template subscriber is part of the merge group; return 81 // a template that matches all merged subscribers. 82 NetworkTemplate.Builder(template.matchRule) 83 .setSubscriberIds(mergedSet) 84 .setMeteredness(template.meteredness) 85 .build() 86 } else template 87 } 88 89 @JvmStatic getMobileTemplateForSubIdnull90 fun getMobileTemplateForSubId(telephonyManager: TelephonyManager, subId: Int): NetworkTemplate { 91 // Create template that matches any mobile network when the subscriberId is null. 92 val subscriberId = telephonyManager.getSubscriberId(subId) 93 return when (subscriberId) { 94 null -> NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE) 95 else -> NetworkTemplate.Builder(NetworkTemplate.MATCH_CARRIER) 96 .setSubscriberIds(setOf(subscriberId)) 97 }.setMeteredness(NetworkStats.METERED_YES).build() 98 } 99 } 100