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