blob: 6a6b155c111f2994c52c2c68db93182a58559b88 [file] [log] [blame]
joonhunshin2c3e4232021-11-28 07:32:01 +00001/*
2 * Copyright (C) 2021 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
17package com.android.phone;
18
Hakjun Choi4c6c10e2022-03-15 05:08:02 +000019import static android.telephony.ims.ImsRcsManager.CAPABILITY_TYPE_OPTIONS_UCE;
20import static android.telephony.ims.ImsRcsManager.CAPABILITY_TYPE_PRESENCE_UCE;
joonhunshin2c3e4232021-11-28 07:32:01 +000021import static android.telephony.ims.ProvisioningManager.KEY_EAB_PROVISIONING_STATUS;
22import static android.telephony.ims.ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE;
23import static android.telephony.ims.ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS;
24import static android.telephony.ims.ProvisioningManager.KEY_VT_PROVISIONING_STATUS;
25import static android.telephony.ims.ProvisioningManager.PROVISIONING_VALUE_DISABLED;
26import static android.telephony.ims.ProvisioningManager.PROVISIONING_VALUE_ENABLED;
27import static android.telephony.ims.feature.ImsFeature.FEATURE_MMTEL;
28import static android.telephony.ims.feature.ImsFeature.FEATURE_RCS;
29import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER;
30import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS;
31import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT;
32import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO;
33import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE;
joonhunshin2c3e4232021-11-28 07:32:01 +000034import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM;
35import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
36import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
37import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_MAX;
38import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE;
39import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NR;
40
41import android.annotation.Nullable;
42import android.content.Context;
joonhunshin39710022022-01-14 11:53:58 +000043import android.os.AsyncResult;
joonhunshin1724dd62022-08-30 07:41:20 +000044import android.os.Binder;
joonhunshin2c3e4232021-11-28 07:32:01 +000045import android.os.Handler;
46import android.os.HandlerThread;
47import android.os.Looper;
48import android.os.Message;
49import android.os.PersistableBundle;
50import android.os.RemoteCallbackList;
51import android.os.RemoteException;
52import android.telephony.CarrierConfigManager;
joonhunshinf9411cb2022-01-17 07:37:15 +000053import android.telephony.CarrierConfigManager.Ims;
joonhunshin2c3e4232021-11-28 07:32:01 +000054import android.telephony.SubscriptionManager;
55import android.telephony.TelephonyRegistryManager;
56import android.telephony.ims.ProvisioningManager;
57import android.telephony.ims.aidl.IFeatureProvisioningCallback;
58import android.telephony.ims.aidl.IImsConfig;
joonhunshin1724dd62022-08-30 07:41:20 +000059import android.telephony.ims.aidl.IImsConfigCallback;
joonhunshin2c3e4232021-11-28 07:32:01 +000060import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities;
61import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
62import android.telephony.ims.stub.ImsConfigImplBase;
63import android.telephony.ims.stub.ImsRegistrationImplBase;
64import android.util.SparseArray;
65
66import com.android.ims.FeatureConnector;
67import com.android.ims.ImsConfig;
68import com.android.ims.ImsException;
69import com.android.ims.ImsManager;
70import com.android.ims.RcsFeatureManager;
71import com.android.internal.annotations.VisibleForTesting;
joonhunshin39710022022-01-14 11:53:58 +000072import com.android.internal.telephony.PhoneConfigurationManager;
joonhunshin2c3e4232021-11-28 07:32:01 +000073import com.android.internal.telephony.util.HandlerExecutor;
74import com.android.telephony.Rlog;
75
76import java.util.Arrays;
joonhunshinf9411cb2022-01-17 07:37:15 +000077import java.util.Map;
joonhunshin2c3e4232021-11-28 07:32:01 +000078import java.util.concurrent.Executor;
79
80/**
81 * Provides APIs for MMTEL and RCS provisioning status. This class handles provisioning status and
82 * notifies the status changing for each capability
83 * {{@link MmTelCapabilities.MmTelCapability} for MMTel services}
84 * {{@link RcsImsCapabilities.RcsImsCapabilityFlag} for RCS services}
85 */
86public class ImsProvisioningController {
87 private static final String TAG = "ImsProvisioningController";
88 private static final int INVALID_VALUE = -1;
89
90 private static final int EVENT_SUB_CHANGED = 1;
91 private static final int EVENT_PROVISIONING_CAPABILITY_CHANGED = 2;
joonhunshin39710022022-01-14 11:53:58 +000092 @VisibleForTesting
93 protected static final int EVENT_MULTI_SIM_CONFIGURATION_CHANGE = 3;
joonhunshin1724dd62022-08-30 07:41:20 +000094 private static final int EVENT_PROVISIONING_VALUE_CHANGED = 4;
joonhunshin2c3e4232021-11-28 07:32:01 +000095
96 // Provisioning Keys that are handled via AOSP cache and not sent to the ImsService
97 private static final int[] LOCAL_IMS_CONFIG_KEYS = {
98 KEY_VOLTE_PROVISIONING_STATUS,
99 KEY_VT_PROVISIONING_STATUS,
100 KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE,
101 KEY_EAB_PROVISIONING_STATUS
102 };
103 private static final int[] LOCAL_RADIO_TECHS = {
104 REGISTRATION_TECH_LTE,
105 REGISTRATION_TECH_IWLAN,
106 REGISTRATION_TECH_CROSS_SIM,
107 REGISTRATION_TECH_NR
108 };
109
110 private static final int MMTEL_CAPABILITY_MIN = MmTelCapabilities.CAPABILITY_TYPE_NONE;
111 private static final int MMTEL_CAPABILITY_MAX = MmTelCapabilities.CAPABILITY_TYPE_MAX;
112
113 private static final int RCS_CAPABILITY_MIN = RcsImsCapabilities.CAPABILITY_TYPE_NONE;
114 private static final int RCS_CAPABILITY_MAX = RcsImsCapabilities.CAPABILITY_TYPE_MAX;
115
116 private static final int[] LOCAL_MMTEL_CAPABILITY = {
117 CAPABILITY_TYPE_VOICE,
118 CAPABILITY_TYPE_VIDEO,
119 CAPABILITY_TYPE_UT,
120 CAPABILITY_TYPE_SMS,
121 CAPABILITY_TYPE_CALL_COMPOSER
122 };
123
124 /**
joonhunshinf9411cb2022-01-17 07:37:15 +0000125 * map the MmTelCapabilities.MmTelCapability and
126 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_VOICE_INT
127 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_VIDEO_INT
128 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_UT_INT
129 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_SMS_INT
joonhunshin6cd38ac2022-02-03 06:37:55 +0000130 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT
joonhunshinf9411cb2022-01-17 07:37:15 +0000131 */
132 private static final Map<Integer, String> KEYS_MMTEL_CAPABILITY = Map.of(
133 CAPABILITY_TYPE_VOICE, Ims.KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY,
134 CAPABILITY_TYPE_VIDEO, Ims.KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY,
135 CAPABILITY_TYPE_UT, Ims.KEY_CAPABILITY_TYPE_UT_INT_ARRAY,
136 CAPABILITY_TYPE_SMS, Ims.KEY_CAPABILITY_TYPE_SMS_INT_ARRAY,
joonhunshin6cd38ac2022-02-03 06:37:55 +0000137 CAPABILITY_TYPE_CALL_COMPOSER, Ims.KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY
joonhunshinf9411cb2022-01-17 07:37:15 +0000138 );
139
140 /**
141 * map the RcsImsCapabilities.RcsImsCapabilityFlag and
142 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_OPTIONS_UCE
143 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_PRESENCE_UCE
144 */
145 private static final Map<Integer, String> KEYS_RCS_CAPABILITY = Map.of(
146 CAPABILITY_TYPE_OPTIONS_UCE, Ims.KEY_CAPABILITY_TYPE_OPTIONS_UCE_INT_ARRAY,
147 CAPABILITY_TYPE_PRESENCE_UCE, Ims.KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY
148 );
149
150 /**
joonhunshin2c3e4232021-11-28 07:32:01 +0000151 * Create a FeatureConnector for this class to use to connect to an ImsManager.
152 */
153 @VisibleForTesting
154 public interface MmTelFeatureConnector {
155 /**
156 * Create a FeatureConnector for this class to use to connect to an ImsManager.
157 * @param listener will receive ImsManager instance.
158 * @param executor that the Listener callbacks will be called on.
159 * @return A FeatureConnector
160 */
161 FeatureConnector<ImsManager> create(Context context, int slotId,
162 String logPrefix, FeatureConnector.Listener<ImsManager> listener,
163 Executor executor);
164 }
165
166 /**
167 * Create a FeatureConnector for this class to use to connect to an RcsFeatureManager.
168 */
169 @VisibleForTesting
170 public interface RcsFeatureConnector {
171 /**
172 * Create a FeatureConnector for this class to use to connect to an RcsFeatureManager.
173 * @param listener will receive RcsFeatureManager instance.
174 * @param executor that the Listener callbacks will be called on.
175 * @return A FeatureConnector
176 */
177 FeatureConnector<RcsFeatureManager> create(Context context, int slotId,
178 FeatureConnector.Listener<RcsFeatureManager> listener,
179 Executor executor, String logPrefix);
180 }
181
182 private static ImsProvisioningController sInstance;
183
184 private final PhoneGlobals mApp;
185 private final Handler mHandler;
186 private final CarrierConfigManager mCarrierConfigManager;
187 private final SubscriptionManager mSubscriptionManager;
188 private final TelephonyRegistryManager mTelephonyRegistryManager;
189 private final MmTelFeatureConnector mMmTelFeatureConnector;
190 private final RcsFeatureConnector mRcsFeatureConnector;
191
192 // maps a slotId to a list of MmTelFeatureListeners
193 private final SparseArray<MmTelFeatureListener> mMmTelFeatureListenersSlotMap =
194 new SparseArray<>();
195 // maps a slotId to a list of RcsFeatureListeners
196 private final SparseArray<RcsFeatureListener> mRcsFeatureListenersSlotMap =
197 new SparseArray<>();
198 // map a slotId to a list of ProvisioningCallbackManager
199 private final SparseArray<ProvisioningCallbackManager> mProvisioningCallbackManagersSlotMap =
200 new SparseArray<>();
201 private final ImsProvisioningLoader mImsProvisioningLoader;
202
203 private int mNumSlot;
204
205 /**
206 * This class contains the provisioning status to notify changes.
207 * {{@link MmTelCapabilities.MmTelCapability} for MMTel services}
Hakjun Choi4c6c10e2022-03-15 05:08:02 +0000208 * {{@link android.telephony.ims.ImsRcsManager.RcsImsCapabilityFlag} for RCS services}
joonhunshin2c3e4232021-11-28 07:32:01 +0000209 * {{@link ImsRegistrationImplBase.ImsRegistrationTech} for Registration tech}
210 */
211 private static final class FeatureProvisioningData {
212 public final int mCapability;
213 public final int mTech;
214 public final boolean mProvisioned;
215 public final boolean mIsMmTel;
216
217 FeatureProvisioningData(int capability, int tech, boolean provisioned, boolean isMmTel) {
218 mCapability = capability;
219 mTech = tech;
220 mProvisioned = provisioned;
221 mIsMmTel = isMmTel;
222 }
223 }
224
225 private final class MessageHandler extends Handler {
226 private static final String LOG_PREFIX = "Handler";
227 MessageHandler(Looper looper) {
228 super(looper);
229 }
230
231 @Override
232 public void handleMessage(Message msg) {
233 switch (msg.what) {
234 case EVENT_SUB_CHANGED:
235 onSubscriptionsChanged();
236 break;
237 case EVENT_PROVISIONING_CAPABILITY_CHANGED:
238 try {
239 mProvisioningCallbackManagersSlotMap.get(msg.arg1)
240 .notifyProvisioningCapabilityChanged(
241 (FeatureProvisioningData) msg.obj);
242 } catch (NullPointerException e) {
243 logw(LOG_PREFIX, msg.arg1,
244 "can not find callback manager message" + msg.what);
245 }
246 break;
joonhunshin39710022022-01-14 11:53:58 +0000247 case EVENT_MULTI_SIM_CONFIGURATION_CHANGE:
248 int activeModemCount = (int) ((AsyncResult) msg.obj).result;
249 onMultiSimConfigChanged(activeModemCount);
250 break;
joonhunshin1724dd62022-08-30 07:41:20 +0000251 case EVENT_PROVISIONING_VALUE_CHANGED:
252 log("subId " + msg.arg1 + " changed provisioning value item : " + msg.arg2
253 + " value : " + (int) msg.obj);
254 updateCapabilityTechFromKey(msg.arg1, msg.arg2, (int) msg.obj);
255 break;
joonhunshin2c3e4232021-11-28 07:32:01 +0000256 default:
257 log("unknown message " + msg);
258 break;
259 }
260 }
261 }
262
263 private final SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener =
264 new SubscriptionManager.OnSubscriptionsChangedListener() {
265 @Override
266 public void onSubscriptionsChanged() {
267 if (!mHandler.hasMessages(EVENT_SUB_CHANGED)) {
268 mHandler.sendEmptyMessage(EVENT_SUB_CHANGED);
269 }
270 }
271 };
272
273 private final class ProvisioningCallbackManager {
274 private static final String LOG_PREFIX = "ProvisioningCallbackManager";
275 private RemoteCallbackList<IFeatureProvisioningCallback> mIFeatureProvisioningCallbackList;
276 private int mSubId;
277 private int mSlotId;
278
279 ProvisioningCallbackManager(int slotId) {
280 mIFeatureProvisioningCallbackList =
281 new RemoteCallbackList<IFeatureProvisioningCallback>();
282 mSlotId = slotId;
283 mSubId = getSubId(slotId);
284 log(LOG_PREFIX, mSlotId, "ProvisioningCallbackManager create");
285 }
286
287 public void clear() {
288 log(LOG_PREFIX, mSlotId, "ProvisioningCallbackManager clear ");
289
290 mIFeatureProvisioningCallbackList.kill();
291
292 // All registered callbacks are unregistered, and the list is disabled
293 // need to create again
294 mIFeatureProvisioningCallbackList =
295 new RemoteCallbackList<IFeatureProvisioningCallback>();
296 }
297
298 public void registerCallback(IFeatureProvisioningCallback localCallback) {
299 if (!mIFeatureProvisioningCallbackList.register(localCallback, (Object) mSubId)) {
300 log(LOG_PREFIX, mSlotId, "registration callback fail");
301 }
302 }
303
304 public void unregisterCallback(IFeatureProvisioningCallback localCallback) {
305 mIFeatureProvisioningCallbackList.unregister(localCallback);
306 }
307
308 public void setSubId(int subId) {
309 if (mSubId == subId) {
310 log(LOG_PREFIX, mSlotId, "subId is not changed ");
311 return;
312 }
313
314 mSubId = subId;
315 mSlotId = getSlotId(subId);
316
317 // subId changed means the registered callbacks are not available.
318 clear();
319 }
320
321 public boolean hasCallblacks() {
322 int size = mIFeatureProvisioningCallbackList.beginBroadcast();
323 mIFeatureProvisioningCallbackList.finishBroadcast();
324
325 return (size > 0);
326 }
327
328 public void notifyProvisioningCapabilityChanged(FeatureProvisioningData data) {
329 int size = mIFeatureProvisioningCallbackList.beginBroadcast();
330 for (int index = 0; index < size; index++) {
331 try {
332 IFeatureProvisioningCallback imsFeatureProvisioningCallback =
333 mIFeatureProvisioningCallbackList.getBroadcastItem(index);
334
335 // MMTEL
336 if (data.mIsMmTel
337 && Arrays.stream(LOCAL_MMTEL_CAPABILITY)
338 .anyMatch(value -> value == data.mCapability)) {
339 imsFeatureProvisioningCallback.onFeatureProvisioningChanged(
340 data.mCapability, data.mTech, data.mProvisioned);
341 logi(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : "
342 + "onFeatureProvisioningChanged"
343 + " capability " + data.mCapability
344 + " tech " + data.mTech
345 + " isProvisioned " + data.mProvisioned);
346 } else if (data.mCapability == CAPABILITY_TYPE_PRESENCE_UCE) {
347 imsFeatureProvisioningCallback.onRcsFeatureProvisioningChanged(
348 data.mCapability, data.mTech, data.mProvisioned);
349 logi(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : "
350 + "onRcsFeatureProvisioningChanged"
351 + " capability " + data.mCapability
352 + " tech " + data.mTech
353 + " isProvisioned " + data.mProvisioned);
354 } else {
355 loge(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : "
356 + "unknown capability "
357 + data.mCapability);
358 }
359 } catch (RemoteException e) {
360 loge(LOG_PREFIX, mSlotId,
361 "notifyProvisioningChanged: callback #" + index + " failed");
362 }
363 }
364 mIFeatureProvisioningCallbackList.finishBroadcast();
365 }
366 }
367
368 private final class MmTelFeatureListener implements FeatureConnector.Listener<ImsManager> {
369 private static final String LOG_PREFIX = "MmTelFeatureListener";
370 private FeatureConnector<ImsManager> mConnector;
371 private ImsManager mImsManager;
372 private boolean mReady = false;
373 // stores whether the initial provisioning key value should be notified to ImsService
374 private boolean mRequiredNotify = false;
375 private int mSubId;
376 private int mSlotId;
joonhunshin1724dd62022-08-30 07:41:20 +0000377 private ConfigCallback mConfigCallback;
joonhunshin2c3e4232021-11-28 07:32:01 +0000378
379 MmTelFeatureListener(int slotId) {
380 log(LOG_PREFIX, slotId, "created");
381
382 mSlotId = slotId;
383 mSubId = getSubId(slotId);
joonhunshin1724dd62022-08-30 07:41:20 +0000384 mConfigCallback = new ConfigCallback(mSubId);
385
joonhunshin2c3e4232021-11-28 07:32:01 +0000386 mConnector = mMmTelFeatureConnector.create(
387 mApp, slotId, TAG, this, new HandlerExecutor(mHandler));
388 mConnector.connect();
389 }
390
391 public void setSubId(int subId) {
392 if (mRequiredNotify && mReady) {
393 mRequiredNotify = false;
394 setInitialProvisioningKeys(subId);
395 }
396 if (mSubId == subId) {
397 log(LOG_PREFIX, mSlotId, "subId is not changed");
398 return;
399 }
400
401 mSubId = subId;
402 mSlotId = getSlotId(subId);
joonhunshin1724dd62022-08-30 07:41:20 +0000403 mConfigCallback.setSubId(subId);
joonhunshin2c3e4232021-11-28 07:32:01 +0000404 }
405
406 public void destroy() {
407 log("destroy");
joonhunshin1724dd62022-08-30 07:41:20 +0000408 if (mImsManager != null) {
409 try {
410 ImsConfig imsConfig = getImsConfig(mImsManager);
411 if (imsConfig != null) {
412 imsConfig.removeConfigCallback(mConfigCallback);
413 }
414 } catch (ImsException e) {
415 logw(LOG_PREFIX, mSlotId, "destroy : " + e.getMessage());
416 }
417 }
418 mConfigCallback = null;
joonhunshin2c3e4232021-11-28 07:32:01 +0000419 mConnector.disconnect();
420 mConnector = null;
421 mReady = false;
422 mImsManager = null;
423 }
424
425 public @Nullable ImsManager getImsManager() {
426 return mImsManager;
427 }
428
429 @Override
430 public void connectionReady(ImsManager manager, int subId) {
431 log(LOG_PREFIX, mSlotId, "connection ready");
432 mReady = true;
433 mImsManager = manager;
434
joonhunshin1724dd62022-08-30 07:41:20 +0000435 if (mImsManager != null) {
436 try {
437 ImsConfig imsConfig = getImsConfig(mImsManager);
438 if (imsConfig != null) {
439 imsConfig.addConfigCallback(mConfigCallback);
440 }
441 } catch (ImsException e) {
442 logw(LOG_PREFIX, mSlotId, "addConfigCallback : " + e.getMessage());
443 }
444 }
445
joonhunshin2c3e4232021-11-28 07:32:01 +0000446 onMmTelAvailable();
447 }
448
449 @Override
450 public void connectionUnavailable(int reason) {
451 log(LOG_PREFIX, mSlotId, "connection unavailable " + reason);
452
453 mReady = false;
454 mImsManager = null;
455
456 // keep the callback for other reason
457 if (reason == FeatureConnector.UNAVAILABLE_REASON_IMS_UNSUPPORTED) {
458 onMmTelUnavailable();
459 }
460 }
461
462 public int setProvisioningValue(int key, int value) {
463 int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED;
464
465 if (!mReady) {
466 loge(LOG_PREFIX, mSlotId, "service is Unavailable");
467 return retVal;
468 }
469 try {
470 // getConfigInterface() will return not null or throw the ImsException
471 // need not null checking
472 ImsConfig imsConfig = getImsConfig(mImsManager);
473 retVal = imsConfig.setConfig(key, value);
474 log(LOG_PREFIX, mSlotId, "setConfig called with key " + key + " value " + value);
475 } catch (ImsException e) {
476 logw(LOG_PREFIX, mSlotId,
477 "setConfig operation failed for key =" + key
478 + ", value =" + value + ". Exception:" + e.getMessage());
479 }
480 return retVal;
481 }
482
483 public int getProvisioningValue(int key) {
484 if (!mReady) {
485 loge(LOG_PREFIX, mSlotId, "service is Unavailable");
486 return INVALID_VALUE;
487 }
488
489 int retValue = INVALID_VALUE;
490 try {
491 // getConfigInterface() will return not null or throw the ImsException
492 // need not null checking
493 ImsConfig imsConfig = getImsConfig(mImsManager);
494 retValue = imsConfig.getConfigInt(key);
495 } catch (ImsException e) {
496 logw(LOG_PREFIX, mSlotId,
497 "getConfig operation failed for key =" + key
498 + ", value =" + retValue + ". Exception:" + e.getMessage());
499 }
500 return retValue;
501 }
502
503 public void onMmTelAvailable() {
504 log(LOG_PREFIX, mSlotId, "onMmTelAvailable");
505
506 if (isValidSubId(mSubId)) {
507 mRequiredNotify = false;
508
509 // notify provisioning key value to ImsService
510 setInitialProvisioningKeys(mSubId);
511 } else {
512 // wait until subId is valid
513 mRequiredNotify = true;
514 }
515 }
516
517 public void onMmTelUnavailable() {
518 log(LOG_PREFIX, mSlotId, "onMmTelUnavailable");
519
520 try {
521 // delete all callbacks reference from ProvisioningManager
522 mProvisioningCallbackManagersSlotMap.get(getSlotId(mSubId)).clear();
523 } catch (NullPointerException e) {
524 logw(LOG_PREFIX, getSlotId(mSubId), "can not find callback manager to clear");
525 }
526 }
527
528 private void setInitialProvisioningKeys(int subId) {
529 boolean required;
530 int value = ImsProvisioningLoader.STATUS_NOT_SET;
531
532 // updating KEY_VOLTE_PROVISIONING_STATUS
joonhunshinad228dc2022-05-20 05:54:26 +0000533 try {
534 required = isImsProvisioningRequiredForCapability(subId, CAPABILITY_TYPE_VOICE,
535 REGISTRATION_TECH_LTE);
536 } catch (IllegalArgumentException e) {
537 logw("setInitialProvisioningKeys: KEY_VOLTE_PROVISIONING_STATUS failed for"
538 + " subId=" + subId + ", exception: " + e.getMessage());
539 return;
540 }
541
joonhunshin2c3e4232021-11-28 07:32:01 +0000542 log(LOG_PREFIX, mSlotId,
543 "setInitialProvisioningKeys provisioning required(voice, lte) " + required);
544 if (required) {
545 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
546 CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE);
547 if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
548 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
549 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
550 setProvisioningValue(KEY_VOLTE_PROVISIONING_STATUS, value);
551 }
552 }
553
554 // updating KEY_VT_PROVISIONING_STATUS
joonhunshinad228dc2022-05-20 05:54:26 +0000555 try {
556 required = isImsProvisioningRequiredForCapability(subId, CAPABILITY_TYPE_VIDEO,
557 REGISTRATION_TECH_LTE);
558 } catch (IllegalArgumentException e) {
559 logw("setInitialProvisioningKeys: KEY_VT_PROVISIONING_STATUS failed for"
560 + " subId=" + subId + ", exception: " + e.getMessage());
561 return;
562 }
563
joonhunshin2c3e4232021-11-28 07:32:01 +0000564 log(LOG_PREFIX, mSlotId,
565 "setInitialProvisioningKeys provisioning required(video, lte) " + required);
566 if (required) {
567 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
568 CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_LTE);
569 if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
570 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
571 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
572 setProvisioningValue(KEY_VT_PROVISIONING_STATUS, value);
573 }
574 }
575
576 // updating KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE
joonhunshinad228dc2022-05-20 05:54:26 +0000577 try {
578 required = isImsProvisioningRequiredForCapability(subId, CAPABILITY_TYPE_VOICE,
579 REGISTRATION_TECH_IWLAN);
580 } catch (IllegalArgumentException e) {
581 logw("setInitialProvisioningKeys: KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE failed"
582 + " for subId=" + subId + ", exception: " + e.getMessage());
583 return;
584 }
585
joonhunshin2c3e4232021-11-28 07:32:01 +0000586 log(LOG_PREFIX, mSlotId,
587 "setInitialProvisioningKeys provisioning required(voice, iwlan) " + required);
588 if (required) {
589 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
590 CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_IWLAN);
591 if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
592 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
593 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
594 setProvisioningValue(KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE, value);
595 }
596 }
597 }
598 }
599
600 private final class RcsFeatureListener implements FeatureConnector.Listener<RcsFeatureManager> {
601 private static final String LOG_PREFIX = "RcsFeatureListener";
602 private FeatureConnector<RcsFeatureManager> mConnector;
603 private RcsFeatureManager mRcsFeatureManager;
604 private boolean mReady = false;
605 // stores whether the initial provisioning key value should be notified to ImsService
606 private boolean mRequiredNotify = false;
607 private int mSubId;
608 private int mSlotId;
joonhunshin1724dd62022-08-30 07:41:20 +0000609 private ConfigCallback mConfigCallback;
joonhunshin2c3e4232021-11-28 07:32:01 +0000610
611 RcsFeatureListener(int slotId) {
612 log(LOG_PREFIX, slotId, "created");
613
614 mSlotId = slotId;
615 mSubId = getSubId(slotId);
joonhunshin1724dd62022-08-30 07:41:20 +0000616 mConfigCallback = new ConfigCallback(mSubId);
617
joonhunshin2c3e4232021-11-28 07:32:01 +0000618 mConnector = mRcsFeatureConnector.create(
619 mApp, slotId, this, new HandlerExecutor(mHandler), TAG);
620 mConnector.connect();
621 }
622
623 public void setSubId(int subId) {
624 if (mRequiredNotify && mReady) {
625 mRequiredNotify = false;
626 setInitialProvisioningKeys(subId);
627 }
628 if (mSubId == subId) {
629 log(LOG_PREFIX, mSlotId, "subId is not changed");
630 return;
631 }
632
633 mSubId = subId;
634 mSlotId = getSlotId(subId);
joonhunshin1724dd62022-08-30 07:41:20 +0000635 mConfigCallback.setSubId(subId);
joonhunshin2c3e4232021-11-28 07:32:01 +0000636 }
637
638 public void destroy() {
639 log(LOG_PREFIX, mSlotId, "destroy");
joonhunshin1724dd62022-08-30 07:41:20 +0000640 if (mRcsFeatureManager != null) {
641 try {
642 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig());
643 if (imsConfig != null) {
644 imsConfig.removeConfigCallback(mConfigCallback);
645 }
646 } catch (ImsException e) {
647 logw(LOG_PREFIX, mSlotId, "destroy :" + e.getMessage());
648 }
649 }
650 mConfigCallback = null;
joonhunshin2c3e4232021-11-28 07:32:01 +0000651 mConnector.disconnect();
652 mConnector = null;
653 mReady = false;
654 mRcsFeatureManager = null;
655 }
656
657 @Override
658 public void connectionReady(RcsFeatureManager manager, int subId) {
659 log(LOG_PREFIX, mSlotId, "connection ready");
660 mReady = true;
661 mRcsFeatureManager = manager;
662
joonhunshin1724dd62022-08-30 07:41:20 +0000663 if (mRcsFeatureManager != null) {
664 try {
665 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig());
666 if (imsConfig != null) {
667 imsConfig.addConfigCallback(mConfigCallback);
668 }
669 } catch (ImsException e) {
670 logw(LOG_PREFIX, mSlotId, "addConfigCallback :" + e.getMessage());
671 }
672 }
673
joonhunshin2c3e4232021-11-28 07:32:01 +0000674 onRcsAvailable();
675 }
676
677 @Override
678 public void connectionUnavailable(int reason) {
679 log(LOG_PREFIX, mSlotId, "connection unavailable");
680 mReady = false;
681 mRcsFeatureManager = null;
682
683 // keep the callback for other reason
684 if (reason == FeatureConnector.UNAVAILABLE_REASON_IMS_UNSUPPORTED) {
685 onRcsUnavailable();
686 }
687 }
688
689 public int setProvisioningValue(int key, int value) {
690 int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED;
691
692 if (!mReady) {
693 loge(LOG_PREFIX, mSlotId, "service is Unavailable");
694 return retVal;
695 }
696
697 try {
698 // getConfigInterface() will return not null or throw the ImsException
699 // need not null checking
700 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig());
701 retVal = imsConfig.setConfig(key, value);
702 log(LOG_PREFIX, mSlotId, "setConfig called with key " + key + " value " + value);
703 } catch (ImsException e) {
704 logw(LOG_PREFIX, mSlotId,
705 "setConfig operation failed for key =" + key
706 + ", value =" + value + ". Exception:" + e.getMessage());
707 }
708 return retVal;
709 }
710
711 public int getProvisioningValue(int key) {
712 if (!mReady) {
713 loge(LOG_PREFIX, mSlotId, "service is Unavailable");
714 return INVALID_VALUE;
715 }
716
717 int retValue = INVALID_VALUE;
718 try {
719 // getConfigInterface() will return not null or throw the ImsException
720 // need not null checking
721 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig());
722 retValue = imsConfig.getConfigInt(key);
723 } catch (ImsException e) {
724 logw(LOG_PREFIX, mSlotId,
725 "getConfig operation failed for key =" + key
726 + ", value =" + retValue + ". Exception:" + e.getMessage());
727 }
728 return retValue;
729 }
730
joonhunshin35d754f2022-06-24 03:29:15 +0000731 public boolean isConnectionReady() {
732 return mReady;
733 }
734
joonhunshin2c3e4232021-11-28 07:32:01 +0000735 public void onRcsAvailable() {
736 log(LOG_PREFIX, mSlotId, "onRcsAvailable");
737
738 if (isValidSubId(mSubId)) {
739 mRequiredNotify = false;
740
741 // notify provisioning key value to ImsService
742 setInitialProvisioningKeys(mSubId);
743 } else {
744 // wait until subId is valid
745 mRequiredNotify = true;
746 }
747 }
748
749 public void onRcsUnavailable() {
750 log(LOG_PREFIX, mSlotId, "onRcsUnavailable");
751
752 try {
753 // delete all callbacks reference from ProvisioningManager
754 mProvisioningCallbackManagersSlotMap.get(getSlotId(mSubId)).clear();
755 } catch (NullPointerException e) {
756 logw(LOG_PREFIX, getSlotId(mSubId), "can not find callback manager to clear");
757 }
758 }
759
760 private void setInitialProvisioningKeys(int subId) {
761 boolean required;
762 int value = ImsProvisioningLoader.STATUS_NOT_SET;
763
764 // KEY_EAB_PROVISIONING_STATUS
765 int capability = CAPABILITY_TYPE_PRESENCE_UCE;
766 // Assume that all radio techs have the same provisioning value
767 int tech = REGISTRATION_TECH_LTE;
768
joonhunshinad228dc2022-05-20 05:54:26 +0000769 try {
770 required = isRcsProvisioningRequiredForCapability(subId, capability, tech);
771 } catch (IllegalArgumentException e) {
772 logw("setInitialProvisioningKeys: KEY_EAB_PROVISIONING_STATUS failed for"
773 + " subId=" + subId + ", exception: " + e.getMessage());
774 return;
775 }
776
joonhunshin2c3e4232021-11-28 07:32:01 +0000777 if (required) {
778 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
779 capability, tech);
780 if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
781 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
782 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
783 setProvisioningValue(KEY_EAB_PROVISIONING_STATUS, value);
784 }
785 }
786 }
787 }
788
joonhunshin1724dd62022-08-30 07:41:20 +0000789 // When vendor ImsService changed provisioning data, which should be updated in AOSP.
790 // Catch the event using IImsConfigCallback.
791 private final class ConfigCallback extends IImsConfigCallback.Stub {
792 private int mSubId;
793
794 ConfigCallback(int subId) {
795 mSubId = subId;
796 }
797
798 public void setSubId(int subId) {
799 mSubId = subId;
800 }
801
802 @Override
803 public void onIntConfigChanged(int item, int value) throws RemoteException {
804 if (!Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(keyValue -> keyValue == item)) {
805 return;
806 }
807
808 final long callingIdentity = Binder.clearCallingIdentity();
809 try {
810 if (mHandler != null) {
811 mHandler.sendMessage(mHandler.obtainMessage(
812 EVENT_PROVISIONING_VALUE_CHANGED, mSubId, item, (Object) value));
813 }
814 } finally {
815 Binder.restoreCallingIdentity(callingIdentity);
816 }
817 }
818
819 @Override
820 public void onStringConfigChanged(int item, String value) throws RemoteException {
821 // Ignore this callback.
822 }
823 }
824
joonhunshin2c3e4232021-11-28 07:32:01 +0000825 /**
826 * Do NOT use this directly, instead use {@link #getInstance()}.
827 */
828 @VisibleForTesting
829 public ImsProvisioningController(PhoneGlobals app, int numSlot, Looper looper,
830 MmTelFeatureConnector mmTelFeatureConnector, RcsFeatureConnector rcsFeatureConnector,
831 ImsProvisioningLoader imsProvisioningLoader) {
832 log("ImsProvisioningController");
833 mApp = app;
834 mNumSlot = numSlot;
835 mHandler = new MessageHandler(looper);
836 mMmTelFeatureConnector = mmTelFeatureConnector;
837 mRcsFeatureConnector = rcsFeatureConnector;
838 mCarrierConfigManager = mApp.getSystemService(CarrierConfigManager.class);
839 mSubscriptionManager = mApp.getSystemService(SubscriptionManager.class);
840 mTelephonyRegistryManager = mApp.getSystemService(TelephonyRegistryManager.class);
841 mTelephonyRegistryManager.addOnSubscriptionsChangedListener(
842 mSubChangedListener, mSubChangedListener.getHandlerExecutor());
843 mImsProvisioningLoader = imsProvisioningLoader;
844
joonhunshin39710022022-01-14 11:53:58 +0000845 PhoneConfigurationManager.registerForMultiSimConfigChange(mHandler,
846 EVENT_MULTI_SIM_CONFIGURATION_CHANGE, null);
847
joonhunshin2c3e4232021-11-28 07:32:01 +0000848 initialize(numSlot);
849 }
850
851 private void initialize(int numSlot) {
852 for (int i = 0; i < numSlot; i++) {
853 MmTelFeatureListener m = new MmTelFeatureListener(i);
854 mMmTelFeatureListenersSlotMap.put(i, m);
855
856 RcsFeatureListener r = new RcsFeatureListener(i);
857 mRcsFeatureListenersSlotMap.put(i, r);
858
859 ProvisioningCallbackManager p = new ProvisioningCallbackManager(i);
860 mProvisioningCallbackManagersSlotMap.put(i, p);
861 }
862 }
863
joonhunshin39710022022-01-14 11:53:58 +0000864 private void onMultiSimConfigChanged(int newNumSlot) {
865 log("onMultiSimConfigChanged: NumSlot " + mNumSlot + " newNumSlot " + newNumSlot);
866
867 if (mNumSlot < newNumSlot) {
868 for (int i = mNumSlot; i < newNumSlot; i++) {
869 MmTelFeatureListener m = new MmTelFeatureListener(i);
870 mMmTelFeatureListenersSlotMap.put(i, m);
871
872 RcsFeatureListener r = new RcsFeatureListener(i);
873 mRcsFeatureListenersSlotMap.put(i, r);
874
875 ProvisioningCallbackManager p = new ProvisioningCallbackManager(i);
876 mProvisioningCallbackManagersSlotMap.put(i, p);
877 }
878 } else if (mNumSlot > newNumSlot) {
879 for (int i = (mNumSlot - 1); i > (newNumSlot - 1); i--) {
880 MmTelFeatureListener m = mMmTelFeatureListenersSlotMap.get(i);
881 mMmTelFeatureListenersSlotMap.remove(i);
882 m.destroy();
883
884 RcsFeatureListener r = mRcsFeatureListenersSlotMap.get(i);
885 mRcsFeatureListenersSlotMap.remove(i);
886 r.destroy();
887
888 ProvisioningCallbackManager p = mProvisioningCallbackManagersSlotMap.get(i);
889 mProvisioningCallbackManagersSlotMap.remove(i);
890 p.clear();
891 }
892 }
893
894 mNumSlot = newNumSlot;
895 }
896
joonhunshin2c3e4232021-11-28 07:32:01 +0000897 /**
898 * destroy the instance
899 */
900 @VisibleForTesting
901 public void destroy() {
902 log("destroy");
903
904 mHandler.getLooper().quit();
905
906 mTelephonyRegistryManager.removeOnSubscriptionsChangedListener(mSubChangedListener);
907
908 for (int i = 0; i < mMmTelFeatureListenersSlotMap.size(); i++) {
909 mMmTelFeatureListenersSlotMap.get(i).destroy();
910 }
911 mMmTelFeatureListenersSlotMap.clear();
912
913 for (int i = 0; i < mRcsFeatureListenersSlotMap.size(); i++) {
914 mRcsFeatureListenersSlotMap.get(i).destroy();
915 }
916 mRcsFeatureListenersSlotMap.clear();
917
918 for (int i = 0; i < mProvisioningCallbackManagersSlotMap.size(); i++) {
919 mProvisioningCallbackManagersSlotMap.get(i).clear();
920 }
921 }
922
923 /**
924 * create an instance
925 */
926 @VisibleForTesting
927 public static ImsProvisioningController make(PhoneGlobals app, int numSlot) {
928 synchronized (ImsProvisioningController.class) {
929 if (sInstance == null) {
930 Rlog.i(TAG, "ImsProvisioningController created");
931 HandlerThread handlerThread = new HandlerThread(TAG);
932 handlerThread.start();
933 sInstance = new ImsProvisioningController(app, numSlot, handlerThread.getLooper(),
934 ImsManager::getConnector, RcsFeatureManager::getConnector,
935 new ImsProvisioningLoader(app));
936 }
937 }
938 return sInstance;
939 }
940
941 /**
942 * Gets a ImsProvisioningController instance
943 */
944 @VisibleForTesting
945 public static ImsProvisioningController getInstance() {
946 synchronized (ImsProvisioningController.class) {
947 return sInstance;
948 }
949 }
950
951 /**
952 * Register IFeatureProvisioningCallback from ProvisioningManager
953 */
954
955 @VisibleForTesting
956 public void addFeatureProvisioningChangedCallback(int subId,
957 IFeatureProvisioningCallback callback) {
958 if (callback == null) {
959 throw new IllegalArgumentException("provisioning callback can't be null");
960 }
961 int slotId = getSlotId(subId);
962 if (slotId < 0 || slotId >= mNumSlot) {
963 throw new IllegalArgumentException("subscription id is not available");
964 }
965
966 try {
967 mProvisioningCallbackManagersSlotMap.get(slotId).registerCallback(callback);
968 log("Feature Provisioning Callback registered.");
969 } catch (NullPointerException e) {
970 logw("can not access callback manager to add callback");
971 }
972 }
973
974 /**
975 * Remove IFeatureProvisioningCallback
976 */
977 @VisibleForTesting
978 public void removeFeatureProvisioningChangedCallback(int subId,
979 IFeatureProvisioningCallback callback) {
980 if (callback == null) {
981 throw new IllegalArgumentException("provisioning callback can't be null");
982 }
983
984 int slotId = getSlotId(subId);
985 if (slotId < 0 || slotId >= mNumSlot) {
986 throw new IllegalArgumentException("subscription id is not available");
987 }
988
989 try {
990 mProvisioningCallbackManagersSlotMap.get(slotId).unregisterCallback(callback);
991 log("Feature Provisioning Callback removed.");
992 } catch (NullPointerException e) {
993 logw("can not access callback manager to remove callback");
994 }
995 }
996
997 /**
joonhunshinf9411cb2022-01-17 07:37:15 +0000998 * return the boolean whether MmTel capability is required provisioning or not
joonhunshin2c3e4232021-11-28 07:32:01 +0000999 */
1000 @VisibleForTesting
1001 public boolean isImsProvisioningRequiredForCapability(int subId, int capability, int tech) {
1002 // check subId
1003 int slotId = getSlotId(subId);
1004 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
1005 loge("Fail to retrieve slotId from subId");
1006 throw new IllegalArgumentException("subscribe id is invalid");
1007 }
1008
1009 // check valid capability
1010 if (!(MMTEL_CAPABILITY_MIN < capability && capability < MMTEL_CAPABILITY_MAX)) {
1011 throw new IllegalArgumentException("MmTel capability '" + capability + "' is invalid");
1012 }
1013
1014 // check valid radio tech
1015 if (!(REGISTRATION_TECH_NONE < tech && tech < REGISTRATION_TECH_MAX)) {
1016 log("Ims not matched radio tech " + tech);
1017 throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
1018 }
1019
joonhunshin10e74ea2022-04-29 06:29:35 +00001020 // check new carrier config first KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE
joonhunshin2c3e4232021-11-28 07:32:01 +00001021 boolean retVal = isProvisioningRequired(subId, capability, tech, /*isMmTel*/true);
1022
joonhunshin10e74ea2022-04-29 06:29:35 +00001023 // if that returns false, check deprecated carrier config
1024 // KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL
1025 if (!retVal && (capability == CAPABILITY_TYPE_VOICE
1026 || capability == CAPABILITY_TYPE_VIDEO
1027 || capability == CAPABILITY_TYPE_UT)) {
1028 String key = CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL;
1029 if (capability == CAPABILITY_TYPE_UT) {
1030 key = CarrierConfigManager.KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL;
1031 }
1032
1033 PersistableBundle imsCarrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
1034 if (imsCarrierConfigs != null) {
1035 retVal = imsCarrierConfigs.getBoolean(key);
1036 } else {
1037 retVal = CarrierConfigManager.getDefaultConfig().getBoolean(key);
1038 }
1039 }
1040
joonhunshin2c3e4232021-11-28 07:32:01 +00001041 log("isImsProvisioningRequiredForCapability capability " + capability
1042 + " tech " + tech + " return value " + retVal);
1043
1044 return retVal;
1045 }
1046
1047 /**
joonhunshinf9411cb2022-01-17 07:37:15 +00001048 * return the boolean whether RCS capability is required provisioning or not
joonhunshin2c3e4232021-11-28 07:32:01 +00001049 */
1050 @VisibleForTesting
1051 public boolean isRcsProvisioningRequiredForCapability(int subId, int capability, int tech) {
1052 // check slotId and Phone object
1053 int slotId = getSlotId(subId);
1054 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
1055 loge("Fail to retrieve slotId from subId");
1056 throw new IllegalArgumentException("subscribe id is invalid");
1057 }
1058
1059 // check valid capability
1060 if (!(RCS_CAPABILITY_MIN < capability && capability < RCS_CAPABILITY_MAX)) {
1061 throw new IllegalArgumentException("Rcs capability '" + capability + "' is invalid");
1062 }
1063
1064 // check valid radio tech
1065 if (!(REGISTRATION_TECH_NONE < tech && tech < REGISTRATION_TECH_MAX)) {
1066 log("Rcs not matched radio tech " + tech);
1067 throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
1068 }
1069
joonhunshin10e74ea2022-04-29 06:29:35 +00001070 // check new carrier config first KEY_RCS_REQUIRES_PROVISIONING_BUNDLE
joonhunshin2c3e4232021-11-28 07:32:01 +00001071 boolean retVal = isProvisioningRequired(subId, capability, tech, /*isMmTel*/false);
1072
joonhunshin10e74ea2022-04-29 06:29:35 +00001073 // if that returns false, check deprecated carrier config
1074 // KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL
1075 if (!retVal) {
1076 PersistableBundle imsCarrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
1077 if (imsCarrierConfigs != null) {
1078 retVal = imsCarrierConfigs.getBoolean(
1079 CarrierConfigManager.KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL);
1080 } else {
1081 retVal = CarrierConfigManager.getDefaultConfig().getBoolean(
1082 CarrierConfigManager.KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL);
1083 }
1084 }
1085
joonhunshin2c3e4232021-11-28 07:32:01 +00001086 log("isRcsProvisioningRequiredForCapability capability " + capability
1087 + " tech " + tech + " return value " + retVal);
1088
1089 return retVal;
1090 }
1091
1092 /**
1093 * return the provisioning status for MmTel capability in specific radio tech
1094 */
1095 @VisibleForTesting
1096 public boolean getImsProvisioningStatusForCapability(int subId, int capability, int tech) {
1097 boolean mmTelProvisioned = isImsProvisioningRequiredForCapability(subId, capability, tech);
1098 if (!mmTelProvisioned) { // provisioning not required
1099 log("getImsProvisioningStatusForCapability : not required "
1100 + " capability " + capability + " tech " + tech);
1101 return true;
1102 }
1103
1104 // read value from ImsProvisioningLoader
1105 int result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
1106 capability, tech);
1107 if (result == ImsProvisioningLoader.STATUS_NOT_SET) {
1108 // not set means initial value
1109 // read data from vendor ImsService and store that in ImsProvisioningLoader
1110 result = getValueFromImsService(subId, capability, tech);
1111 mmTelProvisioned = getBoolValue(result);
1112 if (result != ProvisioningManager.PROVISIONING_RESULT_UNKNOWN) {
1113 setAndNotifyMmTelProvisioningValue(subId, capability, tech, mmTelProvisioned);
1114 }
1115 } else {
1116 mmTelProvisioned = getBoolValue(result);
1117 }
1118
1119 log("getImsProvisioningStatusForCapability : "
1120 + " capability " + capability
1121 + " tech " + tech
1122 + " result " + mmTelProvisioned);
1123 return mmTelProvisioned;
1124 }
1125
1126 /**
1127 * set MmTel provisioning status in specific tech
1128 */
1129 @VisibleForTesting
1130 public void setImsProvisioningStatusForCapability(int subId, int capability, int tech,
1131 boolean isProvisioned) {
1132 boolean mmTelProvisioned = isImsProvisioningRequiredForCapability(subId, capability, tech);
1133 if (!mmTelProvisioned) { // provisioning not required
1134 log("setImsProvisioningStatusForCapability : not required "
1135 + " capability " + capability + " tech " + tech);
1136 return;
1137 }
1138
1139 // write value to ImsProvisioningLoader
1140 boolean isChanged = setAndNotifyMmTelProvisioningValue(subId, capability, tech,
1141 isProvisioned);
1142 if (!isChanged) {
1143 log("status not changed mmtel capability " + capability + " tech " + tech);
1144 return;
1145 }
1146
1147 int slotId = getSlotId(subId);
1148 // find matched key from capability and tech
1149 int value = getIntValue(isProvisioned);
1150 int key = getKeyFromCapability(capability, tech);
1151 if (key != INVALID_VALUE) {
1152 log("setImsProvisioningStatusForCapability : matched key " + key);
1153 try {
1154 // set key and value to vendor ImsService for MmTel
1155 mMmTelFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
joonhunshin2c3e4232021-11-28 07:32:01 +00001156 } catch (NullPointerException e) {
1157 loge("can not access MmTelFeatureListener with capability " + capability);
1158 }
1159 }
1160 }
1161
1162 /**
1163 * return the provisioning status for RCS capability in specific radio tech
1164 */
1165 @VisibleForTesting
1166 public boolean getRcsProvisioningStatusForCapability(int subId, int capability, int tech) {
1167 boolean rcsProvisioned = isRcsProvisioningRequiredForCapability(subId, capability, tech);
1168 if (!rcsProvisioned) { // provisioning not required
1169 log("getRcsProvisioningStatusForCapability : not required"
1170 + " capability " + capability + " tech " + tech);
1171 return true;
1172 }
1173
1174 // read data from ImsProvisioningLoader
1175 int result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
1176 capability, tech);
1177 if (result == ImsProvisioningLoader.STATUS_NOT_SET) {
1178 // not set means initial value
1179 // read data from vendor ImsService and store that in ImsProvisioningLoader
1180 result = getRcsValueFromImsService(subId, capability);
1181 rcsProvisioned = getBoolValue(result);
1182 if (result != ProvisioningManager.PROVISIONING_RESULT_UNKNOWN) {
1183 setAndNotifyRcsProvisioningValueForAllTech(subId, capability, rcsProvisioned);
1184 }
1185 } else {
1186 rcsProvisioned = getBoolValue(result);
1187 }
1188
1189 log("getRcsProvisioningStatusForCapability : "
1190 + " capability " + capability
1191 + " tech " + tech
1192 + " result " + rcsProvisioned);
1193 return rcsProvisioned;
1194 }
1195
1196 /**
1197 * set RCS provisioning status in specific tech
1198 */
1199 @VisibleForTesting
1200 public void setRcsProvisioningStatusForCapability(int subId, int capability, int tech,
1201 boolean isProvisioned) {
1202 boolean rcsProvisioned = isRcsProvisioningRequiredForCapability(subId, capability, tech);
1203 if (!rcsProvisioned) { // provisioning not required
1204 log("set rcs provisioning status but not required");
1205 return;
1206 }
1207
1208 // write status using ImsProvisioningLoader
1209 boolean isChanged = setAndNotifyRcsProvisioningValue(subId, capability, tech,
1210 isProvisioned);
1211 if (!isChanged) {
1212 log("status not changed rcs capability " + capability + " tech " + tech);
1213 return;
1214 }
1215
1216 int slotId = getSlotId(subId);
1217 int key = ProvisioningManager.KEY_EAB_PROVISIONING_STATUS;
1218 int value = getIntValue(isProvisioned);
1219 try {
joonhunshin35d754f2022-06-24 03:29:15 +00001220 // On some older devices, EAB is managed on the MmTel ImsService when the RCS
1221 // ImsService is not configured. If there is no RCS ImsService defined, fallback to
1222 // MmTel. In the rare case that we hit a race condition where the RCS ImsService has
1223 // crashed or has not come up yet, the value will be synchronized via
1224 // setInitialProvisioningKeys().
1225 if (mRcsFeatureListenersSlotMap.get(slotId).isConnectionReady()) {
1226 mRcsFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
1227 }
1228
1229 // EAB provisioning status should be updated to both the Rcs and MmTel ImsService,
1230 // because the provisioning callback is listening to only MmTel provisioning key
1231 // changes.
1232 mMmTelFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
joonhunshin2c3e4232021-11-28 07:32:01 +00001233 } catch (NullPointerException e) {
1234 loge("can not access RcsFeatureListener with capability " + capability);
1235 }
1236 }
1237
1238 /**
1239 * set RCS provisioning status in specific key and value
1240 * @param key integer key, defined as one of
1241 * {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS}
1242 * {@link ProvisioningManager#KEY_VT_PROVISIONING_STATUS}
1243 * {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE}
1244 * {@link ProvisioningManager#KEY_EAB_PROVISIONING_STATUS}
1245 * @param value in Integer format.
1246 * @return the result of setting the configuration value, defined as one of
1247 * {@link ImsConfigImplBase#CONFIG_RESULT_FAILED} or
1248 * {@link ImsConfigImplBase#CONFIG_RESULT_SUCCESS} or
1249 */
1250 @VisibleForTesting
1251 public int setProvisioningValue(int subId, int key, int value) {
1252 log("setProvisioningValue");
1253
1254 int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED;
1255 // check key value
1256 if (!Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(keyValue -> keyValue == key)) {
1257 log("not matched key " + key);
1258 return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
1259 }
1260
1261 // check subId
1262 int slotId = getSlotId(subId);
1263 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
1264 loge("Fail to retrieve slotId from subId");
1265 return ImsConfigImplBase.CONFIG_RESULT_FAILED;
1266 }
1267
1268 try {
joonhunshin35d754f2022-06-24 03:29:15 +00001269 // set key and value to vendor ImsService for MmTel
1270 // EAB provisioning status should be updated to both the Rcs and MmTel ImsService,
1271 // because the provisioning callback is listening to only MmTel provisioning key
1272 // changes.
1273 retVal = mMmTelFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
1274
1275 // If the Rcs ImsService is not available, the EAB provisioning status will be written
1276 // to the MmTel ImsService for backwards compatibility. In the rare case that this is
1277 // hit due to RCS ImsService temporarily unavailable, the value will be synchronized
1278 // via setInitialProvisioningKeys() when the RCS ImsService comes back up.
1279 if (key == KEY_EAB_PROVISIONING_STATUS
1280 && mRcsFeatureListenersSlotMap.get(slotId).isConnectionReady()) {
1281 // set key and value to vendor ImsService for RCS and use retVal from RCS if
1282 // related to EAB when possible.
1283 retVal = mRcsFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
joonhunshin2c3e4232021-11-28 07:32:01 +00001284 }
1285 } catch (NullPointerException e) {
1286 loge("can not access FeatureListener to set provisioning value");
1287 return ImsConfigImplBase.CONFIG_RESULT_FAILED;
1288 }
1289
1290 // update and notify provisioning status changed capability and tech from key
1291 updateCapabilityTechFromKey(subId, key, value);
1292
joonhunshin2c3e4232021-11-28 07:32:01 +00001293 return retVal;
1294 }
1295
1296 /**
1297 * get RCS provisioning status in specific key and value
1298 * @param key integer key, defined as one of
1299 * {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS}
1300 * {@link ProvisioningManager#KEY_VT_PROVISIONING_STATUS}
1301 * {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE}
1302 * {@link ProvisioningManager#KEY_EAB_PROVISIONING_STATUS}
1303 * @return the result of setting the configuration value, defined as one of
1304 * {@link ImsConfigImplBase#CONFIG_RESULT_FAILED} or
1305 * {@link ImsConfigImplBase#CONFIG_RESULT_SUCCESS} or
1306 * {@link ImsConfigImplBase#CONFIG_RESULT_UNKNOWN}
1307 */
1308 @VisibleForTesting
1309 public int getProvisioningValue(int subId, int key) {
joonhunshin2c3e4232021-11-28 07:32:01 +00001310 // check key value
1311 if (!Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(keyValue -> keyValue == key)) {
1312 log("not matched key " + key);
1313 return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
1314 }
1315
1316 // check subId
1317 int slotId = getSlotId(subId);
1318 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
1319 loge("Fail to retrieve slotId from subId");
1320 return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
1321 }
1322
1323 // check data from ImsProvisioningLoader
1324 int capability = getCapabilityFromKey(key);
1325 int tech = getTechFromKey(key);
1326 int result;
1327 if (capability != INVALID_VALUE && tech != INVALID_VALUE) {
1328 if (key == KEY_EAB_PROVISIONING_STATUS) {
1329 result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
1330 capability, tech);
1331 } else {
1332 result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
1333 capability, tech);
1334 }
1335 if (result != ImsProvisioningLoader.STATUS_NOT_SET) {
joonhunshin6cd38ac2022-02-03 06:37:55 +00001336 log("getProvisioningValue from loader : key " + key + " result " + result);
joonhunshin2c3e4232021-11-28 07:32:01 +00001337 return result;
1338 }
1339 }
1340
1341 // get data from ImsService, update it in ImsProvisioningLoader
1342 if (key == KEY_EAB_PROVISIONING_STATUS) {
1343 result = getRcsValueFromImsService(subId, capability);
1344 if (result == ImsConfigImplBase.CONFIG_RESULT_UNKNOWN) {
1345 logw("getProvisioningValue : fail to get data from ImsService capability"
1346 + capability);
1347 return result;
1348 }
joonhunshin6cd38ac2022-02-03 06:37:55 +00001349 log("getProvisioningValue from vendor : key " + key + " result " + result);
1350
joonhunshin2c3e4232021-11-28 07:32:01 +00001351 setAndNotifyRcsProvisioningValueForAllTech(subId, capability, getBoolValue(result));
1352 return result;
1353 } else {
1354 result = getValueFromImsService(subId, capability, tech);
1355 if (result == ImsConfigImplBase.CONFIG_RESULT_UNKNOWN) {
1356 logw("getProvisioningValue : fail to get data from ImsService capability"
1357 + capability);
1358 return result;
1359 }
joonhunshin6cd38ac2022-02-03 06:37:55 +00001360 log("getProvisioningValue from vendor : key " + key + " result " + result);
1361
joonhunshin2c3e4232021-11-28 07:32:01 +00001362 setAndNotifyMmTelProvisioningValue(subId, capability, tech, getBoolValue(result));
1363 return result;
1364 }
1365 }
1366
1367 /**
1368 * get the handler
1369 */
1370 @VisibleForTesting
1371 public Handler getHandler() {
1372 return mHandler;
1373 }
1374
1375 private boolean isProvisioningRequired(int subId, int capability, int tech, boolean isMmTel) {
joonhunshinf9411cb2022-01-17 07:37:15 +00001376 int[] techArray;
1377 techArray = getTechsFromCarrierConfig(subId, capability, isMmTel);
1378 if (techArray == null) {
1379 logw("isProvisioningRequired : getTechsFromCarrierConfig failed");
1380 // not exist in CarrierConfig that means provisioning is not required
joonhunshin2c3e4232021-11-28 07:32:01 +00001381 return false;
1382 }
1383
joonhunshin2c3e4232021-11-28 07:32:01 +00001384 // compare with carrier config
joonhunshinf9411cb2022-01-17 07:37:15 +00001385 if (Arrays.stream(techArray).anyMatch(keyValue -> keyValue == tech)) {
1386 // existing same tech means provisioning required
1387 return true;
joonhunshin2c3e4232021-11-28 07:32:01 +00001388 }
1389
1390 log("isProvisioningRequired : not matched capability " + capability + " tech " + tech);
1391 return false;
1392 }
1393
joonhunshin10e74ea2022-04-29 06:29:35 +00001394 private int[] getTechsFromCarrierConfig(int subId, int capability, boolean isMmTel) {
joonhunshinf9411cb2022-01-17 07:37:15 +00001395 String featureKey;
1396 String capabilityKey;
1397 if (isMmTel) {
1398 featureKey = CarrierConfigManager.Ims.KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE;
1399 capabilityKey = KEYS_MMTEL_CAPABILITY.get(capability);
1400 } else {
1401 featureKey = CarrierConfigManager.Ims.KEY_RCS_REQUIRES_PROVISIONING_BUNDLE;
1402 capabilityKey = KEYS_RCS_CAPABILITY.get(capability);
1403 }
joonhunshin2c3e4232021-11-28 07:32:01 +00001404
joonhunshinf9411cb2022-01-17 07:37:15 +00001405 if (capabilityKey != null) {
1406 PersistableBundle imsCarrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
1407 if (imsCarrierConfigs == null) {
1408 log("getTechsFromCarrierConfig : imsCarrierConfigs null");
1409 return null;
1410 }
1411
1412 PersistableBundle provisioningBundle =
1413 imsCarrierConfigs.getPersistableBundle(featureKey);
1414 if (provisioningBundle == null) {
1415 log("getTechsFromCarrierConfig : provisioningBundle null");
1416 return null;
1417 }
1418
1419 return provisioningBundle.getIntArray(capabilityKey);
1420 }
1421
1422 return null;
joonhunshin2c3e4232021-11-28 07:32:01 +00001423 }
1424
1425 private int getValueFromImsService(int subId, int capability, int tech) {
1426 int config = ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
1427
1428 // operation is based on capability
1429 switch (capability) {
1430 case CAPABILITY_TYPE_VOICE:
1431 int item = (tech == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN)
1432 ? ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE
1433 : ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS;
1434 // read data from vendor ImsService
1435 config = mMmTelFeatureListenersSlotMap.get(getSlotId(subId))
1436 .getProvisioningValue(item);
1437 break;
1438 case CAPABILITY_TYPE_VIDEO:
1439 // read data from vendor ImsService
1440 config = mMmTelFeatureListenersSlotMap.get(getSlotId(subId))
1441 .getProvisioningValue(ProvisioningManager.KEY_VT_PROVISIONING_STATUS);
1442 break;
1443 default:
1444 log("Capability " + capability + " has been provisioning");
1445 break;
1446 }
1447
1448 return config;
1449 }
1450
1451 private int getRcsValueFromImsService(int subId, int capability) {
1452 int config = ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
joonhunshin35d754f2022-06-24 03:29:15 +00001453 int slotId = getSlotId(subId);
joonhunshin2c3e4232021-11-28 07:32:01 +00001454
joonhunshin35d754f2022-06-24 03:29:15 +00001455 if (capability != CAPABILITY_TYPE_PRESENCE_UCE) {
joonhunshin2c3e4232021-11-28 07:32:01 +00001456 log("Capability " + capability + " has been provisioning");
joonhunshin35d754f2022-06-24 03:29:15 +00001457 return config;
1458 }
1459 try {
1460 if (mRcsFeatureListenersSlotMap.get(slotId).isConnectionReady()) {
1461 config = mRcsFeatureListenersSlotMap.get(slotId)
1462 .getProvisioningValue(ProvisioningManager.KEY_EAB_PROVISIONING_STATUS);
1463 } else {
1464 log("Rcs ImsService is not available, "
1465 + "EAB provisioning status should be read from MmTel ImsService");
1466 config = mMmTelFeatureListenersSlotMap.get(slotId)
1467 .getProvisioningValue(ProvisioningManager.KEY_EAB_PROVISIONING_STATUS);
1468 }
1469 } catch (NullPointerException e) {
1470 logw("can not access FeatureListener : " + e.getMessage());
joonhunshin2c3e4232021-11-28 07:32:01 +00001471 }
1472
1473 return config;
1474 }
1475
1476 private void onSubscriptionsChanged() {
1477 for (int index = 0; index < mMmTelFeatureListenersSlotMap.size(); index++) {
1478 MmTelFeatureListener m = mMmTelFeatureListenersSlotMap.get(index);
1479 m.setSubId(getSubId(index));
1480 }
1481 for (int index = 0; index < mRcsFeatureListenersSlotMap.size(); index++) {
1482 RcsFeatureListener r = mRcsFeatureListenersSlotMap.get(index);
1483 r.setSubId(getSubId(index));
1484 }
1485 for (int index = 0; index < mProvisioningCallbackManagersSlotMap.size(); index++) {
1486 ProvisioningCallbackManager m = mProvisioningCallbackManagersSlotMap.get(index);
1487 m.setSubId(getSubId(index));
1488 }
1489 }
1490
1491 private void updateCapabilityTechFromKey(int subId, int key, int value) {
1492 boolean isProvisioned = getBoolValue(value);
1493 int capability = getCapabilityFromKey(key);
1494 int tech = getTechFromKey(key);
1495
1496 if (capability == INVALID_VALUE || tech == INVALID_VALUE) {
1497 logw("updateCapabilityTechFromKey : unknown key " + key);
1498 return;
1499 }
1500
1501 if (key == KEY_VOLTE_PROVISIONING_STATUS
1502 || key == KEY_VT_PROVISIONING_STATUS
1503 || key == KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE) {
1504 setAndNotifyMmTelProvisioningValue(subId, capability, tech, isProvisioned);
1505 }
1506 if (key == KEY_EAB_PROVISIONING_STATUS) {
1507 setAndNotifyRcsProvisioningValueForAllTech(subId, capability, isProvisioned);
1508 }
1509 }
1510
1511 private int getCapabilityFromKey(int key) {
1512 int capability;
1513 switch (key) {
1514 case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS:
1515 // intentional fallthrough
1516 case ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE:
1517 capability = CAPABILITY_TYPE_VOICE;
1518 break;
1519 case ProvisioningManager.KEY_VT_PROVISIONING_STATUS:
1520 capability = CAPABILITY_TYPE_VIDEO;
1521 break;
1522 case ProvisioningManager.KEY_EAB_PROVISIONING_STATUS:
1523 // default CAPABILITY_TYPE_PRESENCE_UCE used for KEY_EAB_PROVISIONING_STATUS
1524 capability = CAPABILITY_TYPE_PRESENCE_UCE;
1525 break;
1526 default:
1527 capability = INVALID_VALUE;
1528 break;
1529 }
1530 return capability;
1531 }
1532
1533 private int getTechFromKey(int key) {
1534 int tech;
1535 switch (key) {
1536 case ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE:
1537 tech = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
1538 break;
1539 case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS:
1540 // intentional fallthrough
1541 case ProvisioningManager.KEY_VT_PROVISIONING_STATUS:
1542 // intentional fallthrough
1543 case ProvisioningManager.KEY_EAB_PROVISIONING_STATUS:
1544 tech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
1545 break;
1546 default:
1547 tech = INVALID_VALUE;
1548 break;
1549 }
1550 return tech;
1551 }
1552
1553 private int getKeyFromCapability(int capability, int tech) {
1554 int key = INVALID_VALUE;
1555 if (capability == CAPABILITY_TYPE_VOICE && tech == REGISTRATION_TECH_IWLAN) {
1556 key = ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE;
1557 } else if (capability == CAPABILITY_TYPE_VOICE && tech == REGISTRATION_TECH_LTE) {
1558 key = ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS;
1559 } else if (capability == CAPABILITY_TYPE_VIDEO && tech == REGISTRATION_TECH_LTE) {
1560 key = ProvisioningManager.KEY_VT_PROVISIONING_STATUS;
1561 }
1562
1563 return key;
1564 }
1565
1566 protected int getSubId(int slotId) {
1567 final int[] subIds = mSubscriptionManager.getSubscriptionIds(slotId);
1568 int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1569 if (subIds != null && subIds.length >= 1) {
1570 subId = subIds[0];
1571 }
1572
1573 return subId;
1574 }
1575
1576 protected int getSlotId(int subId) {
1577 return mSubscriptionManager.getPhoneId(subId);
1578 }
1579
1580 protected ImsConfig getImsConfig(ImsManager imsManager) throws ImsException {
1581 return imsManager.getConfigInterface();
1582 }
1583
1584 protected ImsConfig getImsConfig(IImsConfig iImsConfig) {
1585 return new ImsConfig(iImsConfig);
1586 }
1587
1588 private int getIntValue(boolean isProvisioned) {
1589 return isProvisioned ? ProvisioningManager.PROVISIONING_VALUE_ENABLED
1590 : ProvisioningManager.PROVISIONING_VALUE_DISABLED;
1591 }
1592
1593 private boolean getBoolValue(int value) {
1594 return value == ProvisioningManager.PROVISIONING_VALUE_ENABLED ? true : false;
1595 }
1596
1597 private boolean setAndNotifyMmTelProvisioningValue(int subId, int capability, int tech,
1598 boolean isProvisioned) {
1599 boolean changed = mImsProvisioningLoader.setProvisioningStatus(subId, FEATURE_MMTEL,
1600 capability, tech, isProvisioned);
1601 // notify MmTel capability changed
1602 if (changed) {
1603 mHandler.sendMessage(mHandler.obtainMessage(EVENT_PROVISIONING_CAPABILITY_CHANGED,
1604 getSlotId(subId), 0, (Object) new FeatureProvisioningData(
1605 capability, tech, isProvisioned, /*isMmTel*/true)));
1606 }
1607
1608 return changed;
1609 }
1610
1611 private boolean setAndNotifyRcsProvisioningValue(int subId, int capability, int tech,
1612 boolean isProvisioned) {
1613 boolean isChanged = mImsProvisioningLoader.setProvisioningStatus(subId, FEATURE_RCS,
1614 capability, tech, isProvisioned);
1615
1616 if (isChanged) {
1617 int slotId = getSlotId(subId);
1618
1619 // notify RCS capability changed
1620 mHandler.sendMessage(mHandler.obtainMessage(EVENT_PROVISIONING_CAPABILITY_CHANGED,
1621 slotId, 0, (Object) new FeatureProvisioningData(
1622 capability, tech, isProvisioned, /*isMmtel*/false)));
1623 }
1624
1625 return isChanged;
1626 }
1627
1628 private boolean setAndNotifyRcsProvisioningValueForAllTech(int subId, int capability,
1629 boolean isProvisioned) {
1630 boolean isChanged = false;
1631
1632 for (int tech : LOCAL_RADIO_TECHS) {
1633 isChanged |= setAndNotifyRcsProvisioningValue(subId, capability, tech, isProvisioned);
1634 }
1635
1636 return isChanged;
1637 }
1638
joonhunshin2c3e4232021-11-28 07:32:01 +00001639 protected boolean isValidSubId(int subId) {
1640 int slotId = getSlotId(subId);
1641 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
1642 return false;
1643 }
1644
1645 return true;
1646 }
1647
1648 private void log(String s) {
1649 Rlog.d(TAG, s);
1650 }
1651
1652 private void log(String prefix, int slotId, String s) {
1653 Rlog.d(TAG, prefix + "[" + slotId + "] " + s);
1654 }
1655
1656 private void logi(String prefix, int slotId, String s) {
1657 Rlog.i(TAG, prefix + "[" + slotId + "] " + s);
1658 }
1659
1660 private void logw(String s) {
1661 Rlog.w(TAG, s);
1662 }
1663
1664 private void logw(String prefix, int slotId, String s) {
1665 Rlog.w(TAG, prefix + "[" + slotId + "] " + s);
1666 }
1667
1668 private void loge(String s) {
1669 Rlog.e(TAG, s);
1670 }
1671
1672 private void loge(String prefix, int slotId, String s) {
1673 Rlog.e(TAG, prefix + "[" + slotId + "] " + s);
1674 }
1675}