blob: d2c720b40e2110506692e57ab7d9f96f0405dc70 [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;
joonhunshin711a8872024-03-19 10:04:08 +000073import com.android.internal.telephony.flags.FeatureFlags;
joonhunshin2c3e4232021-11-28 07:32:01 +000074import com.android.internal.telephony.util.HandlerExecutor;
75import com.android.telephony.Rlog;
76
77import java.util.Arrays;
joonhunshinf9411cb2022-01-17 07:37:15 +000078import java.util.Map;
joonhunshin2c3e4232021-11-28 07:32:01 +000079import java.util.concurrent.Executor;
80
81/**
82 * Provides APIs for MMTEL and RCS provisioning status. This class handles provisioning status and
83 * notifies the status changing for each capability
84 * {{@link MmTelCapabilities.MmTelCapability} for MMTel services}
85 * {{@link RcsImsCapabilities.RcsImsCapabilityFlag} for RCS services}
86 */
87public class ImsProvisioningController {
88 private static final String TAG = "ImsProvisioningController";
89 private static final int INVALID_VALUE = -1;
90
91 private static final int EVENT_SUB_CHANGED = 1;
92 private static final int EVENT_PROVISIONING_CAPABILITY_CHANGED = 2;
joonhunshin39710022022-01-14 11:53:58 +000093 @VisibleForTesting
94 protected static final int EVENT_MULTI_SIM_CONFIGURATION_CHANGE = 3;
joonhunshin1724dd62022-08-30 07:41:20 +000095 private static final int EVENT_PROVISIONING_VALUE_CHANGED = 4;
joonhunshin711a8872024-03-19 10:04:08 +000096 private static final int EVENT_NOTIFY_INIT_PROVISIONED_VALUE = 5;
joonhunshin2c3e4232021-11-28 07:32:01 +000097
98 // Provisioning Keys that are handled via AOSP cache and not sent to the ImsService
99 private static final int[] LOCAL_IMS_CONFIG_KEYS = {
100 KEY_VOLTE_PROVISIONING_STATUS,
101 KEY_VT_PROVISIONING_STATUS,
102 KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE,
103 KEY_EAB_PROVISIONING_STATUS
104 };
105 private static final int[] LOCAL_RADIO_TECHS = {
106 REGISTRATION_TECH_LTE,
107 REGISTRATION_TECH_IWLAN,
108 REGISTRATION_TECH_CROSS_SIM,
109 REGISTRATION_TECH_NR
110 };
111
112 private static final int MMTEL_CAPABILITY_MIN = MmTelCapabilities.CAPABILITY_TYPE_NONE;
113 private static final int MMTEL_CAPABILITY_MAX = MmTelCapabilities.CAPABILITY_TYPE_MAX;
114
115 private static final int RCS_CAPABILITY_MIN = RcsImsCapabilities.CAPABILITY_TYPE_NONE;
116 private static final int RCS_CAPABILITY_MAX = RcsImsCapabilities.CAPABILITY_TYPE_MAX;
117
118 private static final int[] LOCAL_MMTEL_CAPABILITY = {
119 CAPABILITY_TYPE_VOICE,
120 CAPABILITY_TYPE_VIDEO,
121 CAPABILITY_TYPE_UT,
122 CAPABILITY_TYPE_SMS,
123 CAPABILITY_TYPE_CALL_COMPOSER
124 };
125
joonhunshin711a8872024-03-19 10:04:08 +0000126 private static final int[] LOCAL_RCS_CAPABILITY = {
127 CAPABILITY_TYPE_OPTIONS_UCE,
128 CAPABILITY_TYPE_PRESENCE_UCE
129 };
130
joonhunshin2c3e4232021-11-28 07:32:01 +0000131 /**
joonhunshinf9411cb2022-01-17 07:37:15 +0000132 * map the MmTelCapabilities.MmTelCapability and
133 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_VOICE_INT
134 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_VIDEO_INT
135 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_UT_INT
136 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_SMS_INT
joonhunshin6cd38ac2022-02-03 06:37:55 +0000137 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT
joonhunshinf9411cb2022-01-17 07:37:15 +0000138 */
139 private static final Map<Integer, String> KEYS_MMTEL_CAPABILITY = Map.of(
140 CAPABILITY_TYPE_VOICE, Ims.KEY_CAPABILITY_TYPE_VOICE_INT_ARRAY,
141 CAPABILITY_TYPE_VIDEO, Ims.KEY_CAPABILITY_TYPE_VIDEO_INT_ARRAY,
142 CAPABILITY_TYPE_UT, Ims.KEY_CAPABILITY_TYPE_UT_INT_ARRAY,
143 CAPABILITY_TYPE_SMS, Ims.KEY_CAPABILITY_TYPE_SMS_INT_ARRAY,
joonhunshin6cd38ac2022-02-03 06:37:55 +0000144 CAPABILITY_TYPE_CALL_COMPOSER, Ims.KEY_CAPABILITY_TYPE_CALL_COMPOSER_INT_ARRAY
joonhunshinf9411cb2022-01-17 07:37:15 +0000145 );
146
147 /**
148 * map the RcsImsCapabilities.RcsImsCapabilityFlag and
149 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_OPTIONS_UCE
150 * CarrierConfigManager.Ims.KEY_CAPABILITY_TYPE_PRESENCE_UCE
151 */
152 private static final Map<Integer, String> KEYS_RCS_CAPABILITY = Map.of(
153 CAPABILITY_TYPE_OPTIONS_UCE, Ims.KEY_CAPABILITY_TYPE_OPTIONS_UCE_INT_ARRAY,
154 CAPABILITY_TYPE_PRESENCE_UCE, Ims.KEY_CAPABILITY_TYPE_PRESENCE_UCE_INT_ARRAY
155 );
156
157 /**
joonhunshin2c3e4232021-11-28 07:32:01 +0000158 * Create a FeatureConnector for this class to use to connect to an ImsManager.
159 */
160 @VisibleForTesting
161 public interface MmTelFeatureConnector {
162 /**
163 * Create a FeatureConnector for this class to use to connect to an ImsManager.
164 * @param listener will receive ImsManager instance.
165 * @param executor that the Listener callbacks will be called on.
166 * @return A FeatureConnector
167 */
168 FeatureConnector<ImsManager> create(Context context, int slotId,
169 String logPrefix, FeatureConnector.Listener<ImsManager> listener,
170 Executor executor);
171 }
172
173 /**
174 * Create a FeatureConnector for this class to use to connect to an RcsFeatureManager.
175 */
176 @VisibleForTesting
177 public interface RcsFeatureConnector {
178 /**
179 * Create a FeatureConnector for this class to use to connect to an RcsFeatureManager.
180 * @param listener will receive RcsFeatureManager instance.
181 * @param executor that the Listener callbacks will be called on.
182 * @return A FeatureConnector
183 */
184 FeatureConnector<RcsFeatureManager> create(Context context, int slotId,
185 FeatureConnector.Listener<RcsFeatureManager> listener,
186 Executor executor, String logPrefix);
187 }
188
189 private static ImsProvisioningController sInstance;
190
191 private final PhoneGlobals mApp;
192 private final Handler mHandler;
193 private final CarrierConfigManager mCarrierConfigManager;
194 private final SubscriptionManager mSubscriptionManager;
195 private final TelephonyRegistryManager mTelephonyRegistryManager;
196 private final MmTelFeatureConnector mMmTelFeatureConnector;
197 private final RcsFeatureConnector mRcsFeatureConnector;
198
199 // maps a slotId to a list of MmTelFeatureListeners
200 private final SparseArray<MmTelFeatureListener> mMmTelFeatureListenersSlotMap =
201 new SparseArray<>();
202 // maps a slotId to a list of RcsFeatureListeners
203 private final SparseArray<RcsFeatureListener> mRcsFeatureListenersSlotMap =
204 new SparseArray<>();
205 // map a slotId to a list of ProvisioningCallbackManager
206 private final SparseArray<ProvisioningCallbackManager> mProvisioningCallbackManagersSlotMap =
207 new SparseArray<>();
208 private final ImsProvisioningLoader mImsProvisioningLoader;
joonhunshin711a8872024-03-19 10:04:08 +0000209 private final FeatureFlags mFeatureFlags;
joonhunshin2c3e4232021-11-28 07:32:01 +0000210
211 private int mNumSlot;
212
213 /**
214 * This class contains the provisioning status to notify changes.
215 * {{@link MmTelCapabilities.MmTelCapability} for MMTel services}
Hakjun Choi4c6c10e2022-03-15 05:08:02 +0000216 * {{@link android.telephony.ims.ImsRcsManager.RcsImsCapabilityFlag} for RCS services}
joonhunshin2c3e4232021-11-28 07:32:01 +0000217 * {{@link ImsRegistrationImplBase.ImsRegistrationTech} for Registration tech}
218 */
219 private static final class FeatureProvisioningData {
220 public final int mCapability;
221 public final int mTech;
222 public final boolean mProvisioned;
223 public final boolean mIsMmTel;
224
225 FeatureProvisioningData(int capability, int tech, boolean provisioned, boolean isMmTel) {
226 mCapability = capability;
227 mTech = tech;
228 mProvisioned = provisioned;
229 mIsMmTel = isMmTel;
230 }
231 }
232
233 private final class MessageHandler extends Handler {
234 private static final String LOG_PREFIX = "Handler";
235 MessageHandler(Looper looper) {
236 super(looper);
237 }
238
239 @Override
240 public void handleMessage(Message msg) {
241 switch (msg.what) {
242 case EVENT_SUB_CHANGED:
243 onSubscriptionsChanged();
244 break;
245 case EVENT_PROVISIONING_CAPABILITY_CHANGED:
246 try {
247 mProvisioningCallbackManagersSlotMap.get(msg.arg1)
248 .notifyProvisioningCapabilityChanged(
249 (FeatureProvisioningData) msg.obj);
250 } catch (NullPointerException e) {
251 logw(LOG_PREFIX, msg.arg1,
252 "can not find callback manager message" + msg.what);
253 }
254 break;
joonhunshin39710022022-01-14 11:53:58 +0000255 case EVENT_MULTI_SIM_CONFIGURATION_CHANGE:
256 int activeModemCount = (int) ((AsyncResult) msg.obj).result;
257 onMultiSimConfigChanged(activeModemCount);
258 break;
joonhunshin1724dd62022-08-30 07:41:20 +0000259 case EVENT_PROVISIONING_VALUE_CHANGED:
260 log("subId " + msg.arg1 + " changed provisioning value item : " + msg.arg2
261 + " value : " + (int) msg.obj);
262 updateCapabilityTechFromKey(msg.arg1, msg.arg2, (int) msg.obj);
263 break;
joonhunshin711a8872024-03-19 10:04:08 +0000264 case EVENT_NOTIFY_INIT_PROVISIONED_VALUE:
265 int slotId = msg.arg1;
266 int subId = msg.arg2;
267 IFeatureProvisioningCallback callback =
268 (IFeatureProvisioningCallback) msg.obj;
269 log("slotId " + slotId + " subId " + subId
270 + " callback " + (callback != null));
271
272 // Notify MmTel Provisioning Status
273 notifyMmTelProvisioningStatus(slotId, subId, callback);
274 notifyRcsProvisioningStatus(slotId, subId, callback);
275 break;
joonhunshin2c3e4232021-11-28 07:32:01 +0000276 default:
277 log("unknown message " + msg);
278 break;
279 }
280 }
281 }
282
283 private final SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener =
284 new SubscriptionManager.OnSubscriptionsChangedListener() {
285 @Override
286 public void onSubscriptionsChanged() {
287 if (!mHandler.hasMessages(EVENT_SUB_CHANGED)) {
288 mHandler.sendEmptyMessage(EVENT_SUB_CHANGED);
289 }
290 }
291 };
292
293 private final class ProvisioningCallbackManager {
294 private static final String LOG_PREFIX = "ProvisioningCallbackManager";
295 private RemoteCallbackList<IFeatureProvisioningCallback> mIFeatureProvisioningCallbackList;
296 private int mSubId;
297 private int mSlotId;
298
299 ProvisioningCallbackManager(int slotId) {
300 mIFeatureProvisioningCallbackList =
301 new RemoteCallbackList<IFeatureProvisioningCallback>();
302 mSlotId = slotId;
303 mSubId = getSubId(slotId);
304 log(LOG_PREFIX, mSlotId, "ProvisioningCallbackManager create");
305 }
306
307 public void clear() {
308 log(LOG_PREFIX, mSlotId, "ProvisioningCallbackManager clear ");
309
310 mIFeatureProvisioningCallbackList.kill();
311
312 // All registered callbacks are unregistered, and the list is disabled
313 // need to create again
314 mIFeatureProvisioningCallbackList =
315 new RemoteCallbackList<IFeatureProvisioningCallback>();
316 }
317
318 public void registerCallback(IFeatureProvisioningCallback localCallback) {
319 if (!mIFeatureProvisioningCallbackList.register(localCallback, (Object) mSubId)) {
320 log(LOG_PREFIX, mSlotId, "registration callback fail");
321 }
322 }
323
324 public void unregisterCallback(IFeatureProvisioningCallback localCallback) {
325 mIFeatureProvisioningCallbackList.unregister(localCallback);
326 }
327
328 public void setSubId(int subId) {
329 if (mSubId == subId) {
330 log(LOG_PREFIX, mSlotId, "subId is not changed ");
331 return;
332 }
333
334 mSubId = subId;
335 mSlotId = getSlotId(subId);
336
337 // subId changed means the registered callbacks are not available.
338 clear();
339 }
340
341 public boolean hasCallblacks() {
342 int size = mIFeatureProvisioningCallbackList.beginBroadcast();
343 mIFeatureProvisioningCallbackList.finishBroadcast();
344
345 return (size > 0);
346 }
347
348 public void notifyProvisioningCapabilityChanged(FeatureProvisioningData data) {
349 int size = mIFeatureProvisioningCallbackList.beginBroadcast();
350 for (int index = 0; index < size; index++) {
351 try {
352 IFeatureProvisioningCallback imsFeatureProvisioningCallback =
353 mIFeatureProvisioningCallbackList.getBroadcastItem(index);
354
355 // MMTEL
356 if (data.mIsMmTel
357 && Arrays.stream(LOCAL_MMTEL_CAPABILITY)
358 .anyMatch(value -> value == data.mCapability)) {
359 imsFeatureProvisioningCallback.onFeatureProvisioningChanged(
360 data.mCapability, data.mTech, data.mProvisioned);
361 logi(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : "
362 + "onFeatureProvisioningChanged"
363 + " capability " + data.mCapability
364 + " tech " + data.mTech
365 + " isProvisioned " + data.mProvisioned);
366 } else if (data.mCapability == CAPABILITY_TYPE_PRESENCE_UCE) {
367 imsFeatureProvisioningCallback.onRcsFeatureProvisioningChanged(
368 data.mCapability, data.mTech, data.mProvisioned);
369 logi(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : "
370 + "onRcsFeatureProvisioningChanged"
371 + " capability " + data.mCapability
372 + " tech " + data.mTech
373 + " isProvisioned " + data.mProvisioned);
374 } else {
375 loge(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : "
376 + "unknown capability "
377 + data.mCapability);
378 }
379 } catch (RemoteException e) {
380 loge(LOG_PREFIX, mSlotId,
381 "notifyProvisioningChanged: callback #" + index + " failed");
382 }
383 }
384 mIFeatureProvisioningCallbackList.finishBroadcast();
385 }
386 }
387
388 private final class MmTelFeatureListener implements FeatureConnector.Listener<ImsManager> {
389 private static final String LOG_PREFIX = "MmTelFeatureListener";
390 private FeatureConnector<ImsManager> mConnector;
391 private ImsManager mImsManager;
392 private boolean mReady = false;
393 // stores whether the initial provisioning key value should be notified to ImsService
394 private boolean mRequiredNotify = false;
395 private int mSubId;
396 private int mSlotId;
joonhunshin1724dd62022-08-30 07:41:20 +0000397 private ConfigCallback mConfigCallback;
joonhunshin2c3e4232021-11-28 07:32:01 +0000398
399 MmTelFeatureListener(int slotId) {
400 log(LOG_PREFIX, slotId, "created");
401
402 mSlotId = slotId;
403 mSubId = getSubId(slotId);
joonhunshin1724dd62022-08-30 07:41:20 +0000404 mConfigCallback = new ConfigCallback(mSubId);
405
joonhunshin2c3e4232021-11-28 07:32:01 +0000406 mConnector = mMmTelFeatureConnector.create(
407 mApp, slotId, TAG, this, new HandlerExecutor(mHandler));
408 mConnector.connect();
409 }
410
411 public void setSubId(int subId) {
412 if (mRequiredNotify && mReady) {
413 mRequiredNotify = false;
414 setInitialProvisioningKeys(subId);
415 }
416 if (mSubId == subId) {
417 log(LOG_PREFIX, mSlotId, "subId is not changed");
418 return;
419 }
420
421 mSubId = subId;
422 mSlotId = getSlotId(subId);
joonhunshin1724dd62022-08-30 07:41:20 +0000423 mConfigCallback.setSubId(subId);
joonhunshin2c3e4232021-11-28 07:32:01 +0000424 }
425
426 public void destroy() {
427 log("destroy");
joonhunshin1724dd62022-08-30 07:41:20 +0000428 if (mImsManager != null) {
429 try {
430 ImsConfig imsConfig = getImsConfig(mImsManager);
431 if (imsConfig != null) {
432 imsConfig.removeConfigCallback(mConfigCallback);
433 }
434 } catch (ImsException e) {
435 logw(LOG_PREFIX, mSlotId, "destroy : " + e.getMessage());
436 }
437 }
438 mConfigCallback = null;
joonhunshin2c3e4232021-11-28 07:32:01 +0000439 mConnector.disconnect();
440 mConnector = null;
441 mReady = false;
442 mImsManager = null;
443 }
444
445 public @Nullable ImsManager getImsManager() {
446 return mImsManager;
447 }
448
449 @Override
450 public void connectionReady(ImsManager manager, int subId) {
451 log(LOG_PREFIX, mSlotId, "connection ready");
452 mReady = true;
453 mImsManager = manager;
454
joonhunshin1724dd62022-08-30 07:41:20 +0000455 if (mImsManager != null) {
456 try {
457 ImsConfig imsConfig = getImsConfig(mImsManager);
458 if (imsConfig != null) {
459 imsConfig.addConfigCallback(mConfigCallback);
460 }
461 } catch (ImsException e) {
462 logw(LOG_PREFIX, mSlotId, "addConfigCallback : " + e.getMessage());
463 }
464 }
465
joonhunshin2c3e4232021-11-28 07:32:01 +0000466 onMmTelAvailable();
467 }
468
469 @Override
470 public void connectionUnavailable(int reason) {
471 log(LOG_PREFIX, mSlotId, "connection unavailable " + reason);
472
473 mReady = false;
474 mImsManager = null;
475
476 // keep the callback for other reason
477 if (reason == FeatureConnector.UNAVAILABLE_REASON_IMS_UNSUPPORTED) {
478 onMmTelUnavailable();
479 }
480 }
481
482 public int setProvisioningValue(int key, int value) {
483 int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED;
484
485 if (!mReady) {
486 loge(LOG_PREFIX, mSlotId, "service is Unavailable");
487 return retVal;
488 }
489 try {
490 // getConfigInterface() will return not null or throw the ImsException
491 // need not null checking
492 ImsConfig imsConfig = getImsConfig(mImsManager);
493 retVal = imsConfig.setConfig(key, value);
494 log(LOG_PREFIX, mSlotId, "setConfig called with key " + key + " value " + value);
495 } catch (ImsException e) {
496 logw(LOG_PREFIX, mSlotId,
497 "setConfig operation failed for key =" + key
498 + ", value =" + value + ". Exception:" + e.getMessage());
499 }
500 return retVal;
501 }
502
503 public int getProvisioningValue(int key) {
504 if (!mReady) {
505 loge(LOG_PREFIX, mSlotId, "service is Unavailable");
506 return INVALID_VALUE;
507 }
508
509 int retValue = INVALID_VALUE;
510 try {
511 // getConfigInterface() will return not null or throw the ImsException
512 // need not null checking
513 ImsConfig imsConfig = getImsConfig(mImsManager);
514 retValue = imsConfig.getConfigInt(key);
515 } catch (ImsException e) {
516 logw(LOG_PREFIX, mSlotId,
517 "getConfig operation failed for key =" + key
518 + ", value =" + retValue + ". Exception:" + e.getMessage());
519 }
520 return retValue;
521 }
522
523 public void onMmTelAvailable() {
524 log(LOG_PREFIX, mSlotId, "onMmTelAvailable");
525
526 if (isValidSubId(mSubId)) {
527 mRequiredNotify = false;
528
529 // notify provisioning key value to ImsService
530 setInitialProvisioningKeys(mSubId);
joonhunshin711a8872024-03-19 10:04:08 +0000531
532 if (mFeatureFlags.notifyInitialImsProvisioningStatus()) {
533 // Notify MmTel provisioning value based on capability and radio tech.
534 if (mProvisioningCallbackManagersSlotMap.get(mSlotId).hasCallblacks()) {
535 notifyMmTelProvisioningStatus(mSlotId, mSubId, null);
536 }
537 }
joonhunshin2c3e4232021-11-28 07:32:01 +0000538 } else {
539 // wait until subId is valid
540 mRequiredNotify = true;
541 }
542 }
543
544 public void onMmTelUnavailable() {
545 log(LOG_PREFIX, mSlotId, "onMmTelUnavailable");
546
547 try {
548 // delete all callbacks reference from ProvisioningManager
549 mProvisioningCallbackManagersSlotMap.get(getSlotId(mSubId)).clear();
550 } catch (NullPointerException e) {
551 logw(LOG_PREFIX, getSlotId(mSubId), "can not find callback manager to clear");
552 }
553 }
554
555 private void setInitialProvisioningKeys(int subId) {
556 boolean required;
557 int value = ImsProvisioningLoader.STATUS_NOT_SET;
558
559 // updating KEY_VOLTE_PROVISIONING_STATUS
joonhunshinad228dc2022-05-20 05:54:26 +0000560 try {
561 required = isImsProvisioningRequiredForCapability(subId, CAPABILITY_TYPE_VOICE,
562 REGISTRATION_TECH_LTE);
563 } catch (IllegalArgumentException e) {
564 logw("setInitialProvisioningKeys: KEY_VOLTE_PROVISIONING_STATUS failed for"
565 + " subId=" + subId + ", exception: " + e.getMessage());
566 return;
567 }
568
joonhunshin2c3e4232021-11-28 07:32:01 +0000569 log(LOG_PREFIX, mSlotId,
570 "setInitialProvisioningKeys provisioning required(voice, lte) " + required);
571 if (required) {
572 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
573 CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE);
574 if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
575 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
576 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
577 setProvisioningValue(KEY_VOLTE_PROVISIONING_STATUS, value);
578 }
579 }
580
581 // updating KEY_VT_PROVISIONING_STATUS
joonhunshinad228dc2022-05-20 05:54:26 +0000582 try {
583 required = isImsProvisioningRequiredForCapability(subId, CAPABILITY_TYPE_VIDEO,
584 REGISTRATION_TECH_LTE);
585 } catch (IllegalArgumentException e) {
586 logw("setInitialProvisioningKeys: KEY_VT_PROVISIONING_STATUS failed for"
587 + " subId=" + subId + ", exception: " + e.getMessage());
588 return;
589 }
590
joonhunshin2c3e4232021-11-28 07:32:01 +0000591 log(LOG_PREFIX, mSlotId,
592 "setInitialProvisioningKeys provisioning required(video, lte) " + required);
593 if (required) {
594 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
595 CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_LTE);
596 if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
597 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
598 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
599 setProvisioningValue(KEY_VT_PROVISIONING_STATUS, value);
600 }
601 }
602
603 // updating KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE
joonhunshinad228dc2022-05-20 05:54:26 +0000604 try {
605 required = isImsProvisioningRequiredForCapability(subId, CAPABILITY_TYPE_VOICE,
606 REGISTRATION_TECH_IWLAN);
607 } catch (IllegalArgumentException e) {
608 logw("setInitialProvisioningKeys: KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE failed"
609 + " for subId=" + subId + ", exception: " + e.getMessage());
610 return;
611 }
612
joonhunshin2c3e4232021-11-28 07:32:01 +0000613 log(LOG_PREFIX, mSlotId,
614 "setInitialProvisioningKeys provisioning required(voice, iwlan) " + required);
615 if (required) {
616 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
617 CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_IWLAN);
618 if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
619 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
620 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
621 setProvisioningValue(KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE, value);
622 }
623 }
624 }
625 }
626
627 private final class RcsFeatureListener implements FeatureConnector.Listener<RcsFeatureManager> {
628 private static final String LOG_PREFIX = "RcsFeatureListener";
629 private FeatureConnector<RcsFeatureManager> mConnector;
630 private RcsFeatureManager mRcsFeatureManager;
631 private boolean mReady = false;
632 // stores whether the initial provisioning key value should be notified to ImsService
633 private boolean mRequiredNotify = false;
634 private int mSubId;
635 private int mSlotId;
joonhunshin1724dd62022-08-30 07:41:20 +0000636 private ConfigCallback mConfigCallback;
joonhunshin2c3e4232021-11-28 07:32:01 +0000637
638 RcsFeatureListener(int slotId) {
639 log(LOG_PREFIX, slotId, "created");
640
641 mSlotId = slotId;
642 mSubId = getSubId(slotId);
joonhunshin1724dd62022-08-30 07:41:20 +0000643 mConfigCallback = new ConfigCallback(mSubId);
644
joonhunshin2c3e4232021-11-28 07:32:01 +0000645 mConnector = mRcsFeatureConnector.create(
646 mApp, slotId, this, new HandlerExecutor(mHandler), TAG);
647 mConnector.connect();
648 }
649
650 public void setSubId(int subId) {
651 if (mRequiredNotify && mReady) {
652 mRequiredNotify = false;
653 setInitialProvisioningKeys(subId);
654 }
655 if (mSubId == subId) {
656 log(LOG_PREFIX, mSlotId, "subId is not changed");
657 return;
658 }
659
660 mSubId = subId;
661 mSlotId = getSlotId(subId);
joonhunshin1724dd62022-08-30 07:41:20 +0000662 mConfigCallback.setSubId(subId);
joonhunshin2c3e4232021-11-28 07:32:01 +0000663 }
664
665 public void destroy() {
666 log(LOG_PREFIX, mSlotId, "destroy");
joonhunshin1724dd62022-08-30 07:41:20 +0000667 if (mRcsFeatureManager != null) {
668 try {
669 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig());
670 if (imsConfig != null) {
671 imsConfig.removeConfigCallback(mConfigCallback);
672 }
673 } catch (ImsException e) {
674 logw(LOG_PREFIX, mSlotId, "destroy :" + e.getMessage());
675 }
676 }
677 mConfigCallback = null;
joonhunshin2c3e4232021-11-28 07:32:01 +0000678 mConnector.disconnect();
679 mConnector = null;
680 mReady = false;
681 mRcsFeatureManager = null;
682 }
683
684 @Override
685 public void connectionReady(RcsFeatureManager manager, int subId) {
686 log(LOG_PREFIX, mSlotId, "connection ready");
687 mReady = true;
688 mRcsFeatureManager = manager;
689
joonhunshin1724dd62022-08-30 07:41:20 +0000690 if (mRcsFeatureManager != null) {
691 try {
692 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig());
693 if (imsConfig != null) {
694 imsConfig.addConfigCallback(mConfigCallback);
695 }
696 } catch (ImsException e) {
697 logw(LOG_PREFIX, mSlotId, "addConfigCallback :" + e.getMessage());
698 }
699 }
700
joonhunshin2c3e4232021-11-28 07:32:01 +0000701 onRcsAvailable();
702 }
703
704 @Override
705 public void connectionUnavailable(int reason) {
706 log(LOG_PREFIX, mSlotId, "connection unavailable");
707 mReady = false;
708 mRcsFeatureManager = null;
709
710 // keep the callback for other reason
711 if (reason == FeatureConnector.UNAVAILABLE_REASON_IMS_UNSUPPORTED) {
712 onRcsUnavailable();
713 }
714 }
715
716 public int setProvisioningValue(int key, int value) {
717 int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED;
718
719 if (!mReady) {
720 loge(LOG_PREFIX, mSlotId, "service is Unavailable");
721 return retVal;
722 }
723
724 try {
725 // getConfigInterface() will return not null or throw the ImsException
726 // need not null checking
727 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig());
728 retVal = imsConfig.setConfig(key, value);
729 log(LOG_PREFIX, mSlotId, "setConfig called with key " + key + " value " + value);
730 } catch (ImsException e) {
731 logw(LOG_PREFIX, mSlotId,
732 "setConfig operation failed for key =" + key
733 + ", value =" + value + ". Exception:" + e.getMessage());
734 }
735 return retVal;
736 }
737
738 public int getProvisioningValue(int key) {
739 if (!mReady) {
740 loge(LOG_PREFIX, mSlotId, "service is Unavailable");
741 return INVALID_VALUE;
742 }
743
744 int retValue = INVALID_VALUE;
745 try {
746 // getConfigInterface() will return not null or throw the ImsException
747 // need not null checking
748 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig());
749 retValue = imsConfig.getConfigInt(key);
750 } catch (ImsException e) {
751 logw(LOG_PREFIX, mSlotId,
752 "getConfig operation failed for key =" + key
753 + ", value =" + retValue + ". Exception:" + e.getMessage());
754 }
755 return retValue;
756 }
757
joonhunshin35d754f2022-06-24 03:29:15 +0000758 public boolean isConnectionReady() {
759 return mReady;
760 }
761
joonhunshin2c3e4232021-11-28 07:32:01 +0000762 public void onRcsAvailable() {
763 log(LOG_PREFIX, mSlotId, "onRcsAvailable");
764
765 if (isValidSubId(mSubId)) {
766 mRequiredNotify = false;
767
768 // notify provisioning key value to ImsService
769 setInitialProvisioningKeys(mSubId);
joonhunshin711a8872024-03-19 10:04:08 +0000770
771 if (mFeatureFlags.notifyInitialImsProvisioningStatus()) {
772 if (mProvisioningCallbackManagersSlotMap.get(mSlotId).hasCallblacks()) {
773 // Notify RCS provisioning value based on capability and radio tech.
774 notifyRcsProvisioningStatus(mSlotId, mSubId, null);
775 }
776 }
joonhunshin2c3e4232021-11-28 07:32:01 +0000777 } else {
778 // wait until subId is valid
779 mRequiredNotify = true;
780 }
781 }
782
783 public void onRcsUnavailable() {
784 log(LOG_PREFIX, mSlotId, "onRcsUnavailable");
785
786 try {
787 // delete all callbacks reference from ProvisioningManager
788 mProvisioningCallbackManagersSlotMap.get(getSlotId(mSubId)).clear();
789 } catch (NullPointerException e) {
790 logw(LOG_PREFIX, getSlotId(mSubId), "can not find callback manager to clear");
791 }
792 }
793
794 private void setInitialProvisioningKeys(int subId) {
795 boolean required;
796 int value = ImsProvisioningLoader.STATUS_NOT_SET;
797
798 // KEY_EAB_PROVISIONING_STATUS
799 int capability = CAPABILITY_TYPE_PRESENCE_UCE;
800 // Assume that all radio techs have the same provisioning value
801 int tech = REGISTRATION_TECH_LTE;
802
joonhunshinad228dc2022-05-20 05:54:26 +0000803 try {
804 required = isRcsProvisioningRequiredForCapability(subId, capability, tech);
805 } catch (IllegalArgumentException e) {
806 logw("setInitialProvisioningKeys: KEY_EAB_PROVISIONING_STATUS failed for"
807 + " subId=" + subId + ", exception: " + e.getMessage());
808 return;
809 }
810
joonhunshin2c3e4232021-11-28 07:32:01 +0000811 if (required) {
812 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
813 capability, tech);
814 if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
815 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
816 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
817 setProvisioningValue(KEY_EAB_PROVISIONING_STATUS, value);
818 }
819 }
820 }
821 }
822
joonhunshin1724dd62022-08-30 07:41:20 +0000823 // When vendor ImsService changed provisioning data, which should be updated in AOSP.
824 // Catch the event using IImsConfigCallback.
825 private final class ConfigCallback extends IImsConfigCallback.Stub {
826 private int mSubId;
827
828 ConfigCallback(int subId) {
829 mSubId = subId;
830 }
831
832 public void setSubId(int subId) {
833 mSubId = subId;
834 }
835
836 @Override
837 public void onIntConfigChanged(int item, int value) throws RemoteException {
838 if (!Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(keyValue -> keyValue == item)) {
839 return;
840 }
841
842 final long callingIdentity = Binder.clearCallingIdentity();
843 try {
844 if (mHandler != null) {
845 mHandler.sendMessage(mHandler.obtainMessage(
846 EVENT_PROVISIONING_VALUE_CHANGED, mSubId, item, (Object) value));
847 }
848 } finally {
849 Binder.restoreCallingIdentity(callingIdentity);
850 }
851 }
852
853 @Override
854 public void onStringConfigChanged(int item, String value) throws RemoteException {
855 // Ignore this callback.
856 }
857 }
858
joonhunshin2c3e4232021-11-28 07:32:01 +0000859 /**
860 * Do NOT use this directly, instead use {@link #getInstance()}.
861 */
862 @VisibleForTesting
863 public ImsProvisioningController(PhoneGlobals app, int numSlot, Looper looper,
864 MmTelFeatureConnector mmTelFeatureConnector, RcsFeatureConnector rcsFeatureConnector,
joonhunshin711a8872024-03-19 10:04:08 +0000865 ImsProvisioningLoader imsProvisioningLoader, FeatureFlags featureFlags) {
joonhunshin2c3e4232021-11-28 07:32:01 +0000866 log("ImsProvisioningController");
867 mApp = app;
868 mNumSlot = numSlot;
869 mHandler = new MessageHandler(looper);
870 mMmTelFeatureConnector = mmTelFeatureConnector;
871 mRcsFeatureConnector = rcsFeatureConnector;
872 mCarrierConfigManager = mApp.getSystemService(CarrierConfigManager.class);
873 mSubscriptionManager = mApp.getSystemService(SubscriptionManager.class);
874 mTelephonyRegistryManager = mApp.getSystemService(TelephonyRegistryManager.class);
875 mTelephonyRegistryManager.addOnSubscriptionsChangedListener(
Nathan Harold4d544b62023-06-21 13:48:40 -0700876 mSubChangedListener, mHandler::post);
joonhunshin2c3e4232021-11-28 07:32:01 +0000877 mImsProvisioningLoader = imsProvisioningLoader;
joonhunshin711a8872024-03-19 10:04:08 +0000878 mFeatureFlags = featureFlags;
joonhunshin2c3e4232021-11-28 07:32:01 +0000879
joonhunshin39710022022-01-14 11:53:58 +0000880 PhoneConfigurationManager.registerForMultiSimConfigChange(mHandler,
881 EVENT_MULTI_SIM_CONFIGURATION_CHANGE, null);
882
joonhunshin2c3e4232021-11-28 07:32:01 +0000883 initialize(numSlot);
884 }
885
886 private void initialize(int numSlot) {
887 for (int i = 0; i < numSlot; i++) {
888 MmTelFeatureListener m = new MmTelFeatureListener(i);
889 mMmTelFeatureListenersSlotMap.put(i, m);
890
891 RcsFeatureListener r = new RcsFeatureListener(i);
892 mRcsFeatureListenersSlotMap.put(i, r);
893
894 ProvisioningCallbackManager p = new ProvisioningCallbackManager(i);
895 mProvisioningCallbackManagersSlotMap.put(i, p);
896 }
897 }
898
joonhunshin39710022022-01-14 11:53:58 +0000899 private void onMultiSimConfigChanged(int newNumSlot) {
900 log("onMultiSimConfigChanged: NumSlot " + mNumSlot + " newNumSlot " + newNumSlot);
901
902 if (mNumSlot < newNumSlot) {
903 for (int i = mNumSlot; i < newNumSlot; i++) {
904 MmTelFeatureListener m = new MmTelFeatureListener(i);
905 mMmTelFeatureListenersSlotMap.put(i, m);
906
907 RcsFeatureListener r = new RcsFeatureListener(i);
908 mRcsFeatureListenersSlotMap.put(i, r);
909
910 ProvisioningCallbackManager p = new ProvisioningCallbackManager(i);
911 mProvisioningCallbackManagersSlotMap.put(i, p);
912 }
913 } else if (mNumSlot > newNumSlot) {
914 for (int i = (mNumSlot - 1); i > (newNumSlot - 1); i--) {
915 MmTelFeatureListener m = mMmTelFeatureListenersSlotMap.get(i);
916 mMmTelFeatureListenersSlotMap.remove(i);
917 m.destroy();
918
919 RcsFeatureListener r = mRcsFeatureListenersSlotMap.get(i);
920 mRcsFeatureListenersSlotMap.remove(i);
921 r.destroy();
922
923 ProvisioningCallbackManager p = mProvisioningCallbackManagersSlotMap.get(i);
924 mProvisioningCallbackManagersSlotMap.remove(i);
925 p.clear();
926 }
927 }
928
929 mNumSlot = newNumSlot;
930 }
931
joonhunshin2c3e4232021-11-28 07:32:01 +0000932 /**
933 * destroy the instance
934 */
935 @VisibleForTesting
936 public void destroy() {
937 log("destroy");
938
939 mHandler.getLooper().quit();
940
941 mTelephonyRegistryManager.removeOnSubscriptionsChangedListener(mSubChangedListener);
942
943 for (int i = 0; i < mMmTelFeatureListenersSlotMap.size(); i++) {
944 mMmTelFeatureListenersSlotMap.get(i).destroy();
945 }
946 mMmTelFeatureListenersSlotMap.clear();
947
948 for (int i = 0; i < mRcsFeatureListenersSlotMap.size(); i++) {
949 mRcsFeatureListenersSlotMap.get(i).destroy();
950 }
951 mRcsFeatureListenersSlotMap.clear();
952
953 for (int i = 0; i < mProvisioningCallbackManagersSlotMap.size(); i++) {
954 mProvisioningCallbackManagersSlotMap.get(i).clear();
955 }
956 }
957
958 /**
959 * create an instance
960 */
961 @VisibleForTesting
joonhunshin711a8872024-03-19 10:04:08 +0000962 public static ImsProvisioningController make(PhoneGlobals app, int numSlot,
963 FeatureFlags featureFlags) {
joonhunshin2c3e4232021-11-28 07:32:01 +0000964 synchronized (ImsProvisioningController.class) {
965 if (sInstance == null) {
966 Rlog.i(TAG, "ImsProvisioningController created");
967 HandlerThread handlerThread = new HandlerThread(TAG);
968 handlerThread.start();
969 sInstance = new ImsProvisioningController(app, numSlot, handlerThread.getLooper(),
970 ImsManager::getConnector, RcsFeatureManager::getConnector,
joonhunshin711a8872024-03-19 10:04:08 +0000971 new ImsProvisioningLoader(app), featureFlags);
joonhunshin2c3e4232021-11-28 07:32:01 +0000972 }
973 }
974 return sInstance;
975 }
976
977 /**
978 * Gets a ImsProvisioningController instance
979 */
980 @VisibleForTesting
981 public static ImsProvisioningController getInstance() {
982 synchronized (ImsProvisioningController.class) {
983 return sInstance;
984 }
985 }
986
987 /**
988 * Register IFeatureProvisioningCallback from ProvisioningManager
989 */
990
991 @VisibleForTesting
992 public void addFeatureProvisioningChangedCallback(int subId,
993 IFeatureProvisioningCallback callback) {
994 if (callback == null) {
995 throw new IllegalArgumentException("provisioning callback can't be null");
996 }
997 int slotId = getSlotId(subId);
998 if (slotId < 0 || slotId >= mNumSlot) {
999 throw new IllegalArgumentException("subscription id is not available");
1000 }
1001
1002 try {
1003 mProvisioningCallbackManagersSlotMap.get(slotId).registerCallback(callback);
1004 log("Feature Provisioning Callback registered.");
joonhunshin711a8872024-03-19 10:04:08 +00001005
1006 if (mFeatureFlags.notifyInitialImsProvisioningStatus()) {
1007 mHandler.sendMessage(mHandler.obtainMessage(EVENT_NOTIFY_INIT_PROVISIONED_VALUE,
1008 getSlotId(subId), subId, (Object) callback));
1009 }
joonhunshin2c3e4232021-11-28 07:32:01 +00001010 } catch (NullPointerException e) {
1011 logw("can not access callback manager to add callback");
1012 }
1013 }
1014
1015 /**
1016 * Remove IFeatureProvisioningCallback
1017 */
1018 @VisibleForTesting
1019 public void removeFeatureProvisioningChangedCallback(int subId,
1020 IFeatureProvisioningCallback callback) {
1021 if (callback == null) {
1022 throw new IllegalArgumentException("provisioning callback can't be null");
1023 }
1024
1025 int slotId = getSlotId(subId);
1026 if (slotId < 0 || slotId >= mNumSlot) {
1027 throw new IllegalArgumentException("subscription id is not available");
1028 }
1029
1030 try {
1031 mProvisioningCallbackManagersSlotMap.get(slotId).unregisterCallback(callback);
1032 log("Feature Provisioning Callback removed.");
1033 } catch (NullPointerException e) {
1034 logw("can not access callback manager to remove callback");
1035 }
1036 }
1037
1038 /**
joonhunshinf9411cb2022-01-17 07:37:15 +00001039 * return the boolean whether MmTel capability is required provisioning or not
joonhunshin2c3e4232021-11-28 07:32:01 +00001040 */
1041 @VisibleForTesting
1042 public boolean isImsProvisioningRequiredForCapability(int subId, int capability, int tech) {
1043 // check subId
1044 int slotId = getSlotId(subId);
1045 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
1046 loge("Fail to retrieve slotId from subId");
1047 throw new IllegalArgumentException("subscribe id is invalid");
1048 }
1049
1050 // check valid capability
1051 if (!(MMTEL_CAPABILITY_MIN < capability && capability < MMTEL_CAPABILITY_MAX)) {
1052 throw new IllegalArgumentException("MmTel capability '" + capability + "' is invalid");
1053 }
1054
1055 // check valid radio tech
1056 if (!(REGISTRATION_TECH_NONE < tech && tech < REGISTRATION_TECH_MAX)) {
1057 log("Ims not matched radio tech " + tech);
1058 throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
1059 }
1060
joonhunshin10e74ea2022-04-29 06:29:35 +00001061 // check new carrier config first KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE
joonhunshin2c3e4232021-11-28 07:32:01 +00001062 boolean retVal = isProvisioningRequired(subId, capability, tech, /*isMmTel*/true);
1063
joonhunshin10e74ea2022-04-29 06:29:35 +00001064 // if that returns false, check deprecated carrier config
1065 // KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL
1066 if (!retVal && (capability == CAPABILITY_TYPE_VOICE
1067 || capability == CAPABILITY_TYPE_VIDEO
1068 || capability == CAPABILITY_TYPE_UT)) {
1069 String key = CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL;
1070 if (capability == CAPABILITY_TYPE_UT) {
1071 key = CarrierConfigManager.KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL;
1072 }
1073
1074 PersistableBundle imsCarrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
1075 if (imsCarrierConfigs != null) {
1076 retVal = imsCarrierConfigs.getBoolean(key);
1077 } else {
1078 retVal = CarrierConfigManager.getDefaultConfig().getBoolean(key);
1079 }
1080 }
1081
joonhunshin2c3e4232021-11-28 07:32:01 +00001082 log("isImsProvisioningRequiredForCapability capability " + capability
1083 + " tech " + tech + " return value " + retVal);
1084
1085 return retVal;
1086 }
1087
1088 /**
joonhunshinf9411cb2022-01-17 07:37:15 +00001089 * return the boolean whether RCS capability is required provisioning or not
joonhunshin2c3e4232021-11-28 07:32:01 +00001090 */
1091 @VisibleForTesting
1092 public boolean isRcsProvisioningRequiredForCapability(int subId, int capability, int tech) {
1093 // check slotId and Phone object
1094 int slotId = getSlotId(subId);
1095 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
1096 loge("Fail to retrieve slotId from subId");
1097 throw new IllegalArgumentException("subscribe id is invalid");
1098 }
1099
1100 // check valid capability
1101 if (!(RCS_CAPABILITY_MIN < capability && capability < RCS_CAPABILITY_MAX)) {
1102 throw new IllegalArgumentException("Rcs capability '" + capability + "' is invalid");
1103 }
1104
1105 // check valid radio tech
1106 if (!(REGISTRATION_TECH_NONE < tech && tech < REGISTRATION_TECH_MAX)) {
1107 log("Rcs not matched radio tech " + tech);
1108 throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
1109 }
1110
joonhunshin10e74ea2022-04-29 06:29:35 +00001111 // check new carrier config first KEY_RCS_REQUIRES_PROVISIONING_BUNDLE
joonhunshin2c3e4232021-11-28 07:32:01 +00001112 boolean retVal = isProvisioningRequired(subId, capability, tech, /*isMmTel*/false);
1113
joonhunshin10e74ea2022-04-29 06:29:35 +00001114 // if that returns false, check deprecated carrier config
1115 // KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL
1116 if (!retVal) {
1117 PersistableBundle imsCarrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
1118 if (imsCarrierConfigs != null) {
1119 retVal = imsCarrierConfigs.getBoolean(
1120 CarrierConfigManager.KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL);
1121 } else {
1122 retVal = CarrierConfigManager.getDefaultConfig().getBoolean(
1123 CarrierConfigManager.KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL);
1124 }
1125 }
1126
joonhunshin2c3e4232021-11-28 07:32:01 +00001127 log("isRcsProvisioningRequiredForCapability capability " + capability
1128 + " tech " + tech + " return value " + retVal);
1129
1130 return retVal;
1131 }
1132
1133 /**
1134 * return the provisioning status for MmTel capability in specific radio tech
1135 */
1136 @VisibleForTesting
1137 public boolean getImsProvisioningStatusForCapability(int subId, int capability, int tech) {
1138 boolean mmTelProvisioned = isImsProvisioningRequiredForCapability(subId, capability, tech);
1139 if (!mmTelProvisioned) { // provisioning not required
1140 log("getImsProvisioningStatusForCapability : not required "
1141 + " capability " + capability + " tech " + tech);
1142 return true;
1143 }
1144
1145 // read value from ImsProvisioningLoader
1146 int result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
1147 capability, tech);
1148 if (result == ImsProvisioningLoader.STATUS_NOT_SET) {
1149 // not set means initial value
1150 // read data from vendor ImsService and store that in ImsProvisioningLoader
1151 result = getValueFromImsService(subId, capability, tech);
1152 mmTelProvisioned = getBoolValue(result);
1153 if (result != ProvisioningManager.PROVISIONING_RESULT_UNKNOWN) {
1154 setAndNotifyMmTelProvisioningValue(subId, capability, tech, mmTelProvisioned);
1155 }
1156 } else {
1157 mmTelProvisioned = getBoolValue(result);
1158 }
1159
1160 log("getImsProvisioningStatusForCapability : "
1161 + " capability " + capability
1162 + " tech " + tech
1163 + " result " + mmTelProvisioned);
1164 return mmTelProvisioned;
1165 }
1166
1167 /**
1168 * set MmTel provisioning status in specific tech
1169 */
1170 @VisibleForTesting
1171 public void setImsProvisioningStatusForCapability(int subId, int capability, int tech,
1172 boolean isProvisioned) {
1173 boolean mmTelProvisioned = isImsProvisioningRequiredForCapability(subId, capability, tech);
1174 if (!mmTelProvisioned) { // provisioning not required
1175 log("setImsProvisioningStatusForCapability : not required "
1176 + " capability " + capability + " tech " + tech);
1177 return;
1178 }
1179
1180 // write value to ImsProvisioningLoader
1181 boolean isChanged = setAndNotifyMmTelProvisioningValue(subId, capability, tech,
1182 isProvisioned);
1183 if (!isChanged) {
1184 log("status not changed mmtel capability " + capability + " tech " + tech);
1185 return;
1186 }
1187
1188 int slotId = getSlotId(subId);
1189 // find matched key from capability and tech
1190 int value = getIntValue(isProvisioned);
1191 int key = getKeyFromCapability(capability, tech);
1192 if (key != INVALID_VALUE) {
1193 log("setImsProvisioningStatusForCapability : matched key " + key);
1194 try {
1195 // set key and value to vendor ImsService for MmTel
1196 mMmTelFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
joonhunshin2c3e4232021-11-28 07:32:01 +00001197 } catch (NullPointerException e) {
1198 loge("can not access MmTelFeatureListener with capability " + capability);
1199 }
1200 }
1201 }
1202
1203 /**
1204 * return the provisioning status for RCS capability in specific radio tech
1205 */
1206 @VisibleForTesting
1207 public boolean getRcsProvisioningStatusForCapability(int subId, int capability, int tech) {
1208 boolean rcsProvisioned = isRcsProvisioningRequiredForCapability(subId, capability, tech);
1209 if (!rcsProvisioned) { // provisioning not required
1210 log("getRcsProvisioningStatusForCapability : not required"
1211 + " capability " + capability + " tech " + tech);
1212 return true;
1213 }
1214
1215 // read data from ImsProvisioningLoader
1216 int result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
1217 capability, tech);
1218 if (result == ImsProvisioningLoader.STATUS_NOT_SET) {
1219 // not set means initial value
1220 // read data from vendor ImsService and store that in ImsProvisioningLoader
1221 result = getRcsValueFromImsService(subId, capability);
1222 rcsProvisioned = getBoolValue(result);
1223 if (result != ProvisioningManager.PROVISIONING_RESULT_UNKNOWN) {
1224 setAndNotifyRcsProvisioningValueForAllTech(subId, capability, rcsProvisioned);
1225 }
1226 } else {
1227 rcsProvisioned = getBoolValue(result);
1228 }
1229
1230 log("getRcsProvisioningStatusForCapability : "
1231 + " capability " + capability
1232 + " tech " + tech
1233 + " result " + rcsProvisioned);
1234 return rcsProvisioned;
1235 }
1236
1237 /**
1238 * set RCS provisioning status in specific tech
1239 */
1240 @VisibleForTesting
1241 public void setRcsProvisioningStatusForCapability(int subId, int capability, int tech,
1242 boolean isProvisioned) {
1243 boolean rcsProvisioned = isRcsProvisioningRequiredForCapability(subId, capability, tech);
1244 if (!rcsProvisioned) { // provisioning not required
1245 log("set rcs provisioning status but not required");
1246 return;
1247 }
1248
1249 // write status using ImsProvisioningLoader
1250 boolean isChanged = setAndNotifyRcsProvisioningValue(subId, capability, tech,
1251 isProvisioned);
1252 if (!isChanged) {
1253 log("status not changed rcs capability " + capability + " tech " + tech);
1254 return;
1255 }
1256
1257 int slotId = getSlotId(subId);
1258 int key = ProvisioningManager.KEY_EAB_PROVISIONING_STATUS;
1259 int value = getIntValue(isProvisioned);
1260 try {
joonhunshin35d754f2022-06-24 03:29:15 +00001261 // On some older devices, EAB is managed on the MmTel ImsService when the RCS
1262 // ImsService is not configured. If there is no RCS ImsService defined, fallback to
1263 // MmTel. In the rare case that we hit a race condition where the RCS ImsService has
1264 // crashed or has not come up yet, the value will be synchronized via
1265 // setInitialProvisioningKeys().
1266 if (mRcsFeatureListenersSlotMap.get(slotId).isConnectionReady()) {
1267 mRcsFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
1268 }
1269
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 mMmTelFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
joonhunshin2c3e4232021-11-28 07:32:01 +00001274 } catch (NullPointerException e) {
1275 loge("can not access RcsFeatureListener with capability " + capability);
1276 }
1277 }
1278
1279 /**
1280 * set RCS provisioning status in specific key and value
1281 * @param key integer key, defined as one of
1282 * {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS}
1283 * {@link ProvisioningManager#KEY_VT_PROVISIONING_STATUS}
1284 * {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE}
1285 * {@link ProvisioningManager#KEY_EAB_PROVISIONING_STATUS}
1286 * @param value in Integer format.
1287 * @return the result of setting the configuration value, defined as one of
1288 * {@link ImsConfigImplBase#CONFIG_RESULT_FAILED} or
1289 * {@link ImsConfigImplBase#CONFIG_RESULT_SUCCESS} or
1290 */
1291 @VisibleForTesting
1292 public int setProvisioningValue(int subId, int key, int value) {
1293 log("setProvisioningValue");
1294
1295 int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED;
1296 // check key value
1297 if (!Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(keyValue -> keyValue == key)) {
1298 log("not matched key " + key);
1299 return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
1300 }
1301
1302 // check subId
1303 int slotId = getSlotId(subId);
1304 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
1305 loge("Fail to retrieve slotId from subId");
1306 return ImsConfigImplBase.CONFIG_RESULT_FAILED;
1307 }
1308
1309 try {
joonhunshin35d754f2022-06-24 03:29:15 +00001310 // set key and value to vendor ImsService for MmTel
1311 // EAB provisioning status should be updated to both the Rcs and MmTel ImsService,
1312 // because the provisioning callback is listening to only MmTel provisioning key
1313 // changes.
1314 retVal = mMmTelFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
1315
1316 // If the Rcs ImsService is not available, the EAB provisioning status will be written
1317 // to the MmTel ImsService for backwards compatibility. In the rare case that this is
1318 // hit due to RCS ImsService temporarily unavailable, the value will be synchronized
1319 // via setInitialProvisioningKeys() when the RCS ImsService comes back up.
1320 if (key == KEY_EAB_PROVISIONING_STATUS
1321 && mRcsFeatureListenersSlotMap.get(slotId).isConnectionReady()) {
1322 // set key and value to vendor ImsService for RCS and use retVal from RCS if
1323 // related to EAB when possible.
1324 retVal = mRcsFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
joonhunshin2c3e4232021-11-28 07:32:01 +00001325 }
1326 } catch (NullPointerException e) {
1327 loge("can not access FeatureListener to set provisioning value");
1328 return ImsConfigImplBase.CONFIG_RESULT_FAILED;
1329 }
1330
1331 // update and notify provisioning status changed capability and tech from key
1332 updateCapabilityTechFromKey(subId, key, value);
1333
joonhunshin2c3e4232021-11-28 07:32:01 +00001334 return retVal;
1335 }
1336
1337 /**
1338 * get RCS provisioning status in specific key and value
1339 * @param key integer key, defined as one of
1340 * {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS}
1341 * {@link ProvisioningManager#KEY_VT_PROVISIONING_STATUS}
1342 * {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE}
1343 * {@link ProvisioningManager#KEY_EAB_PROVISIONING_STATUS}
1344 * @return the result of setting the configuration value, defined as one of
1345 * {@link ImsConfigImplBase#CONFIG_RESULT_FAILED} or
1346 * {@link ImsConfigImplBase#CONFIG_RESULT_SUCCESS} or
1347 * {@link ImsConfigImplBase#CONFIG_RESULT_UNKNOWN}
1348 */
1349 @VisibleForTesting
1350 public int getProvisioningValue(int subId, int key) {
joonhunshin2c3e4232021-11-28 07:32:01 +00001351 // check key value
1352 if (!Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(keyValue -> keyValue == key)) {
1353 log("not matched key " + key);
1354 return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
1355 }
1356
1357 // check subId
1358 int slotId = getSlotId(subId);
1359 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
1360 loge("Fail to retrieve slotId from subId");
1361 return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
1362 }
1363
1364 // check data from ImsProvisioningLoader
1365 int capability = getCapabilityFromKey(key);
1366 int tech = getTechFromKey(key);
1367 int result;
1368 if (capability != INVALID_VALUE && tech != INVALID_VALUE) {
1369 if (key == KEY_EAB_PROVISIONING_STATUS) {
1370 result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
1371 capability, tech);
1372 } else {
1373 result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
1374 capability, tech);
1375 }
1376 if (result != ImsProvisioningLoader.STATUS_NOT_SET) {
joonhunshin6cd38ac2022-02-03 06:37:55 +00001377 log("getProvisioningValue from loader : key " + key + " result " + result);
joonhunshin2c3e4232021-11-28 07:32:01 +00001378 return result;
1379 }
1380 }
1381
1382 // get data from ImsService, update it in ImsProvisioningLoader
1383 if (key == KEY_EAB_PROVISIONING_STATUS) {
1384 result = getRcsValueFromImsService(subId, capability);
1385 if (result == ImsConfigImplBase.CONFIG_RESULT_UNKNOWN) {
1386 logw("getProvisioningValue : fail to get data from ImsService capability"
1387 + capability);
1388 return result;
1389 }
joonhunshin6cd38ac2022-02-03 06:37:55 +00001390 log("getProvisioningValue from vendor : key " + key + " result " + result);
1391
joonhunshin2c3e4232021-11-28 07:32:01 +00001392 setAndNotifyRcsProvisioningValueForAllTech(subId, capability, getBoolValue(result));
1393 return result;
1394 } else {
1395 result = getValueFromImsService(subId, capability, tech);
1396 if (result == ImsConfigImplBase.CONFIG_RESULT_UNKNOWN) {
1397 logw("getProvisioningValue : fail to get data from ImsService capability"
1398 + capability);
1399 return result;
1400 }
joonhunshin6cd38ac2022-02-03 06:37:55 +00001401 log("getProvisioningValue from vendor : key " + key + " result " + result);
1402
joonhunshin2c3e4232021-11-28 07:32:01 +00001403 setAndNotifyMmTelProvisioningValue(subId, capability, tech, getBoolValue(result));
1404 return result;
1405 }
1406 }
1407
1408 /**
1409 * get the handler
1410 */
1411 @VisibleForTesting
1412 public Handler getHandler() {
1413 return mHandler;
1414 }
1415
1416 private boolean isProvisioningRequired(int subId, int capability, int tech, boolean isMmTel) {
joonhunshinf9411cb2022-01-17 07:37:15 +00001417 int[] techArray;
1418 techArray = getTechsFromCarrierConfig(subId, capability, isMmTel);
1419 if (techArray == null) {
1420 logw("isProvisioningRequired : getTechsFromCarrierConfig failed");
1421 // not exist in CarrierConfig that means provisioning is not required
joonhunshin2c3e4232021-11-28 07:32:01 +00001422 return false;
1423 }
1424
joonhunshin2c3e4232021-11-28 07:32:01 +00001425 // compare with carrier config
joonhunshinf9411cb2022-01-17 07:37:15 +00001426 if (Arrays.stream(techArray).anyMatch(keyValue -> keyValue == tech)) {
1427 // existing same tech means provisioning required
1428 return true;
joonhunshin2c3e4232021-11-28 07:32:01 +00001429 }
1430
1431 log("isProvisioningRequired : not matched capability " + capability + " tech " + tech);
1432 return false;
1433 }
1434
joonhunshin10e74ea2022-04-29 06:29:35 +00001435 private int[] getTechsFromCarrierConfig(int subId, int capability, boolean isMmTel) {
joonhunshinf9411cb2022-01-17 07:37:15 +00001436 String featureKey;
1437 String capabilityKey;
1438 if (isMmTel) {
1439 featureKey = CarrierConfigManager.Ims.KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE;
1440 capabilityKey = KEYS_MMTEL_CAPABILITY.get(capability);
1441 } else {
1442 featureKey = CarrierConfigManager.Ims.KEY_RCS_REQUIRES_PROVISIONING_BUNDLE;
1443 capabilityKey = KEYS_RCS_CAPABILITY.get(capability);
1444 }
joonhunshin2c3e4232021-11-28 07:32:01 +00001445
joonhunshinf9411cb2022-01-17 07:37:15 +00001446 if (capabilityKey != null) {
1447 PersistableBundle imsCarrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
1448 if (imsCarrierConfigs == null) {
1449 log("getTechsFromCarrierConfig : imsCarrierConfigs null");
1450 return null;
1451 }
1452
1453 PersistableBundle provisioningBundle =
1454 imsCarrierConfigs.getPersistableBundle(featureKey);
1455 if (provisioningBundle == null) {
1456 log("getTechsFromCarrierConfig : provisioningBundle null");
1457 return null;
1458 }
1459
1460 return provisioningBundle.getIntArray(capabilityKey);
1461 }
1462
1463 return null;
joonhunshin2c3e4232021-11-28 07:32:01 +00001464 }
1465
1466 private int getValueFromImsService(int subId, int capability, int tech) {
1467 int config = ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
1468
1469 // operation is based on capability
1470 switch (capability) {
1471 case CAPABILITY_TYPE_VOICE:
1472 int item = (tech == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN)
1473 ? ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE
1474 : ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS;
1475 // read data from vendor ImsService
1476 config = mMmTelFeatureListenersSlotMap.get(getSlotId(subId))
1477 .getProvisioningValue(item);
1478 break;
1479 case CAPABILITY_TYPE_VIDEO:
1480 // read data from vendor ImsService
1481 config = mMmTelFeatureListenersSlotMap.get(getSlotId(subId))
1482 .getProvisioningValue(ProvisioningManager.KEY_VT_PROVISIONING_STATUS);
1483 break;
1484 default:
1485 log("Capability " + capability + " has been provisioning");
1486 break;
1487 }
1488
1489 return config;
1490 }
1491
1492 private int getRcsValueFromImsService(int subId, int capability) {
1493 int config = ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
joonhunshin35d754f2022-06-24 03:29:15 +00001494 int slotId = getSlotId(subId);
joonhunshin2c3e4232021-11-28 07:32:01 +00001495
joonhunshin35d754f2022-06-24 03:29:15 +00001496 if (capability != CAPABILITY_TYPE_PRESENCE_UCE) {
joonhunshin2c3e4232021-11-28 07:32:01 +00001497 log("Capability " + capability + " has been provisioning");
joonhunshin35d754f2022-06-24 03:29:15 +00001498 return config;
1499 }
1500 try {
1501 if (mRcsFeatureListenersSlotMap.get(slotId).isConnectionReady()) {
1502 config = mRcsFeatureListenersSlotMap.get(slotId)
1503 .getProvisioningValue(ProvisioningManager.KEY_EAB_PROVISIONING_STATUS);
1504 } else {
1505 log("Rcs ImsService is not available, "
1506 + "EAB provisioning status should be read from MmTel ImsService");
1507 config = mMmTelFeatureListenersSlotMap.get(slotId)
1508 .getProvisioningValue(ProvisioningManager.KEY_EAB_PROVISIONING_STATUS);
1509 }
1510 } catch (NullPointerException e) {
1511 logw("can not access FeatureListener : " + e.getMessage());
joonhunshin2c3e4232021-11-28 07:32:01 +00001512 }
1513
1514 return config;
1515 }
1516
1517 private void onSubscriptionsChanged() {
1518 for (int index = 0; index < mMmTelFeatureListenersSlotMap.size(); index++) {
1519 MmTelFeatureListener m = mMmTelFeatureListenersSlotMap.get(index);
1520 m.setSubId(getSubId(index));
1521 }
1522 for (int index = 0; index < mRcsFeatureListenersSlotMap.size(); index++) {
1523 RcsFeatureListener r = mRcsFeatureListenersSlotMap.get(index);
1524 r.setSubId(getSubId(index));
1525 }
1526 for (int index = 0; index < mProvisioningCallbackManagersSlotMap.size(); index++) {
1527 ProvisioningCallbackManager m = mProvisioningCallbackManagersSlotMap.get(index);
1528 m.setSubId(getSubId(index));
1529 }
1530 }
1531
1532 private void updateCapabilityTechFromKey(int subId, int key, int value) {
1533 boolean isProvisioned = getBoolValue(value);
1534 int capability = getCapabilityFromKey(key);
1535 int tech = getTechFromKey(key);
1536
1537 if (capability == INVALID_VALUE || tech == INVALID_VALUE) {
1538 logw("updateCapabilityTechFromKey : unknown key " + key);
1539 return;
1540 }
1541
1542 if (key == KEY_VOLTE_PROVISIONING_STATUS
1543 || key == KEY_VT_PROVISIONING_STATUS
1544 || key == KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE) {
1545 setAndNotifyMmTelProvisioningValue(subId, capability, tech, isProvisioned);
1546 }
1547 if (key == KEY_EAB_PROVISIONING_STATUS) {
1548 setAndNotifyRcsProvisioningValueForAllTech(subId, capability, isProvisioned);
1549 }
1550 }
1551
1552 private int getCapabilityFromKey(int key) {
1553 int capability;
1554 switch (key) {
1555 case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS:
1556 // intentional fallthrough
1557 case ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE:
1558 capability = CAPABILITY_TYPE_VOICE;
1559 break;
1560 case ProvisioningManager.KEY_VT_PROVISIONING_STATUS:
1561 capability = CAPABILITY_TYPE_VIDEO;
1562 break;
1563 case ProvisioningManager.KEY_EAB_PROVISIONING_STATUS:
1564 // default CAPABILITY_TYPE_PRESENCE_UCE used for KEY_EAB_PROVISIONING_STATUS
1565 capability = CAPABILITY_TYPE_PRESENCE_UCE;
1566 break;
1567 default:
1568 capability = INVALID_VALUE;
1569 break;
1570 }
1571 return capability;
1572 }
1573
1574 private int getTechFromKey(int key) {
1575 int tech;
1576 switch (key) {
1577 case ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE:
1578 tech = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
1579 break;
1580 case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS:
1581 // intentional fallthrough
1582 case ProvisioningManager.KEY_VT_PROVISIONING_STATUS:
1583 // intentional fallthrough
1584 case ProvisioningManager.KEY_EAB_PROVISIONING_STATUS:
1585 tech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
1586 break;
1587 default:
1588 tech = INVALID_VALUE;
1589 break;
1590 }
1591 return tech;
1592 }
1593
1594 private int getKeyFromCapability(int capability, int tech) {
1595 int key = INVALID_VALUE;
1596 if (capability == CAPABILITY_TYPE_VOICE && tech == REGISTRATION_TECH_IWLAN) {
1597 key = ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE;
1598 } else if (capability == CAPABILITY_TYPE_VOICE && tech == REGISTRATION_TECH_LTE) {
1599 key = ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS;
1600 } else if (capability == CAPABILITY_TYPE_VIDEO && tech == REGISTRATION_TECH_LTE) {
1601 key = ProvisioningManager.KEY_VT_PROVISIONING_STATUS;
1602 }
1603
1604 return key;
1605 }
1606
1607 protected int getSubId(int slotId) {
Jack Yudfce4d62023-02-25 15:15:01 -08001608 return SubscriptionManager.getSubscriptionId(slotId);
joonhunshin2c3e4232021-11-28 07:32:01 +00001609 }
1610
1611 protected int getSlotId(int subId) {
1612 return mSubscriptionManager.getPhoneId(subId);
1613 }
1614
1615 protected ImsConfig getImsConfig(ImsManager imsManager) throws ImsException {
1616 return imsManager.getConfigInterface();
1617 }
1618
1619 protected ImsConfig getImsConfig(IImsConfig iImsConfig) {
1620 return new ImsConfig(iImsConfig);
1621 }
1622
1623 private int getIntValue(boolean isProvisioned) {
1624 return isProvisioned ? ProvisioningManager.PROVISIONING_VALUE_ENABLED
1625 : ProvisioningManager.PROVISIONING_VALUE_DISABLED;
1626 }
1627
1628 private boolean getBoolValue(int value) {
1629 return value == ProvisioningManager.PROVISIONING_VALUE_ENABLED ? true : false;
1630 }
1631
1632 private boolean setAndNotifyMmTelProvisioningValue(int subId, int capability, int tech,
1633 boolean isProvisioned) {
1634 boolean changed = mImsProvisioningLoader.setProvisioningStatus(subId, FEATURE_MMTEL,
1635 capability, tech, isProvisioned);
1636 // notify MmTel capability changed
1637 if (changed) {
1638 mHandler.sendMessage(mHandler.obtainMessage(EVENT_PROVISIONING_CAPABILITY_CHANGED,
1639 getSlotId(subId), 0, (Object) new FeatureProvisioningData(
1640 capability, tech, isProvisioned, /*isMmTel*/true)));
1641 }
1642
1643 return changed;
1644 }
1645
1646 private boolean setAndNotifyRcsProvisioningValue(int subId, int capability, int tech,
1647 boolean isProvisioned) {
1648 boolean isChanged = mImsProvisioningLoader.setProvisioningStatus(subId, FEATURE_RCS,
1649 capability, tech, isProvisioned);
1650
1651 if (isChanged) {
1652 int slotId = getSlotId(subId);
1653
1654 // notify RCS capability changed
1655 mHandler.sendMessage(mHandler.obtainMessage(EVENT_PROVISIONING_CAPABILITY_CHANGED,
1656 slotId, 0, (Object) new FeatureProvisioningData(
1657 capability, tech, isProvisioned, /*isMmtel*/false)));
1658 }
1659
1660 return isChanged;
1661 }
1662
1663 private boolean setAndNotifyRcsProvisioningValueForAllTech(int subId, int capability,
1664 boolean isProvisioned) {
1665 boolean isChanged = false;
1666
1667 for (int tech : LOCAL_RADIO_TECHS) {
1668 isChanged |= setAndNotifyRcsProvisioningValue(subId, capability, tech, isProvisioned);
1669 }
1670
1671 return isChanged;
1672 }
1673
joonhunshin2c3e4232021-11-28 07:32:01 +00001674 protected boolean isValidSubId(int subId) {
1675 int slotId = getSlotId(subId);
1676 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
1677 return false;
1678 }
1679
1680 return true;
1681 }
1682
joonhunshin711a8872024-03-19 10:04:08 +00001683 private void notifyMmTelProvisioningStatus(int slotId, int subId,
1684 @Nullable IFeatureProvisioningCallback callback) {
1685 int value = ImsProvisioningLoader.STATUS_NOT_SET;
1686 int[] techArray;
1687 for (int capability : LOCAL_MMTEL_CAPABILITY) {
1688 techArray = getTechsFromCarrierConfig(subId, capability, /*isMmTle*/true);
1689 if (techArray == null) {
1690 continue;
1691 }
1692
1693 for (int radioTech : techArray) {
1694 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
1695 capability, radioTech);
1696 if (value == ImsProvisioningLoader.STATUS_NOT_SET) {
1697 // Not yet provisioned
1698 continue;
1699 }
1700
1701 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
1702 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
1703
1704 // Notify all registered callbacks
1705 if (callback == null) {
1706 mProvisioningCallbackManagersSlotMap.get(slotId)
1707 .notifyProvisioningCapabilityChanged(
1708 new FeatureProvisioningData(
1709 capability,
1710 radioTech,
1711 getBoolValue(value),
1712 /*isMmTle*/true));
1713 } else {
1714 try {
1715 callback.onFeatureProvisioningChanged(capability, radioTech,
1716 getBoolValue(value));
1717 } catch (RemoteException e) {
1718 logw("notifyMmTelProvisioningStatus callback is not available");
1719 }
1720 }
1721 }
1722 }
1723 }
1724
1725 private void notifyRcsProvisioningStatus(int slotId, int subId,
1726 @Nullable IFeatureProvisioningCallback callback) {
1727 int value = ImsProvisioningLoader.STATUS_NOT_SET;
1728 int[] techArray;
1729 for (int capability : LOCAL_RCS_CAPABILITY) {
1730 techArray = getTechsFromCarrierConfig(subId, capability, /*isMmTle*/false);
1731 if (techArray == null) {
1732 continue;
1733 }
1734
1735 for (int radioTech : techArray) {
1736 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
1737 capability, radioTech);
1738 if (value == ImsProvisioningLoader.STATUS_NOT_SET) {
1739 // Not yet provisioned
1740 continue;
1741 }
1742
1743 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
1744 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
1745
1746 // Notify all registered callbacks
1747 if (callback == null) {
1748 mProvisioningCallbackManagersSlotMap.get(slotId)
1749 .notifyProvisioningCapabilityChanged(
1750 new FeatureProvisioningData(
1751 capability,
1752 radioTech,
1753 getBoolValue(value),
1754 /*isMmTle*/false));
1755 } else {
1756 try {
1757 callback.onRcsFeatureProvisioningChanged(capability, radioTech,
1758 getBoolValue(value));
1759 } catch (RemoteException e) {
1760 logw("notifyRcsProvisioningStatus callback is not available");
1761 }
1762 }
1763 }
1764 }
1765 }
1766
joonhunshin2c3e4232021-11-28 07:32:01 +00001767 private void log(String s) {
1768 Rlog.d(TAG, s);
1769 }
1770
1771 private void log(String prefix, int slotId, String s) {
1772 Rlog.d(TAG, prefix + "[" + slotId + "] " + s);
1773 }
1774
1775 private void logi(String prefix, int slotId, String s) {
1776 Rlog.i(TAG, prefix + "[" + slotId + "] " + s);
1777 }
1778
1779 private void logw(String s) {
1780 Rlog.w(TAG, s);
1781 }
1782
1783 private void logw(String prefix, int slotId, String s) {
1784 Rlog.w(TAG, prefix + "[" + slotId + "] " + s);
1785 }
1786
1787 private void loge(String s) {
1788 Rlog.e(TAG, s);
1789 }
1790
1791 private void loge(String prefix, int slotId, String s) {
1792 Rlog.e(TAG, prefix + "[" + slotId + "] " + s);
1793 }
1794}