• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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.internal.telephony.subscription;
18 
19 import android.annotation.CallbackExecutor;
20 import android.annotation.ColorInt;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.UserIdInt;
24 import android.content.ContentValues;
25 import android.content.Context;
26 import android.database.Cursor;
27 import android.net.Uri;
28 import android.os.Handler;
29 import android.os.Looper;
30 import android.os.ParcelUuid;
31 import android.provider.Telephony;
32 import android.provider.Telephony.SimInfo;
33 import android.telephony.CarrierConfigManager;
34 import android.telephony.SubscriptionInfo;
35 import android.telephony.SubscriptionManager;
36 import android.telephony.SubscriptionManager.DataRoamingMode;
37 import android.telephony.SubscriptionManager.DeviceToDeviceStatusSharingPreference;
38 import android.telephony.SubscriptionManager.ProfileClass;
39 import android.telephony.SubscriptionManager.SimDisplayNameSource;
40 import android.telephony.SubscriptionManager.SubscriptionType;
41 import android.telephony.SubscriptionManager.UsageSetting;
42 import android.telephony.TelephonyManager;
43 import android.telephony.UiccAccessRule;
44 import android.telephony.ims.ImsMmTelManager;
45 import android.text.TextUtils;
46 import android.util.Base64;
47 import android.util.IndentingPrintWriter;
48 import android.util.LocalLog;
49 
50 import com.android.internal.annotations.GuardedBy;
51 import com.android.internal.annotations.VisibleForTesting;
52 import com.android.internal.telephony.flags.FeatureFlags;
53 import com.android.internal.telephony.satellite.SatelliteController;
54 import com.android.internal.telephony.uicc.UiccController;
55 import com.android.internal.util.function.TriConsumer;
56 import com.android.telephony.Rlog;
57 
58 import org.json.JSONArray;
59 import org.json.JSONException;
60 import org.json.JSONObject;
61 
62 import java.io.FileDescriptor;
63 import java.io.PrintWriter;
64 import java.util.AbstractMap;
65 import java.util.ArrayList;
66 import java.util.Arrays;
67 import java.util.HashMap;
68 import java.util.List;
69 import java.util.Map;
70 import java.util.Objects;
71 import java.util.Set;
72 import java.util.concurrent.Executor;
73 import java.util.concurrent.locks.ReadWriteLock;
74 import java.util.concurrent.locks.ReentrantReadWriteLock;
75 import java.util.function.BiFunction;
76 import java.util.function.Function;
77 import java.util.function.Predicate;
78 import java.util.stream.Collectors;
79 
80 /**
81  * The subscription database manager is the wrapper of {@link SimInfo}
82  * table. It's a full memory cache of the entire subscription database, and the update can be
83  * asynchronously or synchronously. The database's cache allows multi threads to read
84  * simultaneously, if no write is ongoing.
85  *
86  * Note that from Android 14, directly writing into the subscription database through content
87  * resolver with {@link SimInfo#CONTENT_URI} will cause cache/db out of sync. All the read/write
88  * to the database should go through {@link SubscriptionManagerService}.
89  */
90 public class SubscriptionDatabaseManager extends Handler {
91     private static final String LOG_TAG = "SDMGR";
92 
93     /** Whether enabling verbose debugging message or not. */
94     private static final boolean VDBG = false;
95 
96     /** Invalid database row index. */
97     private static final int INVALID_ROW_INDEX = -1;
98 
99     /** The mapping from {@link SimInfo} table to {@link SubscriptionInfoInternal} get methods. */
100     private static final Map<String, Function<SubscriptionInfoInternal, ?>>
101             SUBSCRIPTION_GET_METHOD_MAP = Map.ofEntries(
102             new AbstractMap.SimpleImmutableEntry<>(
103                     SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID,
104                     SubscriptionInfoInternal::getSubscriptionId),
105             new AbstractMap.SimpleImmutableEntry<>(
106                     SimInfo.COLUMN_ICC_ID,
107                     SubscriptionInfoInternal::getIccId),
108             new AbstractMap.SimpleImmutableEntry<>(
109                     SimInfo.COLUMN_SIM_SLOT_INDEX,
110                     SubscriptionInfoInternal::getSimSlotIndex),
111             new AbstractMap.SimpleImmutableEntry<>(
112                     SimInfo.COLUMN_DISPLAY_NAME,
113                     SubscriptionInfoInternal::getDisplayName),
114             new AbstractMap.SimpleImmutableEntry<>(
115                     SimInfo.COLUMN_CARRIER_NAME,
116                     SubscriptionInfoInternal::getCarrierName),
117             new AbstractMap.SimpleImmutableEntry<>(
118                     SimInfo.COLUMN_NAME_SOURCE,
119                     SubscriptionInfoInternal::getDisplayNameSource),
120             new AbstractMap.SimpleImmutableEntry<>(
121                     SimInfo.COLUMN_COLOR,
122                     SubscriptionInfoInternal::getIconTint),
123             new AbstractMap.SimpleImmutableEntry<>(
124                     SimInfo.COLUMN_NUMBER,
125                     SubscriptionInfoInternal::getNumber),
126             new AbstractMap.SimpleImmutableEntry<>(
127                     SimInfo.COLUMN_DATA_ROAMING,
128                     SubscriptionInfoInternal::getDataRoaming),
129             new AbstractMap.SimpleImmutableEntry<>(
130                     SimInfo.COLUMN_MCC_STRING,
131                     SubscriptionInfoInternal::getMcc),
132             new AbstractMap.SimpleImmutableEntry<>(
133                     SimInfo.COLUMN_MNC_STRING,
134                     SubscriptionInfoInternal::getMnc),
135             new AbstractMap.SimpleImmutableEntry<>(
136                     SimInfo.COLUMN_EHPLMNS,
137                     SubscriptionInfoInternal::getEhplmns),
138             new AbstractMap.SimpleImmutableEntry<>(
139                     SimInfo.COLUMN_HPLMNS,
140                     SubscriptionInfoInternal::getHplmns),
141             new AbstractMap.SimpleImmutableEntry<>(
142                     SimInfo.COLUMN_IS_EMBEDDED,
143                     SubscriptionInfoInternal::getEmbedded),
144             new AbstractMap.SimpleImmutableEntry<>(
145                     SimInfo.COLUMN_CARD_ID,
146                     SubscriptionInfoInternal::getCardString),
147             new AbstractMap.SimpleImmutableEntry<>(
148                     SimInfo.COLUMN_ACCESS_RULES,
149                     SubscriptionInfoInternal::getNativeAccessRules),
150             new AbstractMap.SimpleImmutableEntry<>(
151                     SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS,
152                     SubscriptionInfoInternal::getCarrierConfigAccessRules),
153             new AbstractMap.SimpleImmutableEntry<>(
154                     SimInfo.COLUMN_IS_REMOVABLE,
155                     SubscriptionInfoInternal::getRemovableEmbedded),
156             new AbstractMap.SimpleImmutableEntry<>(
157                     SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT,
158                     SubscriptionInfoInternal::getCellBroadcastExtremeThreatAlertEnabled),
159             new AbstractMap.SimpleImmutableEntry<>(
160                     SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT,
161                     SubscriptionInfoInternal::getCellBroadcastSevereThreatAlertEnabled),
162             new AbstractMap.SimpleImmutableEntry<>(
163                     SimInfo.COLUMN_CB_AMBER_ALERT,
164                     SubscriptionInfoInternal::getCellBroadcastAmberAlertEnabled),
165             new AbstractMap.SimpleImmutableEntry<>(
166                     SimInfo.COLUMN_CB_EMERGENCY_ALERT,
167                     SubscriptionInfoInternal::getCellBroadcastEmergencyAlertEnabled),
168             new AbstractMap.SimpleImmutableEntry<>(
169                     SimInfo.COLUMN_CB_ALERT_SOUND_DURATION,
170                     SubscriptionInfoInternal::getCellBroadcastAlertSoundDuration),
171             new AbstractMap.SimpleImmutableEntry<>(
172                     SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL,
173                     SubscriptionInfoInternal::getCellBroadcastAlertReminderInterval),
174             new AbstractMap.SimpleImmutableEntry<>(
175                     SimInfo.COLUMN_CB_ALERT_VIBRATE,
176                     SubscriptionInfoInternal::getCellBroadcastAlertVibrationEnabled),
177             new AbstractMap.SimpleImmutableEntry<>(
178                     SimInfo.COLUMN_CB_ALERT_SPEECH,
179                     SubscriptionInfoInternal::getCellBroadcastAlertSpeechEnabled),
180             new AbstractMap.SimpleImmutableEntry<>(
181                     SimInfo.COLUMN_CB_ETWS_TEST_ALERT,
182                     SubscriptionInfoInternal::getCellBroadcastEtwsTestAlertEnabled),
183             new AbstractMap.SimpleImmutableEntry<>(
184                     SimInfo.COLUMN_CB_CHANNEL_50_ALERT,
185                     SubscriptionInfoInternal::getCellBroadcastAreaInfoMessageEnabled),
186             new AbstractMap.SimpleImmutableEntry<>(
187                     SimInfo.COLUMN_CB_CMAS_TEST_ALERT,
188                     SubscriptionInfoInternal::getCellBroadcastTestAlertEnabled),
189             new AbstractMap.SimpleImmutableEntry<>(
190                     SimInfo.COLUMN_CB_OPT_OUT_DIALOG,
191                     SubscriptionInfoInternal::getCellBroadcastOptOutDialogEnabled),
192             new AbstractMap.SimpleImmutableEntry<>(
193                     SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED,
194                     SubscriptionInfoInternal::getEnhanced4GModeEnabled),
195             new AbstractMap.SimpleImmutableEntry<>(
196                     SimInfo.COLUMN_VT_IMS_ENABLED,
197                     SubscriptionInfoInternal::getVideoTelephonyEnabled),
198             new AbstractMap.SimpleImmutableEntry<>(
199                     SimInfo.COLUMN_WFC_IMS_ENABLED,
200                     SubscriptionInfoInternal::getWifiCallingEnabled),
201             new AbstractMap.SimpleImmutableEntry<>(
202                     SimInfo.COLUMN_WFC_IMS_MODE,
203                     SubscriptionInfoInternal::getWifiCallingMode),
204             new AbstractMap.SimpleImmutableEntry<>(
205                     SimInfo.COLUMN_WFC_IMS_ROAMING_MODE,
206                     SubscriptionInfoInternal::getWifiCallingModeForRoaming),
207             new AbstractMap.SimpleImmutableEntry<>(
208                     SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED,
209                     SubscriptionInfoInternal::getWifiCallingEnabledForRoaming),
210             new AbstractMap.SimpleImmutableEntry<>(
211                     SimInfo.COLUMN_IS_OPPORTUNISTIC,
212                     SubscriptionInfoInternal::getOpportunistic),
213             new AbstractMap.SimpleImmutableEntry<>(
214                     SimInfo.COLUMN_GROUP_UUID,
215                     SubscriptionInfoInternal::getGroupUuid),
216             new AbstractMap.SimpleImmutableEntry<>(
217                     SimInfo.COLUMN_ISO_COUNTRY_CODE,
218                     SubscriptionInfoInternal::getCountryIso),
219             new AbstractMap.SimpleImmutableEntry<>(
220                     SimInfo.COLUMN_CARRIER_ID,
221                     SubscriptionInfoInternal::getCarrierId),
222             new AbstractMap.SimpleImmutableEntry<>(
223                     SimInfo.COLUMN_PROFILE_CLASS,
224                     SubscriptionInfoInternal::getProfileClass),
225             new AbstractMap.SimpleImmutableEntry<>(
226                     SimInfo.COLUMN_SUBSCRIPTION_TYPE,
227                     SubscriptionInfoInternal::getSubscriptionType),
228             new AbstractMap.SimpleImmutableEntry<>(
229                     SimInfo.COLUMN_GROUP_OWNER,
230                     SubscriptionInfoInternal::getGroupOwner),
231             new AbstractMap.SimpleImmutableEntry<>(
232                     SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES,
233                     SubscriptionInfoInternal::getEnabledMobileDataPolicies),
234             new AbstractMap.SimpleImmutableEntry<>(
235                     SimInfo.COLUMN_IMSI,
236                     SubscriptionInfoInternal::getImsi),
237             new AbstractMap.SimpleImmutableEntry<>(
238                     SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED,
239                     SubscriptionInfoInternal::getUiccApplicationsEnabled),
240             new AbstractMap.SimpleImmutableEntry<>(
241                     SimInfo.COLUMN_IMS_RCS_UCE_ENABLED,
242                     SubscriptionInfoInternal::getRcsUceEnabled),
243             new AbstractMap.SimpleImmutableEntry<>(
244                     SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED,
245                     SubscriptionInfoInternal::getCrossSimCallingEnabled),
246             new AbstractMap.SimpleImmutableEntry<>(
247                     SimInfo.COLUMN_RCS_CONFIG,
248                     SubscriptionInfoInternal::getRcsConfig),
249             new AbstractMap.SimpleImmutableEntry<>(
250                     SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS,
251                     SubscriptionInfoInternal::getAllowedNetworkTypesForReasons),
252             new AbstractMap.SimpleImmutableEntry<>(
253                     SimInfo.COLUMN_D2D_STATUS_SHARING,
254                     SubscriptionInfoInternal::getDeviceToDeviceStatusSharingPreference),
255             new AbstractMap.SimpleImmutableEntry<>(
256                     SimInfo.COLUMN_VOIMS_OPT_IN_STATUS,
257                     SubscriptionInfoInternal::getVoImsOptInEnabled),
258             new AbstractMap.SimpleImmutableEntry<>(
259                     SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS,
260                     SubscriptionInfoInternal::getDeviceToDeviceStatusSharingContacts),
261             new AbstractMap.SimpleImmutableEntry<>(
262                     SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED,
263                     SubscriptionInfoInternal::getNrAdvancedCallingEnabled),
264             new AbstractMap.SimpleImmutableEntry<>(
265                     SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER,
266                     SubscriptionInfoInternal::getNumberFromCarrier),
267             new AbstractMap.SimpleImmutableEntry<>(
268                     SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS,
269                     SubscriptionInfoInternal::getNumberFromIms),
270             new AbstractMap.SimpleImmutableEntry<>(
271                     SimInfo.COLUMN_PORT_INDEX,
272                     SubscriptionInfoInternal::getPortIndex),
273             new AbstractMap.SimpleImmutableEntry<>(
274                     SimInfo.COLUMN_USAGE_SETTING,
275                     SubscriptionInfoInternal::getUsageSetting),
276             new AbstractMap.SimpleImmutableEntry<>(
277                     SimInfo.COLUMN_TP_MESSAGE_REF,
278                     SubscriptionInfoInternal::getLastUsedTPMessageReference),
279             new AbstractMap.SimpleImmutableEntry<>(
280                     SimInfo.COLUMN_USER_HANDLE,
281                     SubscriptionInfoInternal::getUserId),
282             new AbstractMap.SimpleImmutableEntry<>(
283                     SimInfo.COLUMN_SATELLITE_ENABLED,
284                     SubscriptionInfoInternal::getSatelliteEnabled),
285             new AbstractMap.SimpleImmutableEntry<>(
286                     SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
287                     SubscriptionInfoInternal::getSatelliteAttachEnabledForCarrier),
288             new AbstractMap.SimpleImmutableEntry<>(
289                     SimInfo.COLUMN_IS_ONLY_NTN,
290                     SubscriptionInfoInternal::getOnlyNonTerrestrialNetwork),
291             new AbstractMap.SimpleImmutableEntry<>(
292                     SimInfo.COLUMN_SERVICE_CAPABILITIES,
293                     SubscriptionInfoInternal::getServiceCapabilities),
294             new AbstractMap.SimpleImmutableEntry<>(
295                     SimInfo.COLUMN_TRANSFER_STATUS,
296                     SubscriptionInfoInternal::getTransferStatus),
297             new AbstractMap.SimpleImmutableEntry<>(
298                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_STATUS,
299                     SubscriptionInfoInternal::getSatelliteEntitlementStatus),
300             new AbstractMap.SimpleImmutableEntry<>(
301                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS,
302                     SubscriptionInfoInternal::getSatelliteEntitlementPlmns),
303             new AbstractMap.SimpleImmutableEntry<>(
304                     SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED,
305                     SubscriptionInfoInternal::getSatelliteESOSSupported),
306             new AbstractMap.SimpleImmutableEntry<>(
307                     SimInfo.COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM,
308                     SubscriptionInfoInternal::getIsSatelliteProvisionedForNonIpDatagram),
309             new AbstractMap.SimpleImmutableEntry<>(
310                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS,
311                     SubscriptionInfoInternal::getSatelliteEntitlementBarredPlmnsList),
312             new AbstractMap.SimpleImmutableEntry<>(
313                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS,
314                     SubscriptionInfoInternal::getSatelliteEntitlementDataPlanForPlmns),
315             new AbstractMap.SimpleImmutableEntry<>(
316                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP,
317                     SubscriptionInfoInternal::getSatelliteEntitlementPlmnsServiceTypes),
318             new AbstractMap.SimpleImmutableEntry<>(
319                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY,
320                     SubscriptionInfoInternal::getSatellitePlmnsDataServicePolicy),
321             new AbstractMap.SimpleImmutableEntry<>(
322                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY,
323                     SubscriptionInfoInternal::getSatellitePlmnsVoiceServicePolicy)
324     );
325 
326     /**
327      * The mapping from columns in {@link android.provider.Telephony.SimInfo} table to
328      * {@link SubscriptionDatabaseManager} setting integer methods.
329      */
330     private static final Map<String, TriConsumer<SubscriptionDatabaseManager, Integer, Integer>>
331             SUBSCRIPTION_SET_INTEGER_METHOD_MAP = Map.ofEntries(
332             new AbstractMap.SimpleImmutableEntry<>(
333                     SimInfo.COLUMN_SIM_SLOT_INDEX,
334                     SubscriptionDatabaseManager::setSimSlotIndex),
335             new AbstractMap.SimpleImmutableEntry<>(
336                     SimInfo.COLUMN_NAME_SOURCE,
337                     SubscriptionDatabaseManager::setDisplayNameSource),
338             new AbstractMap.SimpleImmutableEntry<>(
339                     SimInfo.COLUMN_COLOR,
340                     SubscriptionDatabaseManager::setIconTint),
341             new AbstractMap.SimpleImmutableEntry<>(
342                     SimInfo.COLUMN_DATA_ROAMING,
343                     SubscriptionDatabaseManager::setDataRoaming),
344             new AbstractMap.SimpleImmutableEntry<>(
345                     SimInfo.COLUMN_IS_EMBEDDED,
346                     SubscriptionDatabaseManager::setEmbedded),
347             new AbstractMap.SimpleImmutableEntry<>(
348                     SimInfo.COLUMN_IS_REMOVABLE,
349                     SubscriptionDatabaseManager::setRemovableEmbedded),
350             new AbstractMap.SimpleImmutableEntry<>(
351                     SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT,
352                     SubscriptionDatabaseManager::setCellBroadcastExtremeThreatAlertEnabled),
353             new AbstractMap.SimpleImmutableEntry<>(
354                     SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT,
355                     SubscriptionDatabaseManager::setCellBroadcastSevereThreatAlertEnabled),
356             new AbstractMap.SimpleImmutableEntry<>(
357                     SimInfo.COLUMN_CB_AMBER_ALERT,
358                     SubscriptionDatabaseManager::setCellBroadcastAmberAlertEnabled),
359             new AbstractMap.SimpleImmutableEntry<>(
360                     SimInfo.COLUMN_CB_EMERGENCY_ALERT,
361                     SubscriptionDatabaseManager::setCellBroadcastEmergencyAlertEnabled),
362             new AbstractMap.SimpleImmutableEntry<>(
363                     SimInfo.COLUMN_CB_ALERT_SOUND_DURATION,
364                     SubscriptionDatabaseManager::setCellBroadcastAlertSoundDuration),
365             new AbstractMap.SimpleImmutableEntry<>(
366                     SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL,
367                     SubscriptionDatabaseManager::setCellBroadcastAlertReminderInterval),
368             new AbstractMap.SimpleImmutableEntry<>(
369                     SimInfo.COLUMN_CB_ALERT_VIBRATE,
370                     SubscriptionDatabaseManager::setCellBroadcastAlertVibrationEnabled),
371             new AbstractMap.SimpleImmutableEntry<>(
372                     SimInfo.COLUMN_CB_ALERT_SPEECH,
373                     SubscriptionDatabaseManager::setCellBroadcastAlertSpeechEnabled),
374             new AbstractMap.SimpleImmutableEntry<>(
375                     SimInfo.COLUMN_CB_ETWS_TEST_ALERT,
376                     SubscriptionDatabaseManager::setCellBroadcastEtwsTestAlertEnabled),
377             new AbstractMap.SimpleImmutableEntry<>(
378                     SimInfo.COLUMN_CB_CHANNEL_50_ALERT,
379                     SubscriptionDatabaseManager::setCellBroadcastAreaInfoMessageEnabled),
380             new AbstractMap.SimpleImmutableEntry<>(
381                     SimInfo.COLUMN_CB_CMAS_TEST_ALERT,
382                     SubscriptionDatabaseManager::setCellBroadcastTestAlertEnabled),
383             new AbstractMap.SimpleImmutableEntry<>(
384                     SimInfo.COLUMN_CB_OPT_OUT_DIALOG,
385                     SubscriptionDatabaseManager::setCellBroadcastOptOutDialogEnabled),
386             new AbstractMap.SimpleImmutableEntry<>(
387                     SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED,
388                     SubscriptionDatabaseManager::setEnhanced4GModeEnabled),
389             new AbstractMap.SimpleImmutableEntry<>(
390                     SimInfo.COLUMN_VT_IMS_ENABLED,
391                     SubscriptionDatabaseManager::setVideoTelephonyEnabled),
392             new AbstractMap.SimpleImmutableEntry<>(
393                     SimInfo.COLUMN_WFC_IMS_ENABLED,
394                     SubscriptionDatabaseManager::setWifiCallingEnabled),
395             new AbstractMap.SimpleImmutableEntry<>(
396                     SimInfo.COLUMN_WFC_IMS_MODE,
397                     SubscriptionDatabaseManager::setWifiCallingMode),
398             new AbstractMap.SimpleImmutableEntry<>(
399                     SimInfo.COLUMN_WFC_IMS_ROAMING_MODE,
400                     SubscriptionDatabaseManager::setWifiCallingModeForRoaming),
401             new AbstractMap.SimpleImmutableEntry<>(
402                     SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED,
403                     SubscriptionDatabaseManager::setWifiCallingEnabledForRoaming),
404             new AbstractMap.SimpleImmutableEntry<>(
405                     SimInfo.COLUMN_IS_OPPORTUNISTIC,
406                     SubscriptionDatabaseManager::setOpportunistic),
407             new AbstractMap.SimpleImmutableEntry<>(
408                     SimInfo.COLUMN_CARRIER_ID,
409                     SubscriptionDatabaseManager::setCarrierId),
410             new AbstractMap.SimpleImmutableEntry<>(
411                     SimInfo.COLUMN_PROFILE_CLASS,
412                     SubscriptionDatabaseManager::setProfileClass),
413             new AbstractMap.SimpleImmutableEntry<>(
414                     SimInfo.COLUMN_SUBSCRIPTION_TYPE,
415                     SubscriptionDatabaseManager::setSubscriptionType),
416             new AbstractMap.SimpleImmutableEntry<>(
417                     SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED,
418                     SubscriptionDatabaseManager::setUiccApplicationsEnabled),
419             new AbstractMap.SimpleImmutableEntry<>(
420                     SimInfo.COLUMN_IMS_RCS_UCE_ENABLED,
421                     SubscriptionDatabaseManager::setRcsUceEnabled),
422             new AbstractMap.SimpleImmutableEntry<>(
423                     SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED,
424                     SubscriptionDatabaseManager::setCrossSimCallingEnabled),
425             new AbstractMap.SimpleImmutableEntry<>(
426                     SimInfo.COLUMN_D2D_STATUS_SHARING,
427                     SubscriptionDatabaseManager::setDeviceToDeviceStatusSharingPreference),
428             new AbstractMap.SimpleImmutableEntry<>(
429                     SimInfo.COLUMN_VOIMS_OPT_IN_STATUS,
430                     SubscriptionDatabaseManager::setVoImsOptInEnabled),
431             new AbstractMap.SimpleImmutableEntry<>(
432                     SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED,
433                     SubscriptionDatabaseManager::setNrAdvancedCallingEnabled),
434             new AbstractMap.SimpleImmutableEntry<>(
435                     SimInfo.COLUMN_PORT_INDEX,
436                     SubscriptionDatabaseManager::setPortIndex),
437             new AbstractMap.SimpleImmutableEntry<>(
438                     SimInfo.COLUMN_USAGE_SETTING,
439                     SubscriptionDatabaseManager::setUsageSetting),
440             new AbstractMap.SimpleImmutableEntry<>(
441                     SimInfo.COLUMN_TP_MESSAGE_REF,
442                     SubscriptionDatabaseManager::setLastUsedTPMessageReference),
443             new AbstractMap.SimpleImmutableEntry<>(
444                     SimInfo.COLUMN_USER_HANDLE,
445                     SubscriptionDatabaseManager::setUserId),
446             new AbstractMap.SimpleImmutableEntry<>(
447                     SimInfo.COLUMN_SATELLITE_ENABLED,
448                     SubscriptionDatabaseManager::setSatelliteEnabled),
449             new AbstractMap.SimpleImmutableEntry<>(
450                     SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
451                     SubscriptionDatabaseManager::setSatelliteAttachEnabledForCarrier),
452             new AbstractMap.SimpleImmutableEntry<>(
453                     SimInfo.COLUMN_IS_ONLY_NTN,
454                     SubscriptionDatabaseManager::setNtn),
455             new AbstractMap.SimpleImmutableEntry<>(
456                     SimInfo.COLUMN_SERVICE_CAPABILITIES,
457                     SubscriptionDatabaseManager::setServiceCapabilities),
458             new AbstractMap.SimpleImmutableEntry<>(
459                     SimInfo.COLUMN_TRANSFER_STATUS,
460                     SubscriptionDatabaseManager::setTransferStatus),
461             new AbstractMap.SimpleImmutableEntry<>(
462                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_STATUS,
463                     SubscriptionDatabaseManager::setSatelliteEntitlementStatus),
464             new AbstractMap.SimpleImmutableEntry<>(
465                     SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED,
466                     SubscriptionDatabaseManager::setSatelliteESOSSupported),
467             new AbstractMap.SimpleImmutableEntry<>(
468                     SimInfo.COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM,
469                     SubscriptionDatabaseManager::setIsSatelliteProvisionedForNonIpDatagram)
470     );
471 
472     /**
473      * The mapping from columns in {@link android.provider.Telephony.SimInfo} table to
474      * {@link SubscriptionDatabaseManager} setting string methods.
475      */
476     private static final Map<String, TriConsumer<SubscriptionDatabaseManager, Integer, String>>
477             SUBSCRIPTION_SET_STRING_METHOD_MAP = Map.ofEntries(
478             new AbstractMap.SimpleImmutableEntry<>(
479                     SimInfo.COLUMN_ICC_ID,
480                     SubscriptionDatabaseManager::setIccId),
481             new AbstractMap.SimpleImmutableEntry<>(
482                     SimInfo.COLUMN_DISPLAY_NAME,
483                     SubscriptionDatabaseManager::setDisplayName),
484             new AbstractMap.SimpleImmutableEntry<>(
485                     SimInfo.COLUMN_CARRIER_NAME,
486                     SubscriptionDatabaseManager::setCarrierName),
487             new AbstractMap.SimpleImmutableEntry<>(
488                     SimInfo.COLUMN_NUMBER,
489                     SubscriptionDatabaseManager::setNumber),
490             new AbstractMap.SimpleImmutableEntry<>(
491                     SimInfo.COLUMN_MCC_STRING,
492                     SubscriptionDatabaseManager::setMcc),
493             new AbstractMap.SimpleImmutableEntry<>(
494                     SimInfo.COLUMN_MNC_STRING,
495                     SubscriptionDatabaseManager::setMnc),
496             new AbstractMap.SimpleImmutableEntry<>(
497                     SimInfo.COLUMN_EHPLMNS,
498                     SubscriptionDatabaseManager::setEhplmns),
499             new AbstractMap.SimpleImmutableEntry<>(
500                     SimInfo.COLUMN_HPLMNS,
501                     SubscriptionDatabaseManager::setHplmns),
502             new AbstractMap.SimpleImmutableEntry<>(
503                     SimInfo.COLUMN_CARD_ID,
504                     SubscriptionDatabaseManager::setCardString),
505             new AbstractMap.SimpleImmutableEntry<>(
506                     SimInfo.COLUMN_GROUP_UUID,
507                     SubscriptionDatabaseManager::setGroupUuid),
508             new AbstractMap.SimpleImmutableEntry<>(
509                     SimInfo.COLUMN_ISO_COUNTRY_CODE,
510                     SubscriptionDatabaseManager::setCountryIso),
511             new AbstractMap.SimpleImmutableEntry<>(
512                     SimInfo.COLUMN_GROUP_OWNER,
513                     SubscriptionDatabaseManager::setGroupOwner),
514             new AbstractMap.SimpleImmutableEntry<>(
515                     SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES,
516                     SubscriptionDatabaseManager::setEnabledMobileDataPolicies),
517             new AbstractMap.SimpleImmutableEntry<>(
518                     SimInfo.COLUMN_IMSI,
519                     SubscriptionDatabaseManager::setImsi),
520             new AbstractMap.SimpleImmutableEntry<>(
521                     SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS,
522                     SubscriptionDatabaseManager::setAllowedNetworkTypesForReasons),
523             new AbstractMap.SimpleImmutableEntry<>(
524                     SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS,
525                     SubscriptionDatabaseManager::setDeviceToDeviceStatusSharingContacts),
526             new AbstractMap.SimpleImmutableEntry<>(
527                     SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER,
528                     SubscriptionDatabaseManager::setNumberFromCarrier),
529             new AbstractMap.SimpleImmutableEntry<>(
530                     SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS,
531                     SubscriptionDatabaseManager::setNumberFromIms),
532             new AbstractMap.SimpleImmutableEntry<>(
533                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS,
534                     SubscriptionDatabaseManager::setSatelliteEntitlementPlmns),
535             new AbstractMap.SimpleImmutableEntry<>(
536                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS,
537                     SubscriptionDatabaseManager::setSatelliteEntitlementBarredPlmns),
538             new AbstractMap.SimpleImmutableEntry<>(
539                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS,
540                     SubscriptionDatabaseManager::setSatelliteEntitlementDataPlanForPlmns),
541             new AbstractMap.SimpleImmutableEntry<>(
542                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP,
543                     SubscriptionDatabaseManager::setSatelliteEntitlementPlmnServiceTypeMap),
544             new AbstractMap.SimpleImmutableEntry<>(
545                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY,
546                     SubscriptionDatabaseManager::setSatelliteEntitlementPlmnDataServicePolicy),
547             new AbstractMap.SimpleImmutableEntry<>(
548                     SimInfo.COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY,
549                     SubscriptionDatabaseManager::setSatelliteEntitlementPlmnVoiceServicePolicy)
550     );
551 
552     /**
553      * The mapping from columns in {@link android.provider.Telephony.SimInfo} table to
554      * {@link SubscriptionDatabaseManager} setting byte array methods.
555      */
556     private static final Map<String, TriConsumer<SubscriptionDatabaseManager, Integer, byte[]>>
557             SUBSCRIPTION_SET_BYTE_ARRAY_METHOD_MAP = Map.ofEntries(
558             new AbstractMap.SimpleImmutableEntry<>(
559                     SimInfo.COLUMN_ACCESS_RULES,
560                     SubscriptionDatabaseManager::setNativeAccessRules),
561             new AbstractMap.SimpleImmutableEntry<>(
562                     SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS,
563                     SubscriptionDatabaseManager::setCarrierConfigAccessRules),
564             new AbstractMap.SimpleImmutableEntry<>(
565                     SimInfo.COLUMN_RCS_CONFIG,
566                     SubscriptionDatabaseManager::setRcsConfig)
567     );
568 
569     /**
570      * The columns that should be in-sync between the subscriptions in the same group. Changing
571      * the value in those fields will automatically apply to the rest of the subscriptions in the
572      * group.
573      *
574      * @see SubscriptionManager#getSubscriptionsInGroup(ParcelUuid)
575      */
576     private static final Set<String> GROUP_SHARING_COLUMNS = Set.of(
577             SimInfo.COLUMN_DISPLAY_NAME,
578             SimInfo.COLUMN_NAME_SOURCE,
579             SimInfo.COLUMN_COLOR,
580             SimInfo.COLUMN_DATA_ROAMING,
581             SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED,
582             SimInfo.COLUMN_VT_IMS_ENABLED,
583             SimInfo.COLUMN_WFC_IMS_ENABLED,
584             SimInfo.COLUMN_WFC_IMS_MODE,
585             SimInfo.COLUMN_WFC_IMS_ROAMING_MODE,
586             SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED,
587             SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES,
588             SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED,
589             SimInfo.COLUMN_IMS_RCS_UCE_ENABLED,
590             SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED,
591             SimInfo.COLUMN_RCS_CONFIG,
592             SimInfo.COLUMN_D2D_STATUS_SHARING,
593             SimInfo.COLUMN_VOIMS_OPT_IN_STATUS,
594             SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS,
595             SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED,
596             SimInfo.COLUMN_USER_HANDLE,
597             SimInfo.COLUMN_SATELLITE_ENABLED,
598             SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER
599     );
600 
601     /**
602      * The deprecated columns that do not have corresponding set methods in
603      * {@link SubscriptionDatabaseManager}.
604      */
605     private static final Set<String> DEPRECATED_DATABASE_COLUMNS = Set.of(
606             SimInfo.COLUMN_DISPLAY_NUMBER_FORMAT,
607             SimInfo.COLUMN_MCC,
608             SimInfo.COLUMN_MNC,
609             SimInfo.COLUMN_SIM_PROVISIONING_STATUS,
610             SimInfo.COLUMN_IS_METERED,
611             SimInfo.COLUMN_DATA_ENABLED_OVERRIDE_RULES,
612             SimInfo.COLUMN_ALLOWED_NETWORK_TYPES
613     );
614 
615     /** The context */
616     @NonNull
617     private final Context mContext;
618 
619     /** The feature flags */
620     @NonNull
621     private final FeatureFlags mFeatureFlags;
622 
623     /** The callback used for passing events back to {@link SubscriptionManagerService}. */
624     @NonNull
625     private final SubscriptionDatabaseManagerCallback mCallback;
626 
627     /** UICC controller */
628     private final UiccController mUiccController;
629 
630     /**
631      * The read/write lock to protect the entire database access. Using a Re-entrant read lock as
632      * much more read requests are expected than the write requests. All the access to
633      * {@link #mAllSubscriptionInfoInternalCache} needs to be protected by this lock.
634      */
635     @NonNull
636     private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();
637 
638     /** Indicating whether access the database asynchronously or not. */
639     private final boolean mAsyncMode;
640 
641     /** Local log for most important debug messages. */
642     @NonNull
643     private final LocalLog mLocalLog = new LocalLog(128);
644 
645     /**
646      * The entire subscription database, including subscriptions from inserted, previously inserted
647      * SIMs. This is the full memory cache of the subscription database. The key is the subscription
648      * id. Note all the access to this map needs to be protected by the re-entrant lock
649      * {@link #mReadWriteLock}.
650      *
651      * @see SimInfo
652      */
653     @GuardedBy("mReadWriteLock")
654     @NonNull
655     private final Map<Integer, SubscriptionInfoInternal> mAllSubscriptionInfoInternalCache =
656             new HashMap<>(16);
657 
658     /** Whether database has been initialized after boot up. */
659     @GuardedBy("this")
660     private boolean mDatabaseInitialized = false;
661 
662     /**
663      * This is the callback used for listening events from {@link SubscriptionDatabaseManager}.
664      */
665     public abstract static class SubscriptionDatabaseManagerCallback {
666         /** The executor of the callback. */
667         private final @NonNull Executor mExecutor;
668 
669         /**
670          * Constructor
671          *
672          * @param executor The executor of the callback.
673          */
SubscriptionDatabaseManagerCallback(@onNull @allbackExecutor Executor executor)674         public SubscriptionDatabaseManagerCallback(@NonNull @CallbackExecutor Executor executor) {
675             mExecutor = executor;
676         }
677 
678         /**
679          * @return The executor of the callback.
680          */
681         @VisibleForTesting
getExecutor()682         public @NonNull Executor getExecutor() {
683             return mExecutor;
684         }
685 
686         /**
687          * Invoke the callback from executor.
688          *
689          * @param runnable The callback method to invoke.
690          */
invokeFromExecutor(@onNull Runnable runnable)691         public void invokeFromExecutor(@NonNull Runnable runnable) {
692             mExecutor.execute(runnable);
693         }
694 
695         /**
696          * Called when database has been initialized.
697          */
onInitialized()698         public abstract void onInitialized();
699 
700         /**
701          * Called when subscription changed.
702          *
703          * @param subId The subscription id.
704          */
onSubscriptionChanged(int subId)705         public abstract void onSubscriptionChanged(int subId);
706     }
707 
708     /**
709      * The constructor.
710      *
711      * @param context The context.
712      * @param looper Looper for the handler.
713      * @param featureFlags The feature flags.
714      * @param callback Subscription database callback.
715      */
SubscriptionDatabaseManager(@onNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags, @NonNull SubscriptionDatabaseManagerCallback callback)716     public SubscriptionDatabaseManager(@NonNull Context context, @NonNull Looper looper,
717             @NonNull FeatureFlags featureFlags,
718             @NonNull SubscriptionDatabaseManagerCallback callback) {
719         super(looper);
720         log("Created SubscriptionDatabaseManager.");
721         mContext = context;
722         mCallback = callback;
723         mUiccController = UiccController.getInstance();
724         mAsyncMode = mContext.getResources().getBoolean(
725                 com.android.internal.R.bool.config_subscription_database_async_update);
726         mFeatureFlags = featureFlags;
727         initializeDatabase();
728     }
729 
730     /**
731      * Helper method to get specific field from {@link SubscriptionInfoInternal} by the database
732      * column name. {@link SubscriptionInfoInternal} represent one single record in the
733      * {@link SimInfo} table. So every column has a corresponding get method in
734      * {@link SubscriptionInfoInternal} (except for unused or deprecated columns).
735      *
736      * @param subInfo The subscription info.
737      * @param columnName The database column name.
738      *
739      * @return The corresponding value from {@link SubscriptionInfoInternal}.
740      *
741      * @throws IllegalArgumentException if {@code columnName} is invalid.
742      *
743      * @see android.provider.Telephony.SimInfo for all the columns.
744      */
745     @NonNull
getSubscriptionInfoFieldByColumnName( @onNull SubscriptionInfoInternal subInfo, @NonNull String columnName)746     private static Object getSubscriptionInfoFieldByColumnName(
747             @NonNull SubscriptionInfoInternal subInfo, @NonNull String columnName) {
748         if (SUBSCRIPTION_GET_METHOD_MAP.containsKey(columnName)) {
749             return SUBSCRIPTION_GET_METHOD_MAP.get(columnName).apply(subInfo);
750         }
751         throw new IllegalArgumentException("Invalid column name " + columnName);
752     }
753 
754     /**
755      * Get a specific field from the subscription database by {@code subId} and {@code columnName}.
756      *
757      * @param subId The subscription id.
758      * @param columnName The database column name.
759      *
760      * @return The value from subscription database.
761      *
762      * @throws IllegalArgumentException if {@code subId} or {@code columnName} is invalid.
763      *
764      * @see android.provider.Telephony.SimInfo for all the columns.
765      */
766     @NonNull
getSubscriptionProperty(int subId, @NonNull String columnName)767     public Object getSubscriptionProperty(int subId, @NonNull String columnName) {
768         SubscriptionInfoInternal subInfo = getSubscriptionInfoInternal(subId);
769         if (subInfo == null) {
770             throw new IllegalArgumentException("getSubscriptionProperty: Invalid subId " + subId
771                     + ", columnName=" + columnName);
772         }
773 
774         return getSubscriptionInfoFieldByColumnName(subInfo, columnName);
775     }
776 
777     /**
778      * Set a field in the subscription database. Note not all fields are supported.
779      *
780      * @param subId Subscription Id of Subscription.
781      * @param columnName Column name in the database. Note not all fields are supported.
782      * @param value Value to store in the database.
783      *
784      * @throws IllegalArgumentException if {@code subId} or {@code columnName} is invalid, or
785      * {@code value} cannot be converted to the corresponding database column format.
786      * @throws NumberFormatException if a string value cannot be converted to integer.
787      * @throws ClassCastException if {@code value} cannot be casted to the required type.
788      *
789      * @see android.provider.Telephony.SimInfo for all the columns.
790      */
setSubscriptionProperty(int subId, @NonNull String columnName, @NonNull Object value)791     public void setSubscriptionProperty(int subId, @NonNull String columnName,
792             @NonNull Object value) {
793         if (SUBSCRIPTION_SET_INTEGER_METHOD_MAP.containsKey(columnName)) {
794             // For integer type columns, accepting both integer and string that can be converted to
795             // integer.
796             int intValue;
797             if (value instanceof String) {
798                 intValue = Integer.parseInt((String) value);
799             } else if (value instanceof Integer) {
800                 intValue = (int) value;
801             } else {
802                 throw new ClassCastException("columnName=" + columnName + ", cannot cast "
803                         + value.getClass() + " to integer.");
804             }
805             SUBSCRIPTION_SET_INTEGER_METHOD_MAP.get(columnName).accept(this, subId, intValue);
806         } else if (SUBSCRIPTION_SET_STRING_METHOD_MAP.containsKey(columnName)) {
807             // For string type columns. Will throw exception if value is not string type.
808             SUBSCRIPTION_SET_STRING_METHOD_MAP.get(columnName).accept(this, subId, (String) value);
809         } else if (SUBSCRIPTION_SET_BYTE_ARRAY_METHOD_MAP.containsKey(columnName)) {
810             // For byte array type columns, accepting both byte[] and string that can be converted
811             // to byte[] using base 64 encoding/decoding.
812             byte[] byteArrayValue;
813             if (value instanceof String) {
814                 byteArrayValue = Base64.decode((String) value, Base64.DEFAULT);
815             } else if (value instanceof byte[]) {
816                 byteArrayValue = (byte[]) value;
817             } else {
818                 throw new ClassCastException("columnName=" + columnName + ", cannot cast "
819                         + value.getClass() + " to byte[].");
820             }
821             SUBSCRIPTION_SET_BYTE_ARRAY_METHOD_MAP.get(columnName).accept(
822                     this, subId, byteArrayValue);
823         } else {
824             throw new IllegalArgumentException("Does not support set " + columnName + ".");
825         }
826     }
827 
828     /**
829      * Comparing the old/new {@link SubscriptionInfoInternal} and create content values for database
830      * update. If any field in the new subscription info is different from the old one, then each
831      * delta will be added into the {@link ContentValues}.
832      *
833      * @param oldSubInfo The old {@link SubscriptionInfoInternal}.
834      * @param newSubInfo The new {@link SubscriptionInfoInternal}.
835      *
836      * @return The delta content values for database update.
837      */
838     @NonNull
createDeltaContentValues(@ullable SubscriptionInfoInternal oldSubInfo, @NonNull SubscriptionInfoInternal newSubInfo)839     private ContentValues createDeltaContentValues(@Nullable SubscriptionInfoInternal oldSubInfo,
840             @NonNull SubscriptionInfoInternal newSubInfo) {
841         ContentValues deltaContentValues = new ContentValues();
842 
843         for (String columnName : Telephony.SimInfo.getAllColumns()) {
844             if (DEPRECATED_DATABASE_COLUMNS.contains(columnName)) continue;
845             // subId is generated by the database. Cannot be updated.
846             if (columnName.equals(SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID)) continue;
847             Object newValue = getSubscriptionInfoFieldByColumnName(newSubInfo, columnName);
848             if (newValue != null) {
849                 Object oldValue = null;
850                 if (oldSubInfo != null) {
851                     oldValue = getSubscriptionInfoFieldByColumnName(oldSubInfo, columnName);
852                 }
853                 // Some columns need special handling. We need to convert them into a format that
854                 // is accepted by the database.
855                 if (!Objects.equals(oldValue, newValue)) {
856                     deltaContentValues.putObject(columnName, newValue);
857                 }
858             }
859         }
860         return deltaContentValues;
861     }
862 
863     /**
864      * Synchronously insert a new record into the database. This operation is synchronous because
865      * we need to convert the inserted row index into the subscription id.
866      *
867      * @param contentValues The fields of the subscription to be inserted into the database.
868      *
869      * @return The row index of the new record. {@link #INVALID_ROW_INDEX} if insertion failed.
870      */
insertNewRecordIntoDatabaseSync(@onNull ContentValues contentValues)871     private int insertNewRecordIntoDatabaseSync(@NonNull ContentValues contentValues) {
872         Objects.requireNonNull(contentValues);
873         Uri uri = mContext.getContentResolver().insert(SimInfo.CONTENT_URI, contentValues);
874         if (uri != null && uri.getLastPathSegment() != null) {
875             int subId = Integer.parseInt(uri.getLastPathSegment());
876             if (SubscriptionManager.isValidSubscriptionId(subId)) {
877                 logv("insertNewRecordIntoDatabaseSync: contentValues=" + contentValues);
878                 logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId="
879                         + uri.getLastPathSegment());
880                 return subId;
881             }
882         }
883 
884         logel("insertNewRecordIntoDatabaseSync: Failed to insert subscription into database. "
885                 + "contentValues=" + contentValues);
886         return INVALID_ROW_INDEX;
887     }
888 
889     /**
890      * Insert a new subscription info. The subscription info must have subscription id
891      * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}. Note this is a slow method, so be
892      * cautious to call this method.
893      *
894      * @param subInfo The subscription info to update.
895      *
896      * @return The new subscription id. {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} (-1) if
897      * insertion fails.
898      */
insertSubscriptionInfo(@onNull SubscriptionInfoInternal subInfo)899     public int insertSubscriptionInfo(@NonNull SubscriptionInfoInternal subInfo) {
900         Objects.requireNonNull(subInfo);
901         // A new subscription to be inserted must have invalid subscription id.
902         if (SubscriptionManager.isValidSubscriptionId(subInfo.getSubscriptionId())) {
903             throw new RuntimeException("insertSubscriptionInfo: Not a new subscription to "
904                     + "insert. subInfo=" + subInfo);
905         }
906 
907         synchronized (this) {
908             if (!mDatabaseInitialized) {
909                 throw new IllegalStateException(
910                         "Database has not been initialized. Can't insert new "
911                                 + "record at this point.");
912             }
913         }
914 
915         int subId;
916         // Grab the write lock so no other threads can read or write the cache.
917         mReadWriteLock.writeLock().lock();
918         try {
919             // Synchronously insert into the database. Note this should be the only synchronous
920             // write operation performed by the subscription database manager. The reason is that
921             // we need to get the sub id for cache update.
922             subId = insertNewRecordIntoDatabaseSync(createDeltaContentValues(null, subInfo));
923             if (subId > 0) {
924                 mAllSubscriptionInfoInternalCache.put(subId, new SubscriptionInfoInternal
925                         .Builder(subInfo)
926                         .setId(subId).build());
927             } else {
928                 logel("insertSubscriptionInfo: Failed to insert a new subscription. subInfo="
929                         + subInfo);
930             }
931         } finally {
932             mReadWriteLock.writeLock().unlock();
933         }
934 
935         mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId));
936         return subId;
937     }
938 
939     /**
940      * Remove a subscription record from the database.
941      *
942      * @param subId The subscription id of the subscription to be deleted.
943      *
944      * @throws IllegalArgumentException If {@code subId} is invalid.
945      */
removeSubscriptionInfo(int subId)946     public void removeSubscriptionInfo(int subId) {
947         if (!mAllSubscriptionInfoInternalCache.containsKey(subId)) {
948             throw new IllegalArgumentException("subId " + subId + " is invalid.");
949         }
950 
951         mReadWriteLock.writeLock().lock();
952         try {
953             if (mContext.getContentResolver().delete(SimInfo.CONTENT_URI,
954                     SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID + "=?",
955                     new String[]{Integer.toString(subId)}) > 0) {
956                 mAllSubscriptionInfoInternalCache.remove(subId);
957             } else {
958                 logel("Failed to remove subscription with subId=" + subId);
959             }
960         } finally {
961             mReadWriteLock.writeLock().unlock();
962         }
963 
964         mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId));
965     }
966 
967     /**
968      * Update a subscription in the database (synchronously or asynchronously).
969      *
970      * @param subId The subscription id of the subscription to be updated.
971      * @param contentValues The fields to be update.
972      *
973      * @return The number of rows updated. Note if the database is configured as asynchronously
974      * update, then this will be always 1.
975      */
updateDatabase(int subId, @NonNull ContentValues contentValues)976     private int updateDatabase(int subId, @NonNull ContentValues contentValues) {
977         logv("updateDatabase: prepare to update sub " + subId);
978 
979         synchronized (this) {
980             if (!mDatabaseInitialized) {
981                 logel("updateDatabase: Database has not been initialized. Can't update database at "
982                         + "this point. contentValues=" + contentValues);
983                 return 0;
984             }
985         }
986 
987         if (mAsyncMode) {
988             // Perform the update in the handler thread asynchronously.
989             post(() -> {
990                 mContext.getContentResolver().update(Uri.withAppendedPath(
991                         SimInfo.CONTENT_URI, String.valueOf(subId)), contentValues, null, null);
992                 logv("updateDatabase: async updated subscription in the database."
993                             + " subId=" + subId + ", contentValues= " + contentValues.getValues());
994             });
995             return 1;
996         } else {
997             logv("updateDatabase: sync updated subscription in the database."
998                     + " subId=" + subId + ", contentValues= " + contentValues.getValues());
999 
1000             return mContext.getContentResolver().update(Uri.withAppendedPath(
1001                     SimInfo.CONTENT_URI, String.valueOf(subId)), contentValues, null, null);
1002         }
1003     }
1004 
1005     /**
1006      * Update a certain field of subscription in the database. Also update the subscription cache
1007      * {@link #mAllSubscriptionInfoInternalCache}.
1008      *
1009      * @param subId The subscription id.
1010      * @param columnName The database column name from the database table {@link SimInfo}.
1011      * @param newValue The new value to update the subscription info cache
1012      * {@link #mAllSubscriptionInfoInternalCache}.
1013      * @param builderSetMethod The {@link SubscriptionInfo.Builder} method to set a specific field
1014      * when constructing the new {@link SubscriptionInfo}. This should be one of the
1015      * SubscriptionInfoInternal.Builder.setXxxx method.
1016      * @param <T> The type of newValue for subscription cache update.
1017      *
1018      * @throws IllegalArgumentException if the subscription does not exist.
1019      */
writeDatabaseAndCacheHelper(int subId, @NonNull String columnName, @Nullable T newValue, BiFunction<SubscriptionInfoInternal.Builder, T, SubscriptionInfoInternal.Builder> builderSetMethod)1020     private <T> void writeDatabaseAndCacheHelper(int subId, @NonNull String columnName,
1021             @Nullable T newValue,
1022             BiFunction<SubscriptionInfoInternal.Builder, T, SubscriptionInfoInternal.Builder>
1023                     builderSetMethod) {
1024         ContentValues contentValues = new ContentValues();
1025 
1026         // Grab the write lock so no other threads can read or write the cache.
1027         mReadWriteLock.writeLock().lock();
1028         try {
1029             final SubscriptionInfoInternal oldSubInfo =
1030                     mAllSubscriptionInfoInternalCache.get(subId);
1031             if (oldSubInfo == null) {
1032                 logel("Subscription doesn't exist. subId=" + subId + ", columnName=" + columnName);
1033                 throw new IllegalArgumentException("Subscription doesn't exist. subId=" + subId
1034                         + ", columnName=" + columnName);
1035             }
1036 
1037             // Check if writing this field should automatically write to the rest of subscriptions
1038             // in the same group.
1039             final boolean syncToGroup = GROUP_SHARING_COLUMNS.contains(columnName);
1040 
1041             mAllSubscriptionInfoInternalCache.forEach((id, subInfo) -> {
1042                 if (id == subId || (syncToGroup && !oldSubInfo.getGroupUuid().isEmpty()
1043                         && oldSubInfo.getGroupUuid().equals(subInfo.getGroupUuid()))) {
1044                     // Check if the new value is different from the old value in the cache.
1045                     if (!Objects.equals(getSubscriptionInfoFieldByColumnName(subInfo, columnName),
1046                             newValue)) {
1047                         logv("writeDatabaseAndCacheHelper: subId=" + subId + ",columnName="
1048                                 + columnName + ", newValue=" + newValue);
1049                         // If the value is different, then we need to update the cache. Since all
1050                         // fields in SubscriptionInfo are final, we need to create a new
1051                         // SubscriptionInfo.
1052                         SubscriptionInfoInternal.Builder builder = new SubscriptionInfoInternal
1053                                 .Builder(subInfo);
1054 
1055                         // Apply the new value to the builder. This line is equivalent to
1056                         // builder.setXxxxxx(newValue);
1057                         builder = builderSetMethod.apply(builder, newValue);
1058 
1059                         // Prepare the content value for update.
1060                         contentValues.putObject(columnName, newValue);
1061                         if (updateDatabase(id, contentValues) > 0) {
1062                             // Update the subscription database cache.
1063                             mAllSubscriptionInfoInternalCache.put(id, builder.build());
1064                             mCallback.invokeFromExecutor(()
1065                                     -> mCallback.onSubscriptionChanged(subId));
1066                         }
1067                     }
1068                 }
1069             });
1070         } finally {
1071             mReadWriteLock.writeLock().unlock();
1072         }
1073     }
1074 
1075     /**
1076      * Update the database with the {@link SubscriptionInfoInternal}, and also update the cache.
1077      *
1078      * @param newSubInfo The new {@link SubscriptionInfoInternal}.
1079      *
1080      * @throws IllegalArgumentException if the subscription does not exist.
1081      */
updateSubscription(@onNull SubscriptionInfoInternal newSubInfo)1082     public void updateSubscription(@NonNull SubscriptionInfoInternal newSubInfo) {
1083         Objects.requireNonNull(newSubInfo);
1084 
1085         // Grab the write lock so no other threads can read or write the cache.
1086         mReadWriteLock.writeLock().lock();
1087         try {
1088             int subId = newSubInfo.getSubscriptionId();
1089             SubscriptionInfoInternal oldSubInfo = mAllSubscriptionInfoInternalCache.get(
1090                     newSubInfo.getSubscriptionId());
1091             if (oldSubInfo == null) {
1092                 throw new IllegalArgumentException("updateSubscription: subscription does not "
1093                         + "exist. subId=" + subId);
1094             }
1095             if (oldSubInfo.equalsDbItemsOnly(newSubInfo)) return;
1096 
1097             if (updateDatabase(subId, createDeltaContentValues(oldSubInfo, newSubInfo)) > 0) {
1098                 mAllSubscriptionInfoInternalCache.put(subId, newSubInfo);
1099                 mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId));
1100             }
1101         } finally {
1102             mReadWriteLock.writeLock().unlock();
1103         }
1104     }
1105 
1106     /**
1107      * Set the ICCID of the SIM that is associated with the subscription.
1108      *
1109      * @param subId Subscription id.
1110      * @param iccId The ICCID of the SIM that is associated with this subscription.
1111      *
1112      * @throws IllegalArgumentException if the subscription does not exist.
1113      */
setIccId(int subId, @NonNull String iccId)1114     public void setIccId(int subId, @NonNull String iccId) {
1115         Objects.requireNonNull(iccId);
1116         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ICC_ID, iccId,
1117                 SubscriptionInfoInternal.Builder::setIccId);
1118     }
1119 
1120     /**
1121      * Set the SIM index of the slot that currently contains the subscription. Set to
1122      * {@link SubscriptionManager#INVALID_SIM_SLOT_INDEX} if the subscription is inactive.
1123      *
1124      * @param subId Subscription id.
1125      * @param simSlotIndex The SIM slot index.
1126      *
1127      * @throws IllegalArgumentException if the subscription does not exist.
1128      */
setSimSlotIndex(int subId, int simSlotIndex)1129     public void setSimSlotIndex(int subId, int simSlotIndex) {
1130         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_SIM_SLOT_INDEX, simSlotIndex,
1131                 SubscriptionInfoInternal.Builder::setSimSlotIndex);
1132     }
1133 
1134     /**
1135      * Set the name displayed to the user that identifies this subscription. This name is used
1136      * in Settings page and can be renamed by the user.
1137      *
1138      * @param subId Subscription id.
1139      * @param displayName The display name.
1140      *
1141      * @throws IllegalArgumentException if the subscription does not exist.
1142      */
setDisplayName(int subId, @NonNull String displayName)1143     public void setDisplayName(int subId, @NonNull String displayName) {
1144         Objects.requireNonNull(displayName);
1145         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_DISPLAY_NAME, displayName,
1146                 SubscriptionInfoInternal.Builder::setDisplayName);
1147     }
1148 
1149     /**
1150      * Set the name displayed to the user that identifies subscription provider name. This name
1151      * is the SPN displayed in status bar and many other places. Can't be renamed by the user.
1152      *
1153      * @param subId Subscription id.
1154      * @param carrierName The carrier name.
1155      *
1156      * @throws IllegalArgumentException if the subscription does not exist.
1157      */
setCarrierName(int subId, @NonNull String carrierName)1158     public void setCarrierName(int subId, @NonNull String carrierName) {
1159         Objects.requireNonNull(carrierName);
1160         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CARRIER_NAME, carrierName,
1161                 SubscriptionInfoInternal.Builder::setCarrierName);
1162     }
1163 
1164     /**
1165      * Set the source of the display name.
1166      *
1167      * @param subId Subscription id.
1168      * @param displayNameSource The source of the display name.
1169      *
1170      * @throws IllegalArgumentException if the subscription does not exist.
1171      *
1172      * @see SubscriptionInfo#getDisplayName()
1173      */
setDisplayNameSource(int subId, @SimDisplayNameSource int displayNameSource)1174     public void setDisplayNameSource(int subId, @SimDisplayNameSource int displayNameSource) {
1175         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_NAME_SOURCE, displayNameSource,
1176                 SubscriptionInfoInternal.Builder::setDisplayNameSource);
1177     }
1178 
1179     /**
1180      * Set the color to be used for tinting the icon when displaying to the user.
1181      *
1182      * @param subId Subscription id.
1183      * @param iconTint The color to be used for tinting the icon when displaying to the user.
1184      *
1185      * @throws IllegalArgumentException if the subscription does not exist.
1186      */
setIconTint(int subId, @ColorInt int iconTint)1187     public void setIconTint(int subId, @ColorInt int iconTint) {
1188         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_COLOR, iconTint,
1189                 SubscriptionInfoInternal.Builder::setIconTint);
1190     }
1191 
1192     /**
1193      * Set the number presented to the user identify this subscription.
1194      *
1195      * @param subId Subscription id.
1196      * @param number the number presented to the user identify this subscription.
1197      *
1198      * @throws IllegalArgumentException if the subscription does not exist.
1199      */
setNumber(int subId, @NonNull String number)1200     public void setNumber(int subId, @NonNull String number) {
1201         Objects.requireNonNull(number);
1202         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_NUMBER, number,
1203                 SubscriptionInfoInternal.Builder::setNumber);
1204     }
1205 
1206     /**
1207      * Set whether user enables data roaming for this subscription or not.
1208      *
1209      * @param subId Subscription id.
1210      * @param dataRoaming Data roaming mode. Either
1211      * {@link SubscriptionManager#DATA_ROAMING_ENABLE} or
1212      * {@link SubscriptionManager#DATA_ROAMING_DISABLE}
1213      *
1214      * @throws IllegalArgumentException if the subscription does not exist.
1215      */
setDataRoaming(int subId, @DataRoamingMode int dataRoaming)1216     public void setDataRoaming(int subId, @DataRoamingMode int dataRoaming) {
1217         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_DATA_ROAMING, dataRoaming,
1218                 SubscriptionInfoInternal.Builder::setDataRoaming);
1219     }
1220 
1221     /**
1222      * Set the mobile country code.
1223      *
1224      * @param subId Subscription id.
1225      * @param mcc The mobile country code.
1226      *
1227      * @throws IllegalArgumentException if the subscription does not exist.
1228      */
setMcc(int subId, @NonNull String mcc)1229     public void setMcc(int subId, @NonNull String mcc) {
1230         Objects.requireNonNull(mcc);
1231         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_MCC_STRING, mcc,
1232                 SubscriptionInfoInternal.Builder::setMcc);
1233     }
1234 
1235     /**
1236      * Set the mobile network code.
1237      *
1238      * @param subId Subscription id.
1239      * @param mnc Mobile network code.
1240      *
1241      * @throws IllegalArgumentException if the subscription does not exist.
1242      */
setMnc(int subId, @NonNull String mnc)1243     public void setMnc(int subId, @NonNull String mnc) {
1244         Objects.requireNonNull(mnc);
1245         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_MNC_STRING, mnc,
1246                 SubscriptionInfoInternal.Builder::setMnc);
1247     }
1248 
1249     /**
1250      * Set EHPLMNs associated with the subscription.
1251      *
1252      * @param subId Subscription id.
1253      * @param ehplmns EHPLMNs associated with the subscription.
1254      *
1255      * @throws IllegalArgumentException if the subscription does not exist.
1256      */
setEhplmns(int subId, @NonNull String[] ehplmns)1257     public void setEhplmns(int subId, @NonNull String[] ehplmns) {
1258         Objects.requireNonNull(ehplmns);
1259         setEhplmns(subId, Arrays.stream(ehplmns)
1260                 .filter(Predicate.not(TextUtils::isEmpty))
1261                 .collect(Collectors.joining(",")));
1262     }
1263 
1264     /**
1265      * Set EHPLMNs associated with the subscription.
1266      *
1267      * @param subId Subscription id.
1268      * @param ehplmns EHPLMNs associated with the subscription.
1269      *
1270      * @throws IllegalArgumentException if the subscription does not exist.
1271      */
setEhplmns(int subId, @NonNull String ehplmns)1272     public void setEhplmns(int subId, @NonNull String ehplmns) {
1273         Objects.requireNonNull(ehplmns);
1274         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_EHPLMNS, ehplmns,
1275                 SubscriptionInfoInternal.Builder::setEhplmns);
1276     }
1277 
1278     /**
1279      * Set HPLMNs associated with the subscription.
1280      *
1281      * @param subId Subscription id.
1282      * @param hplmns HPLMNs associated with the subscription.
1283      *
1284      * @throws IllegalArgumentException if the subscription does not exist.
1285      */
setHplmns(int subId, @NonNull String[] hplmns)1286     public void setHplmns(int subId, @NonNull String[] hplmns) {
1287         Objects.requireNonNull(hplmns);
1288         setHplmns(subId, Arrays.stream(hplmns)
1289                 .filter(Predicate.not(TextUtils::isEmpty))
1290                 .collect(Collectors.joining(",")));
1291     }
1292 
1293     /**
1294      * Set HPLMNs associated with the subscription.
1295      *
1296      * @param subId Subscription id.
1297      * @param hplmns HPLMNs associated with the subscription.
1298      *
1299      * @throws IllegalArgumentException if the subscription does not exist.
1300      */
setHplmns(int subId, @NonNull String hplmns)1301     public void setHplmns(int subId, @NonNull String hplmns) {
1302         Objects.requireNonNull(hplmns);
1303         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_HPLMNS, hplmns,
1304                 SubscriptionInfoInternal.Builder::setHplmns);
1305     }
1306 
1307     /**
1308      * Set whether the subscription is from eSIM or not.
1309      *
1310      * @param subId Subscription id.
1311      * @param isEmbedded if the subscription is from eSIM.
1312      *
1313      * @throws IllegalArgumentException if the subscription does not exist.
1314      */
setEmbedded(int subId, int isEmbedded)1315     public void setEmbedded(int subId, int isEmbedded) {
1316         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_EMBEDDED, isEmbedded,
1317                 SubscriptionInfoInternal.Builder::setEmbedded);
1318     }
1319 
1320     /**
1321      * Set whether the subscription is from eSIM or not.
1322      *
1323      * @param subId Subscription id.
1324      * @param isEmbedded {@code true} if the subscription is from eSIM.
1325      *
1326      * @throws IllegalArgumentException if the subscription does not exist.
1327      */
setEmbedded(int subId, boolean isEmbedded)1328     public void setEmbedded(int subId, boolean isEmbedded) {
1329         setEmbedded(subId, isEmbedded ? 1 : 0);
1330     }
1331 
1332     /**
1333      * Set the card string of the SIM card. This is usually the ICCID or EID.
1334      *
1335      * @param subId Subscription id.
1336      * @param cardString The card string of the SIM card.
1337      *
1338      * @throws IllegalArgumentException if the subscription does not exist.
1339      *
1340      * @see SubscriptionInfo#getCardString()
1341      */
setCardString(int subId, @NonNull String cardString)1342     public void setCardString(int subId, @NonNull String cardString) {
1343         Objects.requireNonNull(cardString);
1344         // Also update the public card id.
1345         setCardId(subId, mUiccController.convertToPublicCardId(cardString));
1346         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CARD_ID, cardString,
1347                 SubscriptionInfoInternal.Builder::setCardString);
1348     }
1349 
1350     /**
1351      * Set the card id. This is the non-PII card id converted from
1352      * {@link SubscriptionInfoInternal#getCardString()}. This field only exists in
1353      * {@link SubscriptionInfo}, but not the database.
1354      *
1355      * @param subId Subscription id.
1356      * @param cardId The card id.
1357      *
1358      * @throws IllegalArgumentException if the subscription does not exist.
1359      */
setCardId(int subId, int cardId)1360     public void setCardId(int subId, int cardId) {
1361         // card id does not have a corresponding SimInfo column. So we only update the cache.
1362 
1363         // Grab the write lock so no other threads can read or write the cache.
1364         mReadWriteLock.writeLock().lock();
1365         try {
1366             SubscriptionInfoInternal subInfoCache = mAllSubscriptionInfoInternalCache.get(subId);
1367             if (subInfoCache == null) {
1368                 throw new IllegalArgumentException("setCardId: Subscription doesn't exist. subId="
1369                         + subId);
1370             }
1371             mAllSubscriptionInfoInternalCache.put(subId,
1372                     new SubscriptionInfoInternal.Builder(subInfoCache)
1373                             .setCardId(cardId).build());
1374         } finally {
1375             mReadWriteLock.writeLock().unlock();
1376         }
1377     }
1378 
1379     /**
1380      * Set the native access rules for this subscription, if it is embedded and defines any.
1381      * This does not include access rules for non-embedded subscriptions.
1382      *
1383      * @param subId Subscription id.
1384      * @param nativeAccessRules The native access rules for this subscription.
1385      *
1386      * @throws IllegalArgumentException if the subscription does not exist.
1387      */
setNativeAccessRules(int subId, @NonNull byte[] nativeAccessRules)1388     public void setNativeAccessRules(int subId, @NonNull byte[] nativeAccessRules) {
1389         Objects.requireNonNull(nativeAccessRules);
1390         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES, nativeAccessRules,
1391                 SubscriptionInfoInternal.Builder::setNativeAccessRules);
1392     }
1393 
1394     /**
1395      * Set the carrier certificates for this subscription that are saved in carrier configs.
1396      * This does not include access rules from the Uicc, whether embedded or non-embedded.
1397      *
1398      * @param subId Subscription id.
1399      * @param carrierConfigAccessRules The carrier certificates for this subscription.
1400      *
1401      * @throws IllegalArgumentException if the subscription does not exist.
1402      */
setCarrierConfigAccessRules(int subId, @NonNull byte[] carrierConfigAccessRules)1403     public void setCarrierConfigAccessRules(int subId, @NonNull byte[] carrierConfigAccessRules) {
1404         Objects.requireNonNull(carrierConfigAccessRules);
1405         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS,
1406                 carrierConfigAccessRules,
1407                 SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules);
1408     }
1409 
1410     /**
1411      * Set the carrier certificates for this subscription that are saved in carrier configs.
1412      * This does not include access rules from the Uicc, whether embedded or non-embedded.
1413      *
1414      * @param subId Subscription id.
1415      * @param carrierConfigAccessRules The carrier certificates for this subscription.
1416      *
1417      * @throws IllegalArgumentException if the subscription does not exist.
1418      */
setCarrierConfigAccessRules(int subId, @NonNull UiccAccessRule[] carrierConfigAccessRules)1419     public void setCarrierConfigAccessRules(int subId,
1420             @NonNull UiccAccessRule[] carrierConfigAccessRules) {
1421         Objects.requireNonNull(carrierConfigAccessRules);
1422         byte[] carrierConfigAccessRulesBytes = UiccAccessRule.encodeRules(carrierConfigAccessRules);
1423         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS,
1424                 carrierConfigAccessRulesBytes,
1425                 SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules);
1426     }
1427 
1428     /**
1429      * Set whether an embedded subscription is on a removable card. Such subscriptions are
1430      * marked inaccessible as soon as the current card is removed. Otherwise, they will remain
1431      * accessible unless explicitly deleted. Only meaningful for embedded subscription.
1432      *
1433      * @param subId Subscription id.
1434      * @param isRemovableEmbedded if the subscription is from the removable embedded SIM.
1435      *
1436      * @throws IllegalArgumentException if the subscription does not exist.
1437      */
setRemovableEmbedded(int subId, int isRemovableEmbedded)1438     public void setRemovableEmbedded(int subId, int isRemovableEmbedded) {
1439         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_REMOVABLE, isRemovableEmbedded,
1440                 SubscriptionInfoInternal.Builder::setRemovableEmbedded);
1441     }
1442 
1443     /**
1444      * Set whether cell broadcast extreme threat alert is enabled by the user or not.
1445      *
1446      * @param subId Subscription id.
1447      * @param isExtremeThreatAlertEnabled whether cell broadcast extreme threat alert is enabled by
1448      * the user or not.
1449      *
1450      * @throws IllegalArgumentException if the subscription does not exist.
1451      */
setCellBroadcastExtremeThreatAlertEnabled(int subId, int isExtremeThreatAlertEnabled)1452     public void setCellBroadcastExtremeThreatAlertEnabled(int subId,
1453             int isExtremeThreatAlertEnabled) {
1454         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT,
1455                 isExtremeThreatAlertEnabled,
1456                 SubscriptionInfoInternal.Builder::setCellBroadcastExtremeThreatAlertEnabled);
1457     }
1458 
1459     /**
1460      * Set whether cell broadcast severe threat alert is enabled by the user or not.
1461      *
1462      * @param subId Subscription id.
1463      * @param isSevereThreatAlertEnabled whether cell broadcast severe threat alert is enabled by
1464      * the user or not.
1465      *
1466      * @throws IllegalArgumentException if the subscription does not exist.
1467      */
setCellBroadcastSevereThreatAlertEnabled(int subId, int isSevereThreatAlertEnabled)1468     public void setCellBroadcastSevereThreatAlertEnabled(int subId,
1469             int isSevereThreatAlertEnabled) {
1470         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT,
1471                 isSevereThreatAlertEnabled,
1472                 SubscriptionInfoInternal.Builder::setCellBroadcastSevereThreatAlertEnabled);
1473     }
1474 
1475     /**
1476      * Set whether cell broadcast amber alert is enabled by the user or not.
1477      *
1478      * @param subId Subscription id.
1479      * @param isAmberAlertEnabled whether cell broadcast amber alert is enabled by
1480      * the user or not.
1481      *
1482      * @throws IllegalArgumentException if the subscription does not exist.
1483      */
setCellBroadcastAmberAlertEnabled(int subId, int isAmberAlertEnabled)1484     public void setCellBroadcastAmberAlertEnabled(int subId, int isAmberAlertEnabled) {
1485         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_AMBER_ALERT, isAmberAlertEnabled,
1486                 SubscriptionInfoInternal.Builder::setCellBroadcastAmberAlertEnabled);
1487     }
1488 
1489     /**
1490      * Set whether cell broadcast emergency alert is enabled by the user or not.
1491      *
1492      * @param subId Subscription id.
1493      * @param isEmergencyAlertEnabled whether cell broadcast emergency alert is enabled by
1494      * the user or not.
1495      *
1496      * @throws IllegalArgumentException if the subscription does not exist.
1497      */
setCellBroadcastEmergencyAlertEnabled(int subId, int isEmergencyAlertEnabled)1498     public void setCellBroadcastEmergencyAlertEnabled(int subId,
1499             int isEmergencyAlertEnabled) {
1500         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_EMERGENCY_ALERT,
1501                 isEmergencyAlertEnabled,
1502                 SubscriptionInfoInternal.Builder::setCellBroadcastEmergencyAlertEnabled);
1503     }
1504 
1505     /**
1506      * Set cell broadcast alert sound duration.
1507      *
1508      * @param subId Subscription id.
1509      * @param alertSoundDuration Alert sound duration in seconds.
1510      *
1511      * @throws IllegalArgumentException if the subscription does not exist.
1512      */
setCellBroadcastAlertSoundDuration(int subId, int alertSoundDuration)1513     public void setCellBroadcastAlertSoundDuration(int subId, int alertSoundDuration) {
1514         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ALERT_SOUND_DURATION,
1515                 alertSoundDuration,
1516                 SubscriptionInfoInternal.Builder::setCellBroadcastAlertSoundDuration);
1517     }
1518 
1519     /**
1520      * Set cell broadcast alert reminder interval.
1521      *
1522      * @param subId Subscription id.
1523      * @param reminderInterval Alert reminder interval in milliseconds.
1524      *
1525      * @throws IllegalArgumentException if the subscription does not exist.
1526      */
setCellBroadcastAlertReminderInterval(int subId, int reminderInterval)1527     public void setCellBroadcastAlertReminderInterval(int subId, int reminderInterval) {
1528         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL,
1529                 reminderInterval,
1530                 SubscriptionInfoInternal.Builder::setCellBroadcastAlertReminderInterval);
1531     }
1532 
1533     /**
1534      * Set whether cell broadcast alert vibration is enabled by the user or not.
1535      *
1536      * @param subId Subscription id.
1537      * @param isAlertVibrationEnabled whether cell broadcast alert vibration is enabled by the user
1538      * or not.
1539      *
1540      * @throws IllegalArgumentException if the subscription does not exist.
1541      */
setCellBroadcastAlertVibrationEnabled(int subId, int isAlertVibrationEnabled)1542     public void setCellBroadcastAlertVibrationEnabled(int subId, int isAlertVibrationEnabled) {
1543         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ALERT_VIBRATE, isAlertVibrationEnabled,
1544                 SubscriptionInfoInternal.Builder::setCellBroadcastAlertVibrationEnabled);
1545     }
1546 
1547     /**
1548      * Set whether cell broadcast alert speech is enabled by the user or not.
1549      *
1550      * @param subId Subscription id.
1551      * @param isAlertSpeechEnabled whether cell broadcast alert speech is enabled by the user or
1552      * not.
1553      *
1554      * @throws IllegalArgumentException if the subscription does not exist.
1555      */
setCellBroadcastAlertSpeechEnabled(int subId, int isAlertSpeechEnabled)1556     public void setCellBroadcastAlertSpeechEnabled(int subId, int isAlertSpeechEnabled) {
1557         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ALERT_SPEECH, isAlertSpeechEnabled,
1558                 SubscriptionInfoInternal.Builder::setCellBroadcastAlertSpeechEnabled);
1559     }
1560 
1561     /**
1562      * Set whether ETWS test alert is enabled by the user or not.
1563      *
1564      * @param subId Subscription id.
1565      * @param isEtwsTestAlertEnabled whether cell broadcast ETWS test alert is enabled by the user
1566      * or not.
1567      *
1568      * @throws IllegalArgumentException if the subscription does not exist.
1569      */
setCellBroadcastEtwsTestAlertEnabled(int subId, int isEtwsTestAlertEnabled)1570     public void setCellBroadcastEtwsTestAlertEnabled(int subId, int isEtwsTestAlertEnabled) {
1571         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ETWS_TEST_ALERT,
1572                 isEtwsTestAlertEnabled,
1573                 SubscriptionInfoInternal.Builder::setCellBroadcastEtwsTestAlertEnabled);
1574     }
1575 
1576     /**
1577      * Set whether area info message is enabled by the user or not.
1578      *
1579      * @param subId Subscription id.
1580      * @param isAreaInfoMessageEnabled whether cell broadcast area info message is enabled by the
1581      * user or not.
1582      *
1583      * @throws IllegalArgumentException if the subscription does not exist.
1584      */
setCellBroadcastAreaInfoMessageEnabled(int subId, int isAreaInfoMessageEnabled)1585     public void setCellBroadcastAreaInfoMessageEnabled(int subId, int isAreaInfoMessageEnabled) {
1586         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_CHANNEL_50_ALERT,
1587                 isAreaInfoMessageEnabled,
1588                 SubscriptionInfoInternal.Builder::setCellBroadcastAreaInfoMessageEnabled);
1589     }
1590 
1591     /**
1592      * Set whether cell broadcast test alert is enabled by the user or not.
1593      *
1594      * @param subId Subscription id.
1595      * @param isTestAlertEnabled whether cell broadcast test alert is enabled by the user or not.
1596      *
1597      * @throws IllegalArgumentException if the subscription does not exist.
1598      */
setCellBroadcastTestAlertEnabled(int subId, int isTestAlertEnabled)1599     public void setCellBroadcastTestAlertEnabled(int subId, int isTestAlertEnabled) {
1600         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_CMAS_TEST_ALERT, isTestAlertEnabled,
1601                 SubscriptionInfoInternal.Builder::setCellBroadcastTestAlertEnabled);
1602     }
1603 
1604     /**
1605      * Set whether cell broadcast opt-out dialog should be shown or not.
1606      *
1607      * @param subId Subscription id.
1608      * @param isOptOutDialogEnabled whether cell broadcast opt-out dialog should be shown or not.
1609      *
1610      * @throws IllegalArgumentException if the subscription does not exist.
1611      */
setCellBroadcastOptOutDialogEnabled(int subId, int isOptOutDialogEnabled)1612     public void setCellBroadcastOptOutDialogEnabled(int subId, int isOptOutDialogEnabled) {
1613         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_OPT_OUT_DIALOG, isOptOutDialogEnabled,
1614                 SubscriptionInfoInternal.Builder::setCellBroadcastOptOutDialogEnabled);
1615     }
1616 
1617     /**
1618      * Set whether enhanced 4G mode is enabled by the user or not.
1619      *
1620      * @param subId Subscription id.
1621      * @param isEnhanced4GModeEnabled whether enhanced 4G mode is enabled by the user or not.
1622      *
1623      * @throws IllegalArgumentException if the subscription does not exist.
1624      */
setEnhanced4GModeEnabled(int subId, int isEnhanced4GModeEnabled)1625     public void setEnhanced4GModeEnabled(int subId, int isEnhanced4GModeEnabled) {
1626         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED,
1627                 isEnhanced4GModeEnabled,
1628                 SubscriptionInfoInternal.Builder::setEnhanced4GModeEnabled);
1629     }
1630 
1631     /**
1632      * Set whether video telephony is enabled by the user or not.
1633      *
1634      * @param subId Subscription id.
1635      * @param isVideoTelephonyEnabled whether video telephony is enabled by the user or not.
1636      *
1637      * @throws IllegalArgumentException if the subscription does not exist.
1638      */
setVideoTelephonyEnabled(int subId, int isVideoTelephonyEnabled)1639     public void setVideoTelephonyEnabled(int subId, int isVideoTelephonyEnabled) {
1640         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_VT_IMS_ENABLED, isVideoTelephonyEnabled,
1641                 SubscriptionInfoInternal.Builder::setVideoTelephonyEnabled);
1642     }
1643 
1644     /**
1645      * Set whether Wi-Fi calling is enabled by the user or not when the device is not roaming.
1646      *
1647      * @param subId Subscription id.
1648      * @param isWifiCallingEnabled whether Wi-Fi calling is enabled by the user or not when the
1649      * device is not roaming.
1650      *
1651      * @throws IllegalArgumentException if the subscription does not exist.
1652      */
setWifiCallingEnabled(int subId, int isWifiCallingEnabled)1653     public void setWifiCallingEnabled(int subId, int isWifiCallingEnabled) {
1654         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ENABLED, isWifiCallingEnabled,
1655                 SubscriptionInfoInternal.Builder::setWifiCallingEnabled);
1656     }
1657 
1658     /**
1659      * Set Wi-Fi calling mode when the device is not roaming.
1660      *
1661      * @param subId Subscription id.
1662      * @param wifiCallingMode Wi-Fi calling mode when the device is not roaming.
1663      *
1664      * @throws IllegalArgumentException if the subscription does not exist.
1665      */
setWifiCallingMode(int subId, @ImsMmTelManager.WiFiCallingMode int wifiCallingMode)1666     public void setWifiCallingMode(int subId,
1667             @ImsMmTelManager.WiFiCallingMode int wifiCallingMode) {
1668         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_MODE, wifiCallingMode,
1669                 SubscriptionInfoInternal.Builder::setWifiCallingMode);
1670     }
1671 
1672     /**
1673      * Set Wi-Fi calling mode when the device is roaming.
1674      *
1675      * @param subId Subscription id.
1676      * @param wifiCallingModeForRoaming Wi-Fi calling mode when the device is roaming.
1677      *
1678      * @throws IllegalArgumentException if the subscription does not exist.
1679      */
setWifiCallingModeForRoaming(int subId, @ImsMmTelManager.WiFiCallingMode int wifiCallingModeForRoaming)1680     public void setWifiCallingModeForRoaming(int subId,
1681             @ImsMmTelManager.WiFiCallingMode int wifiCallingModeForRoaming) {
1682         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ROAMING_MODE,
1683                 wifiCallingModeForRoaming,
1684                 SubscriptionInfoInternal.Builder::setWifiCallingModeForRoaming);
1685     }
1686 
1687     /**
1688      * Set whether Wi-Fi calling is enabled by the user or not when the device is roaming.
1689      *
1690      * @param subId Subscription id.
1691      * @param isWifiCallingEnabledForRoaming whether Wi-Fi calling is enabled by the user or not
1692      * when the device is roaming.
1693      *
1694      * @throws IllegalArgumentException if the subscription does not exist.
1695      */
setWifiCallingEnabledForRoaming(int subId, int isWifiCallingEnabledForRoaming)1696     public void setWifiCallingEnabledForRoaming(int subId, int isWifiCallingEnabledForRoaming) {
1697         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED,
1698                 isWifiCallingEnabledForRoaming,
1699                 SubscriptionInfoInternal.Builder::setWifiCallingEnabledForRoaming);
1700     }
1701 
1702     /**
1703      * Set whether the subscription is opportunistic or not.
1704      *
1705      * @param subId Subscription id.
1706      * @param isOpportunistic if the subscription is opportunistic.
1707      *
1708      * @throws IllegalArgumentException if the subscription does not exist.
1709      */
setOpportunistic(int subId, boolean isOpportunistic)1710     public void setOpportunistic(int subId, boolean isOpportunistic) {
1711         setOpportunistic(subId, isOpportunistic ? 1 : 0);
1712     }
1713 
1714     /**
1715      * Set whether the subscription is opportunistic or not.
1716      *
1717      * @param subId Subscription id.
1718      * @param isOpportunistic if the subscription is opportunistic.
1719      *
1720      * @throws IllegalArgumentException if the subscription does not exist.
1721      */
setOpportunistic(int subId, int isOpportunistic)1722     public void setOpportunistic(int subId, int isOpportunistic) {
1723         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_OPPORTUNISTIC, isOpportunistic,
1724                 SubscriptionInfoInternal.Builder::setOpportunistic);
1725     }
1726 
1727     /**
1728      * Set the group UUID of the subscription group.
1729      *
1730      * @param subId Subscription id.
1731      * @param groupUuid The group UUID.
1732      *
1733      * @throws IllegalArgumentException if the subscription does not exist.
1734      *
1735      * @see SubscriptionInfo#getGroupUuid()
1736      */
setGroupUuid(int subId, @NonNull String groupUuid)1737     public void setGroupUuid(int subId, @NonNull String groupUuid) {
1738         Objects.requireNonNull(groupUuid);
1739         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_GROUP_UUID, groupUuid,
1740                 SubscriptionInfoInternal.Builder::setGroupUuid);
1741     }
1742 
1743     /**
1744      * Set the ISO Country code for the subscription's provider.
1745      *
1746      * @param subId Subscription id.
1747      * @param countryIso The ISO country code for the subscription's provider.
1748      *
1749      * @throws IllegalArgumentException if the subscription does not exist.
1750      */
setCountryIso(int subId, @NonNull String countryIso)1751     public void setCountryIso(int subId, @NonNull String countryIso) {
1752         Objects.requireNonNull(countryIso);
1753         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ISO_COUNTRY_CODE, countryIso,
1754                 SubscriptionInfoInternal.Builder::setCountryIso);
1755     }
1756 
1757     /**
1758      * Set the subscription carrier id.
1759      *
1760      * @param subId Subscription id.
1761      * @param carrierId The carrier id.
1762      *
1763      * @throws IllegalArgumentException if the subscription does not exist.
1764      *
1765      * @see TelephonyManager#getSimCarrierId()
1766      */
setCarrierId(int subId, int carrierId)1767     public void setCarrierId(int subId, int carrierId) {
1768         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CARRIER_ID, carrierId,
1769                 SubscriptionInfoInternal.Builder::setCarrierId);
1770     }
1771 
1772     /**
1773      * Set the profile class populated from the profile metadata if present.
1774      *
1775      * @param subId Subscription id.
1776      * @param profileClass the profile class populated from the profile metadata if present.
1777      *
1778      * @throws IllegalArgumentException if the subscription does not exist.
1779      *
1780      * @see SubscriptionInfo#getProfileClass()
1781      */
setProfileClass(int subId, @ProfileClass int profileClass)1782     public void setProfileClass(int subId, @ProfileClass int profileClass) {
1783         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_PROFILE_CLASS, profileClass,
1784                 SubscriptionInfoInternal.Builder::setProfileClass);
1785     }
1786 
1787     /**
1788      * Set the subscription type.
1789      *
1790      * @param subId Subscription id.
1791      * @param type Subscription type.
1792      *
1793      * @throws IllegalArgumentException if the subscription does not exist.
1794      */
setSubscriptionType(int subId, @SubscriptionType int type)1795     public void setSubscriptionType(int subId, @SubscriptionType int type) {
1796         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_SUBSCRIPTION_TYPE, type,
1797                 SubscriptionInfoInternal.Builder::setType);
1798     }
1799 
1800     /**
1801      * Set the owner package of group the subscription belongs to.
1802      *
1803      * @param subId Subscription id.
1804      * @param groupOwner Owner package of group the subscription belongs to.
1805      *
1806      * @throws IllegalArgumentException if the subscription does not exist.
1807      */
setGroupOwner(int subId, @NonNull String groupOwner)1808     public void setGroupOwner(int subId, @NonNull String groupOwner) {
1809         Objects.requireNonNull(groupOwner);
1810         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_GROUP_OWNER, groupOwner,
1811                 SubscriptionInfoInternal.Builder::setGroupOwner);
1812     }
1813 
1814     /**
1815      * Set the enabled mobile data policies.
1816      *
1817      * @param subId Subscription id.
1818      * @param enabledMobileDataPolicies The enabled mobile data policies.
1819      *
1820      * @throws IllegalArgumentException if the subscription does not exist.
1821      */
setEnabledMobileDataPolicies(int subId, @NonNull String enabledMobileDataPolicies)1822     public void setEnabledMobileDataPolicies(int subId, @NonNull String enabledMobileDataPolicies) {
1823         Objects.requireNonNull(enabledMobileDataPolicies);
1824         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES,
1825                 enabledMobileDataPolicies,
1826                 SubscriptionInfoInternal.Builder::setEnabledMobileDataPolicies);
1827     }
1828 
1829     /**
1830      * Set the IMSI (International Mobile Subscriber Identity) of the subscription.
1831      *
1832      * @param subId Subscription id.
1833      * @param imsi The IMSI.
1834      *
1835      * @throws IllegalArgumentException if the subscription does not exist.
1836      */
setImsi(int subId, @NonNull String imsi)1837     public void setImsi(int subId, @NonNull String imsi) {
1838         Objects.requireNonNull(imsi);
1839         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IMSI, imsi,
1840                 SubscriptionInfoInternal.Builder::setImsi);
1841     }
1842 
1843     /**
1844      * Set whether Uicc applications are configured to enable or not.
1845      *
1846      * @param subId Subscription id.
1847      * @param areUiccApplicationsEnabled if Uicc applications are configured to enable.
1848      *
1849      * @throws IllegalArgumentException if the subscription does not exist.
1850      */
setUiccApplicationsEnabled(int subId, boolean areUiccApplicationsEnabled)1851     public void setUiccApplicationsEnabled(int subId, boolean areUiccApplicationsEnabled) {
1852         setUiccApplicationsEnabled(subId, areUiccApplicationsEnabled ? 1 : 0);
1853     }
1854 
1855     /**
1856      * Set whether Uicc applications are configured to enable or not.
1857      *
1858      * @param subId Subscription id.
1859      * @param areUiccApplicationsEnabled if Uicc applications are configured to enable.
1860      *
1861      * @throws IllegalArgumentException if the subscription does not exist.
1862      */
setUiccApplicationsEnabled(int subId, int areUiccApplicationsEnabled)1863     public void setUiccApplicationsEnabled(int subId, int areUiccApplicationsEnabled) {
1864         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED,
1865                 areUiccApplicationsEnabled,
1866                 SubscriptionInfoInternal.Builder::setUiccApplicationsEnabled);
1867     }
1868 
1869     /**
1870      * Set whether the user has enabled IMS RCS User Capability Exchange (UCE) for this
1871      * subscription.
1872      *
1873      * @param subId Subscription id.
1874      * @param isRcsUceEnabled If the user enabled RCS UCE for this subscription.
1875      *
1876      * @throws IllegalArgumentException if the subscription does not exist.
1877      */
setRcsUceEnabled(int subId, int isRcsUceEnabled)1878     public void setRcsUceEnabled(int subId, int isRcsUceEnabled) {
1879         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, isRcsUceEnabled,
1880                 SubscriptionInfoInternal.Builder::setRcsUceEnabled);
1881     }
1882 
1883     /**
1884      * Set whether the user has enabled cross SIM calling for this subscription.
1885      *
1886      * @param subId Subscription id.
1887      * @param isCrossSimCallingEnabled If the user enabled cross SIM calling for this
1888      * subscription.
1889      *
1890      * @throws IllegalArgumentException if the subscription does not exist.
1891      */
setCrossSimCallingEnabled(int subId, int isCrossSimCallingEnabled)1892     public void setCrossSimCallingEnabled(int subId, int isCrossSimCallingEnabled) {
1893         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED,
1894                 isCrossSimCallingEnabled,
1895                 SubscriptionInfoInternal.Builder::setCrossSimCallingEnabled);
1896     }
1897 
1898     /**
1899      * Set the RCS config for this subscription.
1900      *
1901      * @param subId Subscription id.
1902      * @param rcsConfig The RCS config for this subscription.
1903      *
1904      * @throws IllegalArgumentException if the subscription does not exist.
1905      */
setRcsConfig(int subId, @NonNull byte[] rcsConfig)1906     public void setRcsConfig(int subId, @NonNull byte[] rcsConfig) {
1907         Objects.requireNonNull(rcsConfig);
1908         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_RCS_CONFIG, rcsConfig,
1909                 SubscriptionInfoInternal.Builder::setRcsConfig);
1910     }
1911 
1912     /**
1913      * Set the allowed network types for reasons.
1914      *
1915      * @param subId Subscription id.
1916      * @param allowedNetworkTypesForReasons The allowed network types for reasons in string
1917      * format. The format is "[reason]=[network types bitmask], [reason]=[network types bitmask],
1918      * ...". For example, "user=1239287394, thermal=298791239, carrier=3456812312".
1919      *
1920      * @throws IllegalArgumentException if the subscription does not exist.
1921      */
setAllowedNetworkTypesForReasons(int subId, @NonNull String allowedNetworkTypesForReasons)1922     public void setAllowedNetworkTypesForReasons(int subId,
1923             @NonNull String allowedNetworkTypesForReasons) {
1924         Objects.requireNonNull(allowedNetworkTypesForReasons);
1925         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS,
1926                 allowedNetworkTypesForReasons,
1927                 SubscriptionInfoInternal.Builder::setAllowedNetworkTypesForReasons);
1928     }
1929 
1930     /**
1931      * Set device to device sharing status.
1932      *
1933      * @param subId Subscription id.
1934      * @param deviceToDeviceStatusSharingPreference Device to device sharing status.
1935      *
1936      * @throws IllegalArgumentException if the subscription does not exist.
1937      */
setDeviceToDeviceStatusSharingPreference(int subId, @DeviceToDeviceStatusSharingPreference int deviceToDeviceStatusSharingPreference)1938     public void setDeviceToDeviceStatusSharingPreference(int subId,
1939             @DeviceToDeviceStatusSharingPreference int deviceToDeviceStatusSharingPreference) {
1940         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_D2D_STATUS_SHARING,
1941                 deviceToDeviceStatusSharingPreference,
1942                 SubscriptionInfoInternal.Builder::setDeviceToDeviceStatusSharingPreference);
1943     }
1944 
1945     /**
1946      * Set whether the user has opted-in voice over IMS.
1947      *
1948      * @param subId Subscription id.
1949      * @param isVoImsOptInEnabled Whether the user has opted-in voice over IMS.
1950      *
1951      * @throws IllegalArgumentException if the subscription does not exist.
1952      */
setVoImsOptInEnabled(int subId, int isVoImsOptInEnabled)1953     public void setVoImsOptInEnabled(int subId, int isVoImsOptInEnabled) {
1954         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, isVoImsOptInEnabled,
1955                 SubscriptionInfoInternal.Builder::setVoImsOptInEnabled);
1956     }
1957 
1958     /**
1959      * Set contacts information that allow device to device sharing.
1960      *
1961      * @param subId Subscription id.
1962      * @param deviceToDeviceStatusSharingContacts contacts information that allow device to
1963      * device sharing.
1964      *
1965      * @throws IllegalArgumentException if the subscription does not exist.
1966      */
setDeviceToDeviceStatusSharingContacts(int subId, @NonNull String deviceToDeviceStatusSharingContacts)1967     public void setDeviceToDeviceStatusSharingContacts(int subId,
1968             @NonNull String deviceToDeviceStatusSharingContacts) {
1969         Objects.requireNonNull(deviceToDeviceStatusSharingContacts);
1970         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS,
1971                 deviceToDeviceStatusSharingContacts,
1972                 SubscriptionInfoInternal.Builder::setDeviceToDeviceStatusSharingContacts);
1973     }
1974 
1975     /**
1976      * Set whether the user has enabled NR advanced calling.
1977      *
1978      * @param subId Subscription id.
1979      * @param isNrAdvancedCallingEnabled Whether the user has enabled NR advanced calling.
1980      *
1981      * @throws IllegalArgumentException if the subscription does not exist.
1982      */
setNrAdvancedCallingEnabled(int subId, int isNrAdvancedCallingEnabled)1983     public void setNrAdvancedCallingEnabled(int subId, int isNrAdvancedCallingEnabled) {
1984         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED,
1985                 isNrAdvancedCallingEnabled,
1986                 SubscriptionInfoInternal.Builder::setNrAdvancedCallingEnabled);
1987     }
1988 
1989     /**
1990      * Set the phone number retrieved from carrier.
1991      *
1992      * @param subId Subscription id.
1993      * @param numberFromCarrier The phone number retrieved from carrier.
1994      *
1995      * @throws IllegalArgumentException if the subscription does not exist.
1996      */
setNumberFromCarrier(int subId, @NonNull String numberFromCarrier)1997     public void setNumberFromCarrier(int subId, @NonNull String numberFromCarrier) {
1998         Objects.requireNonNull(numberFromCarrier);
1999         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER,
2000                 numberFromCarrier, SubscriptionInfoInternal.Builder::setNumberFromCarrier);
2001     }
2002 
2003     /**
2004      * Set the phone number retrieved from IMS.
2005      *
2006      * @param subId Subscription id.
2007      * @param numberFromIms The phone number retrieved from IMS.
2008      *
2009      * @throws IllegalArgumentException if the subscription does not exist.
2010      */
setNumberFromIms(int subId, @NonNull String numberFromIms)2011     public void setNumberFromIms(int subId, @NonNull String numberFromIms) {
2012         Objects.requireNonNull(numberFromIms);
2013         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS,
2014                 numberFromIms, SubscriptionInfoInternal.Builder::setNumberFromIms);
2015     }
2016 
2017     /**
2018      * Set the port index of the Uicc card.
2019      *
2020      * @param subId Subscription id.
2021      * @param portIndex The port index of the Uicc card.
2022      *
2023      * @throws IllegalArgumentException if the subscription does not exist.
2024      */
setPortIndex(int subId, int portIndex)2025     public void setPortIndex(int subId, int portIndex) {
2026         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_PORT_INDEX, portIndex,
2027                 SubscriptionInfoInternal.Builder::setPortIndex);
2028     }
2029 
2030     /**
2031      * Set subscription's preferred usage setting.
2032      *
2033      * @param subId Subscription id.
2034      * @param usageSetting Subscription's preferred usage setting.
2035      *
2036      * @throws IllegalArgumentException if the subscription does not exist.
2037      */
setUsageSetting(int subId, @UsageSetting int usageSetting)2038     public void setUsageSetting(int subId, @UsageSetting int usageSetting) {
2039         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_USAGE_SETTING, usageSetting,
2040                 SubscriptionInfoInternal.Builder::setUsageSetting);
2041     }
2042 
2043     /**
2044      * Set last used TP message reference.
2045      *
2046      * @param subId Subscription id.
2047      * @param lastUsedTPMessageReference Last used TP message reference.
2048      *
2049      * @throws IllegalArgumentException if the subscription does not exist.
2050      */
setLastUsedTPMessageReference(int subId, int lastUsedTPMessageReference)2051     public void setLastUsedTPMessageReference(int subId, int lastUsedTPMessageReference) {
2052         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_TP_MESSAGE_REF,
2053                 lastUsedTPMessageReference,
2054                 SubscriptionInfoInternal.Builder::setLastUsedTPMessageReference);
2055     }
2056 
2057     /**
2058      * Set the user id associated with this subscription.
2059      *
2060      * @param subId Subscription id.
2061      * @param userId The user id associated with this subscription.
2062      *
2063      * @throws IllegalArgumentException if the subscription does not exist.
2064      */
setUserId(int subId, @UserIdInt int userId)2065     public void setUserId(int subId, @UserIdInt int userId) {
2066         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_USER_HANDLE, userId,
2067                 SubscriptionInfoInternal.Builder::setUserId);
2068     }
2069 
2070     /**
2071      * Set whether satellite is enabled or not.
2072      *
2073      * @param subId Subscription id.
2074      * @param isSatelliteEnabled if satellite is enabled or not.
2075      *
2076      * @throws IllegalArgumentException if the subscription does not exist.
2077      */
setSatelliteEnabled(int subId, int isSatelliteEnabled)2078     public void setSatelliteEnabled(int subId, int isSatelliteEnabled) {
2079         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_SATELLITE_ENABLED,
2080                 isSatelliteEnabled,
2081                 SubscriptionInfoInternal.Builder::setSatelliteEnabled);
2082     }
2083 
2084     /**
2085      * Set whether satellite attach for carrier is enabled or disabled by user.
2086      *
2087      * @param subId Subscription id.
2088      * @param isSatelliteAttachEnabledForCarrier Whether satellite attach for carrier is enabled or
2089      * disabled.
2090      *
2091      * @throws IllegalArgumentException if the subscription does not exist.
2092      */
setSatelliteAttachEnabledForCarrier(int subId, int isSatelliteAttachEnabledForCarrier)2093     public void setSatelliteAttachEnabledForCarrier(int subId,
2094             int isSatelliteAttachEnabledForCarrier) {
2095         writeDatabaseAndCacheHelper(subId,
2096                 SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
2097                 isSatelliteAttachEnabledForCarrier,
2098                 SubscriptionInfoInternal.Builder::setSatelliteAttachEnabledForCarrier);
2099     }
2100 
2101     /**
2102      * Set whether the subscription is exclusively used for non-terrestrial networks or not.
2103      *
2104      * @param subId Subscription ID.
2105      * @param isNtn {@code 1} if it is a non-terrestrial network subscription.
2106      * {@code 0} otherwise.
2107      *
2108      * @throws IllegalArgumentException if the subscription does not exist.
2109      */
setNtn(int subId, int isNtn)2110     public void setNtn(int subId, int isNtn) {
2111         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_ONLY_NTN, isNtn,
2112                 SubscriptionInfoInternal.Builder::setOnlyNonTerrestrialNetwork);
2113     }
2114 
2115     /**
2116      * Set whether group of the subscription is disabled. This is only useful if it's a grouped
2117      * opportunistic subscription. In this case, if all primary (non-opportunistic)
2118      * subscriptions in the group are deactivated (unplugged pSIM or deactivated eSIM profile),
2119      * we should disable this opportunistic subscription.
2120      *
2121      * @param subId Subscription id.
2122      * @param isGroupDisabled if group of the subscription is disabled.
2123      *
2124      * @throws IllegalArgumentException if the subscription does not exist.
2125      */
setGroupDisabled(int subId, boolean isGroupDisabled)2126     public void setGroupDisabled(int subId, boolean isGroupDisabled) {
2127         // group disabled does not have a corresponding SimInfo column. So we only update the cache.
2128         boolean isChanged = false;
2129         // Grab the write lock so no other threads can read or write the cache.
2130         mReadWriteLock.writeLock().lock();
2131         try {
2132             SubscriptionInfoInternal subInfoCache = mAllSubscriptionInfoInternalCache.get(subId);
2133             if (subInfoCache == null) {
2134                 throw new IllegalArgumentException("setGroupDisabled: Subscription doesn't exist. "
2135                         + "subId=" + subId);
2136             }
2137             isChanged = subInfoCache.isGroupDisabled() != isGroupDisabled;
2138             mAllSubscriptionInfoInternalCache.put(subId,
2139                     new SubscriptionInfoInternal.Builder(subInfoCache)
2140                             .setGroupDisabled(isGroupDisabled).build());
2141         } finally {
2142             mReadWriteLock.writeLock().unlock();
2143         }
2144 
2145         if (isChanged) {
2146             log("setGroupDisabled value changed, firing the callback");
2147             mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId));
2148         }
2149     }
2150 
2151     /**
2152      * Set service capabilities the subscription support.
2153      * @param subId Subscription id.
2154      * @param capabilities Service capabilities bitmasks
2155      */
setServiceCapabilities(int subId, int capabilities)2156     public void setServiceCapabilities(int subId, int capabilities) {
2157         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_SERVICE_CAPABILITIES,
2158                 capabilities, SubscriptionInfoInternal.Builder::setServiceCapabilities);
2159     }
2160 
2161     /**
2162      * Set whether satellite entitlement status is enabled by entitlement query result.
2163      *
2164      * @param subId Subscription id.
2165      * @param isSatelliteEntitlementStatus Whether satellite entitlement status is enabled or
2166      * disabled.
2167      * @throws IllegalArgumentException if the subscription does not exist.
2168      */
setSatelliteEntitlementStatus(int subId, int isSatelliteEntitlementStatus)2169     public void setSatelliteEntitlementStatus(int subId,
2170             int isSatelliteEntitlementStatus) {
2171         writeDatabaseAndCacheHelper(subId,
2172                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_STATUS,
2173                 isSatelliteEntitlementStatus,
2174                 SubscriptionInfoInternal.Builder::setSatelliteEntitlementStatus);
2175     }
2176 
2177     /**
2178      * Set satellite entitlement plmns by entitlement query result.
2179      *
2180      * @param subId Subscription id.
2181      * @param satelliteEntitlementPlmns Satellite entitlement plmns
2182      * @throws IllegalArgumentException if the subscription does not exist.
2183      */
setSatelliteEntitlementPlmns(int subId, @NonNull String satelliteEntitlementPlmns)2184     public void setSatelliteEntitlementPlmns(int subId,
2185             @NonNull String satelliteEntitlementPlmns) {
2186         writeDatabaseAndCacheHelper(subId,
2187                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS,
2188                 satelliteEntitlementPlmns,
2189                 SubscriptionInfoInternal.Builder::setSatelliteEntitlementPlmns);
2190     }
2191 
2192     /**
2193      * Save the satellite entitlement Info in the subscription database.
2194      *
2195      * @param subId                     subId.
2196      * @param allowedPlmnList           Plmn [MCC+MNC] list of codes to determine if satellite
2197      *                                  communication is allowed. Ex : "123123,12310".
2198      * @param barredPlmnList            Plmn [MCC+MNC] list of codes to determine if satellite
2199      *                                  communication is not allowed.  Ex : "123123,12310".
2200      * @param plmnDataPlanMap           data plan per plmn of type
2201      *                                  {@link SatelliteController#SATELLITE_DATA_PLAN_METERED} OR
2202      *                                  {@link SatelliteController#SATELLITE_DATA_PLAN_UNMETERED}.
2203      *                                  Ex : {"302820":0, "31026":1}
2204      * @param plmnServiceTypeMap        list of supported services per plmn of type
2205      *                                  {@link
2206      *                                  android.telephony.NetworkRegistrationInfo.ServiceType}).
2207      *                                  Ex : {"302820":[1,3],"31026":[2,3]}
2208      * @param plmnDataServicePolicyMap  data support mode per plmn map of types
2209      *                                  {@link CarrierConfigManager.SATELLITE_DATA_SUPPORT_MODE}.
2210      *                                  Ex : {"302820":2, "31026":1}
2211      * @param plmnVoiceServicePolicyMap voice support mode per plmn map of types
2212      *                                  {@link CarrierConfigManager.SATELLITE_DATA_SUPPORT_MODE}
2213      *                                  . Ex : {"302820":2, "31026":1}.
2214      * @throws IllegalArgumentException if the subscription does not exist.
2215      */
setSatelliteEntitlementInfo(int subId, @NonNull List<String> allowedPlmnList, @Nullable List<String> barredPlmnList, @Nullable Map<String, Integer> plmnDataPlanMap, @Nullable Map<String, List<Integer>> plmnServiceTypeMap, @Nullable Map<String, Integer> plmnDataServicePolicyMap, @Nullable Map<String, Integer> plmnVoiceServicePolicyMap)2216     public void setSatelliteEntitlementInfo(int subId,
2217             @NonNull List<String> allowedPlmnList,
2218             @Nullable List<String> barredPlmnList,
2219             @Nullable Map<String, Integer> plmnDataPlanMap,
2220             @Nullable Map<String, List<Integer>> plmnServiceTypeMap,
2221             @Nullable Map<String, Integer> plmnDataServicePolicyMap,
2222             @Nullable Map<String, Integer> plmnVoiceServicePolicyMap) {
2223         String satelliteEntitlementPlmns = allowedPlmnList.stream().collect(
2224                 Collectors.joining(","));
2225         setSatelliteEntitlementPlmns(subId, satelliteEntitlementPlmns);
2226 
2227         String satelliteEntitlementBarredPlmns = barredPlmnList.stream().collect(
2228                 Collectors.joining(","));
2229         setSatelliteEntitlementBarredPlmns(subId, satelliteEntitlementBarredPlmns);
2230 
2231 
2232         String plmnDataPlanJson = serializeMapToJsonString(plmnDataPlanMap);
2233         setSatelliteEntitlementDataPlanForPlmns(subId, plmnDataPlanJson);
2234 
2235         String plmnServiceTypeJson = serializeMapListToJsonString(plmnServiceTypeMap);
2236         setSatelliteEntitlementPlmnServiceTypeMap(subId, plmnServiceTypeJson);
2237 
2238         String plmnDataServicePolicyJson = serializeMapToJsonString(plmnDataServicePolicyMap);
2239         setSatelliteEntitlementPlmnDataServicePolicy(subId, plmnDataServicePolicyJson);
2240 
2241         String plmnVoiceServicePolicyJson = serializeMapToJsonString(plmnVoiceServicePolicyMap);
2242         setSatelliteEntitlementPlmnVoiceServicePolicy(subId, plmnVoiceServicePolicyJson);
2243     }
2244 
2245     /**
2246      * Set whether the carrier roaming to satellite is using ESOS for emergency messaging.
2247      *
2248      * @param subId Subscription id.
2249      * @param isSatelliteESOSSupported whether the carrier roaming to satellite is using ESOS for
2250      * emergency messaging.
2251      * @throws IllegalArgumentException if the subscription does not exist.
2252      */
setSatelliteESOSSupported(int subId, int isSatelliteESOSSupported)2253     public void setSatelliteESOSSupported(int subId, int isSatelliteESOSSupported) {
2254         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
2255             return;
2256         }
2257         writeDatabaseAndCacheHelper(subId,
2258                 SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED, isSatelliteESOSSupported,
2259                 SubscriptionInfoInternal.Builder::setSatelliteESOSSupported);
2260     }
2261 
2262     /**
2263      * Set whether the subscription is provisioned for OEM-enabled or carrier roaming NB-IOT
2264      * satellite service.
2265      *
2266      * @param subId Subscription ID.
2267      * @param isSatelliteProvisionedForNonIpDatagram {@code 1} if it is provisioned for OEM-enabled
2268      * or carrier roaming NB-IOT satellite service. {@code 0} otherwise.
2269      *
2270      * @throws IllegalArgumentException if the subscription does not exist.
2271      */
setIsSatelliteProvisionedForNonIpDatagram(int subId, int isSatelliteProvisionedForNonIpDatagram)2272     public void setIsSatelliteProvisionedForNonIpDatagram(int subId,
2273             int isSatelliteProvisionedForNonIpDatagram) {
2274         writeDatabaseAndCacheHelper(subId,
2275                 SimInfo.COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM,
2276                 isSatelliteProvisionedForNonIpDatagram,
2277                 SubscriptionInfoInternal.Builder::setIsSatelliteProvisionedForNonIpDatagram);
2278     }
2279 
2280     /**
2281      * Set satellite entitlement barred plmns list by entitlement query result.
2282      *
2283      * @param subId Subscription id.
2284      * @param satelliteEntitlementBarredPlmns Satellite entitlement barred plmns
2285      * @throws IllegalArgumentException if the subscription does not exist.
2286      */
setSatelliteEntitlementBarredPlmns(int subId, @NonNull String satelliteEntitlementBarredPlmns)2287     public void setSatelliteEntitlementBarredPlmns(int subId,
2288             @NonNull String satelliteEntitlementBarredPlmns) {
2289         writeDatabaseAndCacheHelper(subId,
2290                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS,
2291                 satelliteEntitlementBarredPlmns,
2292                 SubscriptionInfoInternal.Builder::setSatelliteEntitlementBarredPlmnsList);
2293     }
2294 
2295     /**
2296      * Set satellite entitlement data plan for the plmns by entitlement query result.
2297      *
2298      * @param subId Subscription id.
2299      * @param plmnDataPlanJson Satellite entitlement data plan for plmns.
2300      * @throws IllegalArgumentException if the subscription does not exist.
2301      */
setSatelliteEntitlementDataPlanForPlmns(int subId, @NonNull String plmnDataPlanJson)2302     public void setSatelliteEntitlementDataPlanForPlmns(int subId,
2303             @NonNull String plmnDataPlanJson) {
2304         writeDatabaseAndCacheHelper(subId,
2305                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS,
2306                 plmnDataPlanJson,
2307                 SubscriptionInfoInternal.Builder::setSatelliteEntitlementDataPlanForPlmns);
2308     }
2309 
2310     /**
2311      * Set satellite entitlement services for the plmns by entitlement query result.
2312      *
2313      * @param subId                     Subscription id.
2314      * @param plmnServiceTypeJson Satellite entitlement services for plmns.
2315      * @throws IllegalArgumentException if the subscription does not exist.
2316      */
setSatelliteEntitlementPlmnServiceTypeMap(int subId, @NonNull String plmnServiceTypeJson)2317     public void setSatelliteEntitlementPlmnServiceTypeMap(int subId,
2318             @NonNull String plmnServiceTypeJson) {
2319         writeDatabaseAndCacheHelper(subId,
2320                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP,
2321                 plmnServiceTypeJson,
2322                 SubscriptionInfoInternal.Builder::setSatelliteEntitlementPlmnServiceTypes);
2323     }
2324 
2325     /**
2326      * Set satellite entitlement data service policy for plmns by entitlement query result.
2327      *
2328      * @param subId Subscription id.
2329      * @param satellitePlmnsDataServicePolicy Satellite entitlement data service policy for plmns.
2330      * @throws IllegalArgumentException if the subscription does not exist.
2331      */
setSatelliteEntitlementPlmnDataServicePolicy(int subId, @NonNull String satellitePlmnsDataServicePolicy)2332     public void setSatelliteEntitlementPlmnDataServicePolicy(int subId,
2333             @NonNull String satellitePlmnsDataServicePolicy) {
2334         writeDatabaseAndCacheHelper(subId,
2335                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY,
2336                 satellitePlmnsDataServicePolicy,
2337                 SubscriptionInfoInternal.Builder::setSatellitePlmnsDataServicePolicy);
2338     }
2339 
2340     /**
2341      * Set satellite entitlement voice service policy for plmns by entitlement query result.
2342      *
2343      * @param subId Subscription id.
2344      * @param satellitePlmnsVoiceServicePolicy Satellite entitlement voice service policy for plmns.
2345      * @throws IllegalArgumentException if the subscription does not exist.
2346      */
setSatelliteEntitlementPlmnVoiceServicePolicy(int subId, @NonNull String satellitePlmnsVoiceServicePolicy)2347     public void setSatelliteEntitlementPlmnVoiceServicePolicy(int subId,
2348             @NonNull String satellitePlmnsVoiceServicePolicy) {
2349         writeDatabaseAndCacheHelper(subId,
2350                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY,
2351                 satellitePlmnsVoiceServicePolicy,
2352                 SubscriptionInfoInternal.Builder::setSatellitePlmnsVoiceServicePolicy);
2353     }
2354 
2355     /**
2356      * Reload the database from content provider to the cache. This must be a synchronous operation
2357      * to prevent cache/database out-of-sync. Callers should be cautious to call this method because
2358      * it might take longer time to complete.
2359      */
reloadDatabaseSync()2360     public void reloadDatabaseSync() {
2361         logl("reloadDatabaseSync");
2362         // Synchronously load the database into the cache.
2363         loadDatabaseInternal();
2364     }
2365 
2366     /**
2367      * Load the database from content provider to the cache.
2368      */
loadDatabaseInternal()2369     private void loadDatabaseInternal() {
2370         logl("loadDatabaseInternal");
2371         try (Cursor cursor = mContext.getContentResolver().query(
2372                 SimInfo.CONTENT_URI, null, null, null, null)) {
2373             mReadWriteLock.writeLock().lock();
2374             try {
2375                 Map<Integer, SubscriptionInfoInternal> newAllSubscriptionInfoInternalCache =
2376                         new HashMap<>();
2377                 boolean changed = false;
2378                 while (cursor != null && cursor.moveToNext()) {
2379                     SubscriptionInfoInternal subInfo = createSubscriptionInfoFromCursor(cursor);
2380                     newAllSubscriptionInfoInternalCache.put(subInfo.getSubscriptionId(), subInfo);
2381                     if (!Objects.equals(mAllSubscriptionInfoInternalCache
2382                             .get(subInfo.getSubscriptionId()), subInfo)) {
2383                         mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(
2384                                 subInfo.getSubscriptionId()));
2385                         changed = true;
2386                     }
2387                 }
2388 
2389                 if (changed) {
2390                     mAllSubscriptionInfoInternalCache.clear();
2391                     mAllSubscriptionInfoInternalCache.putAll(newAllSubscriptionInfoInternalCache);
2392 
2393                     logl("Loaded " + mAllSubscriptionInfoInternalCache.size()
2394                             + " records from the subscription database.");
2395                     mAllSubscriptionInfoInternalCache.forEach(
2396                             (subId, subInfo) -> log("  " + subInfo.toString()));
2397                 }
2398             } finally {
2399                 mReadWriteLock.writeLock().unlock();
2400             }
2401         }
2402     }
2403 
2404     /**
2405      * Initialize the database cache. Load the entire database into the cache.
2406      */
initializeDatabase()2407     private void initializeDatabase() {
2408         if (mAsyncMode) {
2409             // Load the database asynchronously.
2410             post(() -> {
2411                 synchronized (this) {
2412                     loadDatabaseInternal();
2413                     mDatabaseInitialized = true;
2414                     mCallback.invokeFromExecutor(mCallback::onInitialized);
2415                 }
2416             });
2417         } else {
2418             // Load the database synchronously.
2419             synchronized (this) {
2420                 loadDatabaseInternal();
2421                 mDatabaseInitialized = true;
2422                 mCallback.invokeFromExecutor(mCallback::onInitialized);
2423             }
2424         }
2425     }
2426 
2427     /**
2428      * Build the {@link SubscriptionInfoInternal} from database.
2429      *
2430      * @param cursor  The cursor of the database.
2431      *
2432      * @return The subscription info from a single database record.
2433      */
2434     @NonNull
createSubscriptionInfoFromCursor(@onNull Cursor cursor)2435     private SubscriptionInfoInternal createSubscriptionInfoFromCursor(@NonNull Cursor cursor) {
2436         SubscriptionInfoInternal.Builder builder = new SubscriptionInfoInternal.Builder();
2437         int id = cursor.getInt(cursor.getColumnIndexOrThrow(
2438                 SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID));
2439         builder.setId(id)
2440                 .setIccId(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2441                         SimInfo.COLUMN_ICC_ID))))
2442                 .setSimSlotIndex(cursor.getInt(cursor.getColumnIndexOrThrow(
2443                         SimInfo.COLUMN_SIM_SLOT_INDEX)))
2444                 .setDisplayName(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2445                         SimInfo.COLUMN_DISPLAY_NAME))))
2446                 .setCarrierName(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2447                         SimInfo.COLUMN_CARRIER_NAME))))
2448                 .setDisplayNameSource(cursor.getInt(cursor.getColumnIndexOrThrow(
2449                         SimInfo.COLUMN_NAME_SOURCE)))
2450                 .setIconTint(cursor.getInt(cursor.getColumnIndexOrThrow(
2451                         SimInfo.COLUMN_COLOR)))
2452                 .setNumber(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2453                         SimInfo.COLUMN_NUMBER))))
2454                 .setDataRoaming(cursor.getInt(cursor.getColumnIndexOrThrow(
2455                         SimInfo.COLUMN_DATA_ROAMING)))
2456                 .setMcc(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2457                         SimInfo.COLUMN_MCC_STRING))))
2458                 .setMnc(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2459                         SimInfo.COLUMN_MNC_STRING))))
2460                 .setEhplmns(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2461                         SimInfo.COLUMN_EHPLMNS))))
2462                 .setHplmns(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2463                         SimInfo.COLUMN_HPLMNS))))
2464                 .setEmbedded(cursor.getInt(cursor.getColumnIndexOrThrow(
2465                         SimInfo.COLUMN_IS_EMBEDDED)));
2466 
2467         String cardString = TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2468                 SimInfo.COLUMN_CARD_ID)));
2469         builder.setCardString(cardString);
2470         // publicCardId is the publicly exposed int card ID
2471         int publicCardId = mUiccController.convertToPublicCardId(cardString);
2472 
2473         byte[] rules = cursor.getBlob(cursor.getColumnIndexOrThrow(SimInfo.COLUMN_ACCESS_RULES));
2474         if (rules != null) {
2475             builder.setNativeAccessRules(rules);
2476         }
2477 
2478         rules = cursor.getBlob(cursor.getColumnIndexOrThrow(
2479                 SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS));
2480         if (rules != null) {
2481             builder.setCarrierConfigAccessRules(rules);
2482         }
2483 
2484         byte[] config = cursor.getBlob(cursor.getColumnIndexOrThrow(SimInfo.COLUMN_RCS_CONFIG));
2485         if (config != null) {
2486             builder.setRcsConfig(config);
2487         }
2488 
2489         builder.setCardId(publicCardId)
2490                 .setRemovableEmbedded(cursor.getInt(cursor.getColumnIndexOrThrow(
2491                         SimInfo.COLUMN_IS_REMOVABLE)))
2492                 .setCellBroadcastExtremeThreatAlertEnabled(cursor.getInt(cursor
2493                         .getColumnIndexOrThrow(SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT)))
2494                 .setCellBroadcastSevereThreatAlertEnabled(cursor.getInt(cursor
2495                         .getColumnIndexOrThrow(SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT)))
2496                 .setCellBroadcastAmberAlertEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2497                         SimInfo.COLUMN_CB_AMBER_ALERT)))
2498                 .setCellBroadcastEmergencyAlertEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2499                         SimInfo.COLUMN_CB_EMERGENCY_ALERT)))
2500                 .setCellBroadcastAlertSoundDuration(cursor.getInt(cursor.getColumnIndexOrThrow(
2501                         SimInfo.COLUMN_CB_ALERT_SOUND_DURATION)))
2502                 .setCellBroadcastAlertReminderInterval(cursor.getInt(cursor.getColumnIndexOrThrow(
2503                         SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL)))
2504                 .setCellBroadcastAlertVibrationEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2505                         SimInfo.COLUMN_CB_ALERT_VIBRATE)))
2506                 .setCellBroadcastAlertSpeechEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2507                         SimInfo.COLUMN_CB_ALERT_SPEECH)))
2508                 .setCellBroadcastEtwsTestAlertEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2509                         SimInfo.COLUMN_CB_ETWS_TEST_ALERT)))
2510                 .setCellBroadcastAreaInfoMessageEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2511                         SimInfo.COLUMN_CB_CHANNEL_50_ALERT)))
2512                 .setCellBroadcastTestAlertEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2513                         SimInfo.COLUMN_CB_CMAS_TEST_ALERT)))
2514                 .setCellBroadcastOptOutDialogEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2515                         SimInfo.COLUMN_CB_OPT_OUT_DIALOG)))
2516                 .setEnhanced4GModeEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2517                         SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED)))
2518                 .setVideoTelephonyEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2519                         SimInfo.COLUMN_VT_IMS_ENABLED)))
2520                 .setWifiCallingEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2521                         SimInfo.COLUMN_WFC_IMS_ENABLED)))
2522                 .setWifiCallingMode(cursor.getInt(cursor.getColumnIndexOrThrow(
2523                         SimInfo.COLUMN_WFC_IMS_MODE)))
2524                 .setWifiCallingModeForRoaming(cursor.getInt(cursor.getColumnIndexOrThrow(
2525                         SimInfo.COLUMN_WFC_IMS_ROAMING_MODE)))
2526                 .setWifiCallingEnabledForRoaming(cursor.getInt(cursor.getColumnIndexOrThrow(
2527                         SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED)))
2528                 .setOpportunistic(cursor.getInt(cursor.getColumnIndexOrThrow(
2529                         SimInfo.COLUMN_IS_OPPORTUNISTIC)))
2530                 .setGroupUuid(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2531                         SimInfo.COLUMN_GROUP_UUID))))
2532                 .setCountryIso(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2533                         SimInfo.COLUMN_ISO_COUNTRY_CODE))))
2534                 .setCarrierId(cursor.getInt(cursor.getColumnIndexOrThrow(
2535                         SimInfo.COLUMN_CARRIER_ID)))
2536                 .setProfileClass(cursor.getInt(cursor.getColumnIndexOrThrow(
2537                         SimInfo.COLUMN_PROFILE_CLASS)))
2538                 .setType(cursor.getInt(cursor.getColumnIndexOrThrow(
2539                         SimInfo.COLUMN_SUBSCRIPTION_TYPE)))
2540                 .setGroupOwner(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2541                         SimInfo.COLUMN_GROUP_OWNER))))
2542                 .setEnabledMobileDataPolicies(TextUtils.emptyIfNull(
2543                         cursor.getString(cursor.getColumnIndexOrThrow(
2544                                 SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES))))
2545                 .setImsi(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow(
2546                         SimInfo.COLUMN_IMSI))))
2547                 .setUiccApplicationsEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2548                         SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED)))
2549                 .setRcsUceEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2550                         SimInfo.COLUMN_IMS_RCS_UCE_ENABLED)))
2551                 .setCrossSimCallingEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2552                         SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED)))
2553                 .setAllowedNetworkTypesForReasons(TextUtils.emptyIfNull(
2554                         cursor.getString(cursor.getColumnIndexOrThrow(
2555                                 SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS))))
2556                 .setDeviceToDeviceStatusSharingPreference(cursor.getInt(
2557                         cursor.getColumnIndexOrThrow(
2558                                 SimInfo.COLUMN_D2D_STATUS_SHARING)))
2559                 .setVoImsOptInEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2560                         SimInfo.COLUMN_VOIMS_OPT_IN_STATUS)))
2561                 .setDeviceToDeviceStatusSharingContacts(TextUtils.emptyIfNull(cursor.getString(
2562                         cursor.getColumnIndexOrThrow(
2563                                 SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS))))
2564                 .setNrAdvancedCallingEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2565                         SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED)))
2566                 .setNumberFromCarrier(TextUtils.emptyIfNull(cursor.getString(
2567                         cursor.getColumnIndexOrThrow(
2568                                 SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER))))
2569                 .setNumberFromIms(TextUtils.emptyIfNull(cursor.getString(
2570                         cursor.getColumnIndexOrThrow(
2571                                 SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS))))
2572                 .setPortIndex(cursor.getInt(cursor.getColumnIndexOrThrow(
2573                         SimInfo.COLUMN_PORT_INDEX)))
2574                 .setUsageSetting(cursor.getInt(cursor.getColumnIndexOrThrow(
2575                         SimInfo.COLUMN_USAGE_SETTING)))
2576                 .setLastUsedTPMessageReference(cursor.getInt(cursor.getColumnIndexOrThrow(
2577                         SimInfo.COLUMN_TP_MESSAGE_REF)))
2578                 .setUserId(cursor.getInt(cursor.getColumnIndexOrThrow(
2579                         SimInfo.COLUMN_USER_HANDLE)))
2580                 .setSatelliteEnabled(cursor.getInt(cursor.getColumnIndexOrThrow(
2581                         SimInfo.COLUMN_SATELLITE_ENABLED)))
2582                 .setSatelliteAttachEnabledForCarrier(cursor.getInt(
2583                         cursor.getColumnIndexOrThrow(
2584                                 SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER)))
2585                 .setServiceCapabilities(cursor.getInt(
2586                         cursor.getColumnIndexOrThrow(
2587                                 SimInfo.COLUMN_SERVICE_CAPABILITIES)))
2588                 .setSatelliteEntitlementStatus(cursor.getInt(
2589                         cursor.getColumnIndexOrThrow(
2590                                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_STATUS)))
2591                 .setSatelliteEntitlementPlmns(cursor.getString(
2592                         cursor.getColumnIndexOrThrow(
2593                                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_PLMNS)))
2594                 .setIsSatelliteProvisionedForNonIpDatagram(cursor.getInt(
2595                         cursor.getColumnIndexOrThrow(
2596                                 SimInfo.COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM)))
2597                 .setSatelliteEntitlementBarredPlmnsList(cursor.getString(
2598                         cursor.getColumnIndexOrThrow(
2599                                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS)))
2600                 .setSatelliteEntitlementDataPlanForPlmns(cursor.getString(
2601                         cursor.getColumnIndexOrThrow(
2602                                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS)))
2603                 .setSatelliteEntitlementPlmnServiceTypes(cursor.getString(
2604                         cursor.getColumnIndexOrThrow(
2605                                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP)))
2606                 .setSatellitePlmnsDataServicePolicy(cursor.getString(
2607                         cursor.getColumnIndexOrThrow(
2608                                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY)))
2609                 .setSatellitePlmnsVoiceServicePolicy(cursor.getString(
2610                         cursor.getColumnIndexOrThrow(
2611                                 SimInfo.COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY)));
2612         builder.setOnlyNonTerrestrialNetwork(cursor.getInt(cursor.getColumnIndexOrThrow(
2613                 SimInfo.COLUMN_IS_ONLY_NTN)));
2614         if (mFeatureFlags.supportPsimToEsimConversion()) {
2615             builder.setTransferStatus(cursor.getInt(cursor.getColumnIndexOrThrow(
2616                     SimInfo.COLUMN_TRANSFER_STATUS)));
2617         }
2618         if (mFeatureFlags.carrierRoamingNbIotNtn()) {
2619             builder.setSatelliteESOSSupported(cursor.getInt(
2620                     cursor.getColumnIndexOrThrow(SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED)));
2621         }
2622         return builder.build();
2623     }
2624 
2625     /**
2626      * Sync the group sharing fields from reference subscription to the rest of the subscriptions in
2627      * the same group. For example, if user enables wifi calling, the same setting should be applied
2628      * to all subscriptions in the same group.
2629      *
2630      * @param subId The subscription id of reference subscription.
2631      *
2632      * @throws IllegalArgumentException if the subscription does not exist.
2633      */
syncToGroup(int subId)2634     public void syncToGroup(int subId) {
2635         if (!mAllSubscriptionInfoInternalCache.containsKey(subId)) {
2636             throw new IllegalArgumentException("Invalid subId " + subId);
2637         }
2638 
2639         for (String column : GROUP_SHARING_COLUMNS) {
2640             // Get the value from the reference subscription, and set to itself again.
2641             // writeDatabaseAndCacheHelper() will automatically sync to the rest of the group.
2642             setSubscriptionProperty(subId, column, getSubscriptionProperty(subId, column));
2643         }
2644     }
2645 
2646     /**
2647      * Get the subscription info by subscription id.
2648      *
2649      * @param subId The subscription id.
2650      *
2651      * @return The subscription info. {@code null} if not found.
2652      */
2653     @Nullable
getSubscriptionInfoInternal(int subId)2654     public SubscriptionInfoInternal getSubscriptionInfoInternal(int subId) {
2655         mReadWriteLock.readLock().lock();
2656         try {
2657             return mAllSubscriptionInfoInternalCache.get(subId);
2658         } finally {
2659             mReadWriteLock.readLock().unlock();
2660         }
2661     }
2662 
2663     /**
2664      * @return All subscription infos in the database.
2665      */
2666     @NonNull
getAllSubscriptions()2667     public List<SubscriptionInfoInternal> getAllSubscriptions() {
2668         mReadWriteLock.readLock().lock();
2669         try {
2670             return new ArrayList<>(mAllSubscriptionInfoInternalCache.values());
2671         } finally {
2672             mReadWriteLock.readLock().unlock();
2673         }
2674     }
2675 
2676     /**
2677      * Get subscription info by ICCID.
2678      *
2679      * @param iccId The ICCID of the SIM card.
2680      * @return The subscription info if found. {@code null} if not found.
2681      */
2682     @Nullable
getSubscriptionInfoInternalByIccId(@onNull String iccId)2683     public SubscriptionInfoInternal getSubscriptionInfoInternalByIccId(@NonNull String iccId) {
2684         mReadWriteLock.readLock().lock();
2685         try {
2686             return mAllSubscriptionInfoInternalCache.values().stream()
2687                     .filter(subInfo -> subInfo.getIccId().equals(iccId))
2688                     .findFirst()
2689                     .orElse(null);
2690         } finally {
2691             mReadWriteLock.readLock().unlock();
2692         }
2693     }
2694 
2695     /**
2696      * Set the transfer status of the subscriptionInfo that corresponds to subId.
2697      *
2698      * @param subId Subscription ID.
2699      * @param status The transfer status to change.
2700      *
2701      * @throws IllegalArgumentException if the subscription does not exist.
2702      */
setTransferStatus(int subId, int status)2703     public void setTransferStatus(int subId, int status) {
2704         if (!mFeatureFlags.supportPsimToEsimConversion()) {
2705             log("SubscriptionDatabaseManager:supportPsimToEsimConversion is false");
2706             return;
2707         }
2708 
2709         writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_TRANSFER_STATUS,
2710                 status,
2711                 SubscriptionInfoInternal.Builder::setTransferStatus);
2712     }
2713 
2714     /**
2715      * Serialize the given Map<String, Integer> to Json model string.
2716      *
2717      * @param mapInfo of type Map
2718      * @return Json in string format.
2719      */
serializeMapToJsonString(Map<String, Integer> mapInfo)2720     public String serializeMapToJsonString(Map<String, Integer> mapInfo) {
2721         JSONObject json = new JSONObject();
2722         if (mapInfo == null || mapInfo.isEmpty()) {
2723             return json.toString();
2724         }
2725         try {
2726             for (Map.Entry<String, Integer> entry : mapInfo.entrySet()) {
2727                 json.put(entry.getKey(), entry.getValue());
2728             }
2729         } catch (JSONException e) {
2730             loge("serializeMapToCV JSON error: " + e.getMessage());
2731         }
2732         return json.toString();
2733     }
2734 
2735     /**
2736      * Serialize the given Map<String, List<Integer>> to Json model string.
2737      *
2738      * @param mapList of type Map
2739      * @return Json in string format.
2740      */
serializeMapListToJsonString(Map<String, List<Integer>> mapList)2741     public String serializeMapListToJsonString(Map<String, List<Integer>> mapList) {
2742         JSONObject json = new JSONObject();
2743         if (mapList == null || mapList.isEmpty()) {
2744             return json.toString();
2745         }
2746         try {
2747             for (Map.Entry<String, List<Integer>> entry : mapList.entrySet()) {
2748                 JSONArray jsonArray = new JSONArray();
2749                 for (int value : entry.getValue()) {
2750                     jsonArray.put(value);
2751                 }
2752                 json.put(entry.getKey(), jsonArray);
2753             }
2754         } catch (JSONException e) {
2755             loge("serializeMapListToCV JSON error: " + e.getMessage());
2756         }
2757         return json.toString();
2758     }
2759 
2760     /**
2761      * Log debug messages.
2762      *
2763      * @param s debug messages
2764      */
log(@onNull String s)2765     private void log(@NonNull String s) {
2766         Rlog.d(LOG_TAG, s);
2767     }
2768 
2769     /**
2770      * Log error messages.
2771      *
2772      * @param s error messages
2773      */
loge(@onNull String s)2774     private void loge(@NonNull String s) {
2775         Rlog.e(LOG_TAG, s);
2776     }
2777 
2778     /**
2779      * Log verbose messages.
2780      *
2781      * @param s debug messages.
2782      */
logv(@onNull String s)2783     private void logv(@NonNull String s) {
2784         if (VDBG) Rlog.v(LOG_TAG, s);
2785     }
2786 
2787     /**
2788      * Log error messages and also log into the local log.
2789      *
2790      * @param s debug messages
2791      */
logel(@onNull String s)2792     private void logel(@NonNull String s) {
2793         loge(s);
2794         mLocalLog.log(s);
2795     }
2796 
2797     /**
2798      * Log debug messages and also log into the local log.
2799      *
2800      * @param s debug messages
2801      */
logl(@onNull String s)2802     private void logl(@NonNull String s) {
2803         log(s);
2804         mLocalLog.log(s);
2805     }
2806 
2807     /**
2808      * Dump the state of {@link SubscriptionDatabaseManager}.
2809      *
2810      * @param fd File descriptor
2811      * @param printWriter Print writer
2812      * @param args Arguments
2813      */
dump(@onNull FileDescriptor fd, @NonNull PrintWriter printWriter, @NonNull String[] args)2814     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter printWriter,
2815             @NonNull String[] args) {
2816         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
2817         pw.println(SubscriptionDatabaseManager.class.getSimpleName() + ":");
2818         pw.increaseIndent();
2819         pw.println("All subscriptions:");
2820         pw.increaseIndent();
2821         mReadWriteLock.readLock().lock();
2822         try {
2823             mAllSubscriptionInfoInternalCache.forEach((subId, subInfo) -> pw.println(subInfo));
2824         } finally {
2825             mReadWriteLock.readLock().unlock();
2826         }
2827         pw.decreaseIndent();
2828         pw.println();
2829         pw.println("mAsyncMode=" + mAsyncMode);
2830         synchronized (this) {
2831             pw.println("mDatabaseInitialized=" + mDatabaseInitialized);
2832         }
2833         pw.println("mReadWriteLock=" + mReadWriteLock);
2834         pw.println();
2835         pw.println("Local log:");
2836         pw.increaseIndent();
2837         mLocalLog.dump(fd, printWriter, args);
2838         pw.decreaseIndent();
2839         pw.decreaseIndent();
2840     }
2841 }
2842