blob: b42f57f561e72fbe5efe6a8fb0fe498f38c09a40 [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
19import static android.telephony.ims.ProvisioningManager.KEY_EAB_PROVISIONING_STATUS;
20import static android.telephony.ims.ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE;
21import static android.telephony.ims.ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS;
22import static android.telephony.ims.ProvisioningManager.KEY_VT_PROVISIONING_STATUS;
23import static android.telephony.ims.ProvisioningManager.PROVISIONING_VALUE_DISABLED;
24import static android.telephony.ims.ProvisioningManager.PROVISIONING_VALUE_ENABLED;
25import static android.telephony.ims.feature.ImsFeature.FEATURE_MMTEL;
26import static android.telephony.ims.feature.ImsFeature.FEATURE_RCS;
27import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER;
28import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS;
29import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT;
30import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO;
31import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE;
32import static android.telephony.ims.feature.RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE;
33import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM;
34import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
35import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
36import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_MAX;
37import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE;
38import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NR;
39
40import android.annotation.Nullable;
41import android.content.Context;
42import android.os.Handler;
43import android.os.HandlerThread;
44import android.os.Looper;
45import android.os.Message;
46import android.os.PersistableBundle;
47import android.os.RemoteCallbackList;
48import android.os.RemoteException;
49import android.telephony.CarrierConfigManager;
50import android.telephony.SubscriptionManager;
51import android.telephony.TelephonyRegistryManager;
52import android.telephony.ims.ProvisioningManager;
53import android.telephony.ims.aidl.IFeatureProvisioningCallback;
54import android.telephony.ims.aidl.IImsConfig;
55import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities;
56import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
57import android.telephony.ims.stub.ImsConfigImplBase;
58import android.telephony.ims.stub.ImsRegistrationImplBase;
59import android.util.SparseArray;
60
61import com.android.ims.FeatureConnector;
62import com.android.ims.ImsConfig;
63import com.android.ims.ImsException;
64import com.android.ims.ImsManager;
65import com.android.ims.RcsFeatureManager;
66import com.android.internal.annotations.VisibleForTesting;
67import com.android.internal.telephony.util.HandlerExecutor;
68import com.android.telephony.Rlog;
69
70import java.util.Arrays;
71import java.util.concurrent.Executor;
72
73/**
74 * Provides APIs for MMTEL and RCS provisioning status. This class handles provisioning status and
75 * notifies the status changing for each capability
76 * {{@link MmTelCapabilities.MmTelCapability} for MMTel services}
77 * {{@link RcsImsCapabilities.RcsImsCapabilityFlag} for RCS services}
78 */
79public class ImsProvisioningController {
80 private static final String TAG = "ImsProvisioningController";
81 private static final int INVALID_VALUE = -1;
82
83 private static final int EVENT_SUB_CHANGED = 1;
84 private static final int EVENT_PROVISIONING_CAPABILITY_CHANGED = 2;
85
86 // Provisioning Keys that are handled via AOSP cache and not sent to the ImsService
87 private static final int[] LOCAL_IMS_CONFIG_KEYS = {
88 KEY_VOLTE_PROVISIONING_STATUS,
89 KEY_VT_PROVISIONING_STATUS,
90 KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE,
91 KEY_EAB_PROVISIONING_STATUS
92 };
93 private static final int[] LOCAL_RADIO_TECHS = {
94 REGISTRATION_TECH_LTE,
95 REGISTRATION_TECH_IWLAN,
96 REGISTRATION_TECH_CROSS_SIM,
97 REGISTRATION_TECH_NR
98 };
99
100 private static final int MMTEL_CAPABILITY_MIN = MmTelCapabilities.CAPABILITY_TYPE_NONE;
101 private static final int MMTEL_CAPABILITY_MAX = MmTelCapabilities.CAPABILITY_TYPE_MAX;
102
103 private static final int RCS_CAPABILITY_MIN = RcsImsCapabilities.CAPABILITY_TYPE_NONE;
104 private static final int RCS_CAPABILITY_MAX = RcsImsCapabilities.CAPABILITY_TYPE_MAX;
105
106 private static final int[] LOCAL_MMTEL_CAPABILITY = {
107 CAPABILITY_TYPE_VOICE,
108 CAPABILITY_TYPE_VIDEO,
109 CAPABILITY_TYPE_UT,
110 CAPABILITY_TYPE_SMS,
111 CAPABILITY_TYPE_CALL_COMPOSER
112 };
113
114 /**
115 * Create a FeatureConnector for this class to use to connect to an ImsManager.
116 */
117 @VisibleForTesting
118 public interface MmTelFeatureConnector {
119 /**
120 * Create a FeatureConnector for this class to use to connect to an ImsManager.
121 * @param listener will receive ImsManager instance.
122 * @param executor that the Listener callbacks will be called on.
123 * @return A FeatureConnector
124 */
125 FeatureConnector<ImsManager> create(Context context, int slotId,
126 String logPrefix, FeatureConnector.Listener<ImsManager> listener,
127 Executor executor);
128 }
129
130 /**
131 * Create a FeatureConnector for this class to use to connect to an RcsFeatureManager.
132 */
133 @VisibleForTesting
134 public interface RcsFeatureConnector {
135 /**
136 * Create a FeatureConnector for this class to use to connect to an RcsFeatureManager.
137 * @param listener will receive RcsFeatureManager instance.
138 * @param executor that the Listener callbacks will be called on.
139 * @return A FeatureConnector
140 */
141 FeatureConnector<RcsFeatureManager> create(Context context, int slotId,
142 FeatureConnector.Listener<RcsFeatureManager> listener,
143 Executor executor, String logPrefix);
144 }
145
146 private static ImsProvisioningController sInstance;
147
148 private final PhoneGlobals mApp;
149 private final Handler mHandler;
150 private final CarrierConfigManager mCarrierConfigManager;
151 private final SubscriptionManager mSubscriptionManager;
152 private final TelephonyRegistryManager mTelephonyRegistryManager;
153 private final MmTelFeatureConnector mMmTelFeatureConnector;
154 private final RcsFeatureConnector mRcsFeatureConnector;
155
156 // maps a slotId to a list of MmTelFeatureListeners
157 private final SparseArray<MmTelFeatureListener> mMmTelFeatureListenersSlotMap =
158 new SparseArray<>();
159 // maps a slotId to a list of RcsFeatureListeners
160 private final SparseArray<RcsFeatureListener> mRcsFeatureListenersSlotMap =
161 new SparseArray<>();
162 // map a slotId to a list of ProvisioningCallbackManager
163 private final SparseArray<ProvisioningCallbackManager> mProvisioningCallbackManagersSlotMap =
164 new SparseArray<>();
165 private final ImsProvisioningLoader mImsProvisioningLoader;
166
167 private int mNumSlot;
168
169 /**
170 * This class contains the provisioning status to notify changes.
171 * {{@link MmTelCapabilities.MmTelCapability} for MMTel services}
172 * {{@link RcsImsCapabilities.RcsImsCapabilityFlag} for RCS services}
173 * {{@link ImsRegistrationImplBase.ImsRegistrationTech} for Registration tech}
174 */
175 private static final class FeatureProvisioningData {
176 public final int mCapability;
177 public final int mTech;
178 public final boolean mProvisioned;
179 public final boolean mIsMmTel;
180
181 FeatureProvisioningData(int capability, int tech, boolean provisioned, boolean isMmTel) {
182 mCapability = capability;
183 mTech = tech;
184 mProvisioned = provisioned;
185 mIsMmTel = isMmTel;
186 }
187 }
188
189 private final class MessageHandler extends Handler {
190 private static final String LOG_PREFIX = "Handler";
191 MessageHandler(Looper looper) {
192 super(looper);
193 }
194
195 @Override
196 public void handleMessage(Message msg) {
197 switch (msg.what) {
198 case EVENT_SUB_CHANGED:
199 onSubscriptionsChanged();
200 break;
201 case EVENT_PROVISIONING_CAPABILITY_CHANGED:
202 try {
203 mProvisioningCallbackManagersSlotMap.get(msg.arg1)
204 .notifyProvisioningCapabilityChanged(
205 (FeatureProvisioningData) msg.obj);
206 } catch (NullPointerException e) {
207 logw(LOG_PREFIX, msg.arg1,
208 "can not find callback manager message" + msg.what);
209 }
210 break;
211 default:
212 log("unknown message " + msg);
213 break;
214 }
215 }
216 }
217
218 private final SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener =
219 new SubscriptionManager.OnSubscriptionsChangedListener() {
220 @Override
221 public void onSubscriptionsChanged() {
222 if (!mHandler.hasMessages(EVENT_SUB_CHANGED)) {
223 mHandler.sendEmptyMessage(EVENT_SUB_CHANGED);
224 }
225 }
226 };
227
228 private final class ProvisioningCallbackManager {
229 private static final String LOG_PREFIX = "ProvisioningCallbackManager";
230 private RemoteCallbackList<IFeatureProvisioningCallback> mIFeatureProvisioningCallbackList;
231 private int mSubId;
232 private int mSlotId;
233
234 ProvisioningCallbackManager(int slotId) {
235 mIFeatureProvisioningCallbackList =
236 new RemoteCallbackList<IFeatureProvisioningCallback>();
237 mSlotId = slotId;
238 mSubId = getSubId(slotId);
239 log(LOG_PREFIX, mSlotId, "ProvisioningCallbackManager create");
240 }
241
242 public void clear() {
243 log(LOG_PREFIX, mSlotId, "ProvisioningCallbackManager clear ");
244
245 mIFeatureProvisioningCallbackList.kill();
246
247 // All registered callbacks are unregistered, and the list is disabled
248 // need to create again
249 mIFeatureProvisioningCallbackList =
250 new RemoteCallbackList<IFeatureProvisioningCallback>();
251 }
252
253 public void registerCallback(IFeatureProvisioningCallback localCallback) {
254 if (!mIFeatureProvisioningCallbackList.register(localCallback, (Object) mSubId)) {
255 log(LOG_PREFIX, mSlotId, "registration callback fail");
256 }
257 }
258
259 public void unregisterCallback(IFeatureProvisioningCallback localCallback) {
260 mIFeatureProvisioningCallbackList.unregister(localCallback);
261 }
262
263 public void setSubId(int subId) {
264 if (mSubId == subId) {
265 log(LOG_PREFIX, mSlotId, "subId is not changed ");
266 return;
267 }
268
269 mSubId = subId;
270 mSlotId = getSlotId(subId);
271
272 // subId changed means the registered callbacks are not available.
273 clear();
274 }
275
276 public boolean hasCallblacks() {
277 int size = mIFeatureProvisioningCallbackList.beginBroadcast();
278 mIFeatureProvisioningCallbackList.finishBroadcast();
279
280 return (size > 0);
281 }
282
283 public void notifyProvisioningCapabilityChanged(FeatureProvisioningData data) {
284 int size = mIFeatureProvisioningCallbackList.beginBroadcast();
285 for (int index = 0; index < size; index++) {
286 try {
287 IFeatureProvisioningCallback imsFeatureProvisioningCallback =
288 mIFeatureProvisioningCallbackList.getBroadcastItem(index);
289
290 // MMTEL
291 if (data.mIsMmTel
292 && Arrays.stream(LOCAL_MMTEL_CAPABILITY)
293 .anyMatch(value -> value == data.mCapability)) {
294 imsFeatureProvisioningCallback.onFeatureProvisioningChanged(
295 data.mCapability, data.mTech, data.mProvisioned);
296 logi(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : "
297 + "onFeatureProvisioningChanged"
298 + " capability " + data.mCapability
299 + " tech " + data.mTech
300 + " isProvisioned " + data.mProvisioned);
301 } else if (data.mCapability == CAPABILITY_TYPE_PRESENCE_UCE) {
302 imsFeatureProvisioningCallback.onRcsFeatureProvisioningChanged(
303 data.mCapability, data.mTech, data.mProvisioned);
304 logi(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : "
305 + "onRcsFeatureProvisioningChanged"
306 + " capability " + data.mCapability
307 + " tech " + data.mTech
308 + " isProvisioned " + data.mProvisioned);
309 } else {
310 loge(LOG_PREFIX, mSlotId, "notifyProvisioningCapabilityChanged : "
311 + "unknown capability "
312 + data.mCapability);
313 }
314 } catch (RemoteException e) {
315 loge(LOG_PREFIX, mSlotId,
316 "notifyProvisioningChanged: callback #" + index + " failed");
317 }
318 }
319 mIFeatureProvisioningCallbackList.finishBroadcast();
320 }
321 }
322
323 private final class MmTelFeatureListener implements FeatureConnector.Listener<ImsManager> {
324 private static final String LOG_PREFIX = "MmTelFeatureListener";
325 private FeatureConnector<ImsManager> mConnector;
326 private ImsManager mImsManager;
327 private boolean mReady = false;
328 // stores whether the initial provisioning key value should be notified to ImsService
329 private boolean mRequiredNotify = false;
330 private int mSubId;
331 private int mSlotId;
332
333 MmTelFeatureListener(int slotId) {
334 log(LOG_PREFIX, slotId, "created");
335
336 mSlotId = slotId;
337 mSubId = getSubId(slotId);
338 mConnector = mMmTelFeatureConnector.create(
339 mApp, slotId, TAG, this, new HandlerExecutor(mHandler));
340 mConnector.connect();
341 }
342
343 public void setSubId(int subId) {
344 if (mRequiredNotify && mReady) {
345 mRequiredNotify = false;
346 setInitialProvisioningKeys(subId);
347 }
348 if (mSubId == subId) {
349 log(LOG_PREFIX, mSlotId, "subId is not changed");
350 return;
351 }
352
353 mSubId = subId;
354 mSlotId = getSlotId(subId);
355 }
356
357 public void destroy() {
358 log("destroy");
359 mConnector.disconnect();
360 mConnector = null;
361 mReady = false;
362 mImsManager = null;
363 }
364
365 public @Nullable ImsManager getImsManager() {
366 return mImsManager;
367 }
368
369 @Override
370 public void connectionReady(ImsManager manager, int subId) {
371 log(LOG_PREFIX, mSlotId, "connection ready");
372 mReady = true;
373 mImsManager = manager;
374
375 onMmTelAvailable();
376 }
377
378 @Override
379 public void connectionUnavailable(int reason) {
380 log(LOG_PREFIX, mSlotId, "connection unavailable " + reason);
381
382 mReady = false;
383 mImsManager = null;
384
385 // keep the callback for other reason
386 if (reason == FeatureConnector.UNAVAILABLE_REASON_IMS_UNSUPPORTED) {
387 onMmTelUnavailable();
388 }
389 }
390
391 public int setProvisioningValue(int key, int value) {
392 int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED;
393
394 if (!mReady) {
395 loge(LOG_PREFIX, mSlotId, "service is Unavailable");
396 return retVal;
397 }
398 try {
399 // getConfigInterface() will return not null or throw the ImsException
400 // need not null checking
401 ImsConfig imsConfig = getImsConfig(mImsManager);
402 retVal = imsConfig.setConfig(key, value);
403 log(LOG_PREFIX, mSlotId, "setConfig called with key " + key + " value " + value);
404 } catch (ImsException e) {
405 logw(LOG_PREFIX, mSlotId,
406 "setConfig operation failed for key =" + key
407 + ", value =" + value + ". Exception:" + e.getMessage());
408 }
409 return retVal;
410 }
411
412 public int getProvisioningValue(int key) {
413 if (!mReady) {
414 loge(LOG_PREFIX, mSlotId, "service is Unavailable");
415 return INVALID_VALUE;
416 }
417
418 int retValue = INVALID_VALUE;
419 try {
420 // getConfigInterface() will return not null or throw the ImsException
421 // need not null checking
422 ImsConfig imsConfig = getImsConfig(mImsManager);
423 retValue = imsConfig.getConfigInt(key);
424 } catch (ImsException e) {
425 logw(LOG_PREFIX, mSlotId,
426 "getConfig operation failed for key =" + key
427 + ", value =" + retValue + ". Exception:" + e.getMessage());
428 }
429 return retValue;
430 }
431
432 public void onMmTelAvailable() {
433 log(LOG_PREFIX, mSlotId, "onMmTelAvailable");
434
435 if (isValidSubId(mSubId)) {
436 mRequiredNotify = false;
437
438 // notify provisioning key value to ImsService
439 setInitialProvisioningKeys(mSubId);
440 } else {
441 // wait until subId is valid
442 mRequiredNotify = true;
443 }
444 }
445
446 public void onMmTelUnavailable() {
447 log(LOG_PREFIX, mSlotId, "onMmTelUnavailable");
448
449 try {
450 // delete all callbacks reference from ProvisioningManager
451 mProvisioningCallbackManagersSlotMap.get(getSlotId(mSubId)).clear();
452 } catch (NullPointerException e) {
453 logw(LOG_PREFIX, getSlotId(mSubId), "can not find callback manager to clear");
454 }
455 }
456
457 private void setInitialProvisioningKeys(int subId) {
458 boolean required;
459 int value = ImsProvisioningLoader.STATUS_NOT_SET;
460
461 // updating KEY_VOLTE_PROVISIONING_STATUS
462 required = isProvisioningRequired(subId, CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE,
463 /*isMmTel*/true);
464 log(LOG_PREFIX, mSlotId,
465 "setInitialProvisioningKeys provisioning required(voice, lte) " + required);
466 if (required) {
467 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
468 CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE);
469 if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
470 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
471 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
472 setProvisioningValue(KEY_VOLTE_PROVISIONING_STATUS, value);
473 }
474 }
475
476 // updating KEY_VT_PROVISIONING_STATUS
477 required = isProvisioningRequired(subId, CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_LTE,
478 /*isMmTel*/true);
479 log(LOG_PREFIX, mSlotId,
480 "setInitialProvisioningKeys provisioning required(video, lte) " + required);
481 if (required) {
482 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
483 CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_LTE);
484 if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
485 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
486 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
487 setProvisioningValue(KEY_VT_PROVISIONING_STATUS, value);
488 }
489 }
490
491 // updating KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE
492 required = isProvisioningRequired(subId, CAPABILITY_TYPE_VOICE,
493 REGISTRATION_TECH_IWLAN, /*isMmTel*/true);
494 log(LOG_PREFIX, mSlotId,
495 "setInitialProvisioningKeys provisioning required(voice, iwlan) " + required);
496 if (required) {
497 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
498 CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_IWLAN);
499 if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
500 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
501 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
502 setProvisioningValue(KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE, value);
503 }
504 }
505 }
506 }
507
508 private final class RcsFeatureListener implements FeatureConnector.Listener<RcsFeatureManager> {
509 private static final String LOG_PREFIX = "RcsFeatureListener";
510 private FeatureConnector<RcsFeatureManager> mConnector;
511 private RcsFeatureManager mRcsFeatureManager;
512 private boolean mReady = false;
513 // stores whether the initial provisioning key value should be notified to ImsService
514 private boolean mRequiredNotify = false;
515 private int mSubId;
516 private int mSlotId;
517
518 RcsFeatureListener(int slotId) {
519 log(LOG_PREFIX, slotId, "created");
520
521 mSlotId = slotId;
522 mSubId = getSubId(slotId);
523 mConnector = mRcsFeatureConnector.create(
524 mApp, slotId, this, new HandlerExecutor(mHandler), TAG);
525 mConnector.connect();
526 }
527
528 public void setSubId(int subId) {
529 if (mRequiredNotify && mReady) {
530 mRequiredNotify = false;
531 setInitialProvisioningKeys(subId);
532 }
533 if (mSubId == subId) {
534 log(LOG_PREFIX, mSlotId, "subId is not changed");
535 return;
536 }
537
538 mSubId = subId;
539 mSlotId = getSlotId(subId);
540 }
541
542 public void destroy() {
543 log(LOG_PREFIX, mSlotId, "destroy");
544 mConnector.disconnect();
545 mConnector = null;
546 mReady = false;
547 mRcsFeatureManager = null;
548 }
549
550 @Override
551 public void connectionReady(RcsFeatureManager manager, int subId) {
552 log(LOG_PREFIX, mSlotId, "connection ready");
553 mReady = true;
554 mRcsFeatureManager = manager;
555
556 onRcsAvailable();
557 }
558
559 @Override
560 public void connectionUnavailable(int reason) {
561 log(LOG_PREFIX, mSlotId, "connection unavailable");
562 mReady = false;
563 mRcsFeatureManager = null;
564
565 // keep the callback for other reason
566 if (reason == FeatureConnector.UNAVAILABLE_REASON_IMS_UNSUPPORTED) {
567 onRcsUnavailable();
568 }
569 }
570
571 public int setProvisioningValue(int key, int value) {
572 int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED;
573
574 if (!mReady) {
575 loge(LOG_PREFIX, mSlotId, "service is Unavailable");
576 return retVal;
577 }
578
579 try {
580 // getConfigInterface() will return not null or throw the ImsException
581 // need not null checking
582 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig());
583 retVal = imsConfig.setConfig(key, value);
584 log(LOG_PREFIX, mSlotId, "setConfig called with key " + key + " value " + value);
585 } catch (ImsException e) {
586 logw(LOG_PREFIX, mSlotId,
587 "setConfig operation failed for key =" + key
588 + ", value =" + value + ". Exception:" + e.getMessage());
589 }
590 return retVal;
591 }
592
593 public int getProvisioningValue(int key) {
594 if (!mReady) {
595 loge(LOG_PREFIX, mSlotId, "service is Unavailable");
596 return INVALID_VALUE;
597 }
598
599 int retValue = INVALID_VALUE;
600 try {
601 // getConfigInterface() will return not null or throw the ImsException
602 // need not null checking
603 ImsConfig imsConfig = getImsConfig(mRcsFeatureManager.getConfig());
604 retValue = imsConfig.getConfigInt(key);
605 } catch (ImsException e) {
606 logw(LOG_PREFIX, mSlotId,
607 "getConfig operation failed for key =" + key
608 + ", value =" + retValue + ". Exception:" + e.getMessage());
609 }
610 return retValue;
611 }
612
613 public void onRcsAvailable() {
614 log(LOG_PREFIX, mSlotId, "onRcsAvailable");
615
616 if (isValidSubId(mSubId)) {
617 mRequiredNotify = false;
618
619 // notify provisioning key value to ImsService
620 setInitialProvisioningKeys(mSubId);
621 } else {
622 // wait until subId is valid
623 mRequiredNotify = true;
624 }
625 }
626
627 public void onRcsUnavailable() {
628 log(LOG_PREFIX, mSlotId, "onRcsUnavailable");
629
630 try {
631 // delete all callbacks reference from ProvisioningManager
632 mProvisioningCallbackManagersSlotMap.get(getSlotId(mSubId)).clear();
633 } catch (NullPointerException e) {
634 logw(LOG_PREFIX, getSlotId(mSubId), "can not find callback manager to clear");
635 }
636 }
637
638 private void setInitialProvisioningKeys(int subId) {
639 boolean required;
640 int value = ImsProvisioningLoader.STATUS_NOT_SET;
641
642 // KEY_EAB_PROVISIONING_STATUS
643 int capability = CAPABILITY_TYPE_PRESENCE_UCE;
644 // Assume that all radio techs have the same provisioning value
645 int tech = REGISTRATION_TECH_LTE;
646
647 required = isProvisioningRequired(subId, capability, tech, /*isMmTel*/false);
648 if (required) {
649 value = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
650 capability, tech);
651 if (value != ImsProvisioningLoader.STATUS_NOT_SET) {
652 value = (value == ImsProvisioningLoader.STATUS_PROVISIONED)
653 ? PROVISIONING_VALUE_ENABLED : PROVISIONING_VALUE_DISABLED;
654 setProvisioningValue(KEY_EAB_PROVISIONING_STATUS, value);
655 }
656 }
657 }
658 }
659
660 /**
661 * Do NOT use this directly, instead use {@link #getInstance()}.
662 */
663 @VisibleForTesting
664 public ImsProvisioningController(PhoneGlobals app, int numSlot, Looper looper,
665 MmTelFeatureConnector mmTelFeatureConnector, RcsFeatureConnector rcsFeatureConnector,
666 ImsProvisioningLoader imsProvisioningLoader) {
667 log("ImsProvisioningController");
668 mApp = app;
669 mNumSlot = numSlot;
670 mHandler = new MessageHandler(looper);
671 mMmTelFeatureConnector = mmTelFeatureConnector;
672 mRcsFeatureConnector = rcsFeatureConnector;
673 mCarrierConfigManager = mApp.getSystemService(CarrierConfigManager.class);
674 mSubscriptionManager = mApp.getSystemService(SubscriptionManager.class);
675 mTelephonyRegistryManager = mApp.getSystemService(TelephonyRegistryManager.class);
676 mTelephonyRegistryManager.addOnSubscriptionsChangedListener(
677 mSubChangedListener, mSubChangedListener.getHandlerExecutor());
678 mImsProvisioningLoader = imsProvisioningLoader;
679
680 initialize(numSlot);
681 }
682
683 private void initialize(int numSlot) {
684 for (int i = 0; i < numSlot; i++) {
685 MmTelFeatureListener m = new MmTelFeatureListener(i);
686 mMmTelFeatureListenersSlotMap.put(i, m);
687
688 RcsFeatureListener r = new RcsFeatureListener(i);
689 mRcsFeatureListenersSlotMap.put(i, r);
690
691 ProvisioningCallbackManager p = new ProvisioningCallbackManager(i);
692 mProvisioningCallbackManagersSlotMap.put(i, p);
693 }
694 }
695
696 /**
697 * destroy the instance
698 */
699 @VisibleForTesting
700 public void destroy() {
701 log("destroy");
702
703 mHandler.getLooper().quit();
704
705 mTelephonyRegistryManager.removeOnSubscriptionsChangedListener(mSubChangedListener);
706
707 for (int i = 0; i < mMmTelFeatureListenersSlotMap.size(); i++) {
708 mMmTelFeatureListenersSlotMap.get(i).destroy();
709 }
710 mMmTelFeatureListenersSlotMap.clear();
711
712 for (int i = 0; i < mRcsFeatureListenersSlotMap.size(); i++) {
713 mRcsFeatureListenersSlotMap.get(i).destroy();
714 }
715 mRcsFeatureListenersSlotMap.clear();
716
717 for (int i = 0; i < mProvisioningCallbackManagersSlotMap.size(); i++) {
718 mProvisioningCallbackManagersSlotMap.get(i).clear();
719 }
720 }
721
722 /**
723 * create an instance
724 */
725 @VisibleForTesting
726 public static ImsProvisioningController make(PhoneGlobals app, int numSlot) {
727 synchronized (ImsProvisioningController.class) {
728 if (sInstance == null) {
729 Rlog.i(TAG, "ImsProvisioningController created");
730 HandlerThread handlerThread = new HandlerThread(TAG);
731 handlerThread.start();
732 sInstance = new ImsProvisioningController(app, numSlot, handlerThread.getLooper(),
733 ImsManager::getConnector, RcsFeatureManager::getConnector,
734 new ImsProvisioningLoader(app));
735 }
736 }
737 return sInstance;
738 }
739
740 /**
741 * Gets a ImsProvisioningController instance
742 */
743 @VisibleForTesting
744 public static ImsProvisioningController getInstance() {
745 synchronized (ImsProvisioningController.class) {
746 return sInstance;
747 }
748 }
749
750 /**
751 * Register IFeatureProvisioningCallback from ProvisioningManager
752 */
753
754 @VisibleForTesting
755 public void addFeatureProvisioningChangedCallback(int subId,
756 IFeatureProvisioningCallback callback) {
757 if (callback == null) {
758 throw new IllegalArgumentException("provisioning callback can't be null");
759 }
760 int slotId = getSlotId(subId);
761 if (slotId < 0 || slotId >= mNumSlot) {
762 throw new IllegalArgumentException("subscription id is not available");
763 }
764
765 try {
766 mProvisioningCallbackManagersSlotMap.get(slotId).registerCallback(callback);
767 log("Feature Provisioning Callback registered.");
768 } catch (NullPointerException e) {
769 logw("can not access callback manager to add callback");
770 }
771 }
772
773 /**
774 * Remove IFeatureProvisioningCallback
775 */
776 @VisibleForTesting
777 public void removeFeatureProvisioningChangedCallback(int subId,
778 IFeatureProvisioningCallback callback) {
779 if (callback == null) {
780 throw new IllegalArgumentException("provisioning callback can't be null");
781 }
782
783 int slotId = getSlotId(subId);
784 if (slotId < 0 || slotId >= mNumSlot) {
785 throw new IllegalArgumentException("subscription id is not available");
786 }
787
788 try {
789 mProvisioningCallbackManagersSlotMap.get(slotId).unregisterCallback(callback);
790 log("Feature Provisioning Callback removed.");
791 } catch (NullPointerException e) {
792 logw("can not access callback manager to remove callback");
793 }
794 }
795
796 /**
797 * return the boolean whether MmTel capability is required provisiong or not
798 */
799 @VisibleForTesting
800 public boolean isImsProvisioningRequiredForCapability(int subId, int capability, int tech) {
801 // check subId
802 int slotId = getSlotId(subId);
803 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
804 loge("Fail to retrieve slotId from subId");
805 throw new IllegalArgumentException("subscribe id is invalid");
806 }
807
808 // check valid capability
809 if (!(MMTEL_CAPABILITY_MIN < capability && capability < MMTEL_CAPABILITY_MAX)) {
810 throw new IllegalArgumentException("MmTel capability '" + capability + "' is invalid");
811 }
812
813 // check valid radio tech
814 if (!(REGISTRATION_TECH_NONE < tech && tech < REGISTRATION_TECH_MAX)) {
815 log("Ims not matched radio tech " + tech);
816 throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
817 }
818
819 boolean retVal = isProvisioningRequired(subId, capability, tech, /*isMmTel*/true);
820
821 log("isImsProvisioningRequiredForCapability capability " + capability
822 + " tech " + tech + " return value " + retVal);
823
824 return retVal;
825 }
826
827 /**
828 * return the boolean whether RCS capability is required provisiong or not
829 */
830 @VisibleForTesting
831 public boolean isRcsProvisioningRequiredForCapability(int subId, int capability, int tech) {
832 // check slotId and Phone object
833 int slotId = getSlotId(subId);
834 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
835 loge("Fail to retrieve slotId from subId");
836 throw new IllegalArgumentException("subscribe id is invalid");
837 }
838
839 // check valid capability
840 if (!(RCS_CAPABILITY_MIN < capability && capability < RCS_CAPABILITY_MAX)) {
841 throw new IllegalArgumentException("Rcs capability '" + capability + "' is invalid");
842 }
843
844 // check valid radio tech
845 if (!(REGISTRATION_TECH_NONE < tech && tech < REGISTRATION_TECH_MAX)) {
846 log("Rcs not matched radio tech " + tech);
847 throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
848 }
849
850 boolean retVal = isProvisioningRequired(subId, capability, tech, /*isMmTel*/false);
851
852 log("isRcsProvisioningRequiredForCapability capability " + capability
853 + " tech " + tech + " return value " + retVal);
854
855 return retVal;
856 }
857
858 /**
859 * return the provisioning status for MmTel capability in specific radio tech
860 */
861 @VisibleForTesting
862 public boolean getImsProvisioningStatusForCapability(int subId, int capability, int tech) {
863 boolean mmTelProvisioned = isImsProvisioningRequiredForCapability(subId, capability, tech);
864 if (!mmTelProvisioned) { // provisioning not required
865 log("getImsProvisioningStatusForCapability : not required "
866 + " capability " + capability + " tech " + tech);
867 return true;
868 }
869
870 // read value from ImsProvisioningLoader
871 int result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
872 capability, tech);
873 if (result == ImsProvisioningLoader.STATUS_NOT_SET) {
874 // not set means initial value
875 // read data from vendor ImsService and store that in ImsProvisioningLoader
876 result = getValueFromImsService(subId, capability, tech);
877 mmTelProvisioned = getBoolValue(result);
878 if (result != ProvisioningManager.PROVISIONING_RESULT_UNKNOWN) {
879 setAndNotifyMmTelProvisioningValue(subId, capability, tech, mmTelProvisioned);
880 }
881 } else {
882 mmTelProvisioned = getBoolValue(result);
883 }
884
885 log("getImsProvisioningStatusForCapability : "
886 + " capability " + capability
887 + " tech " + tech
888 + " result " + mmTelProvisioned);
889 return mmTelProvisioned;
890 }
891
892 /**
893 * set MmTel provisioning status in specific tech
894 */
895 @VisibleForTesting
896 public void setImsProvisioningStatusForCapability(int subId, int capability, int tech,
897 boolean isProvisioned) {
898 boolean mmTelProvisioned = isImsProvisioningRequiredForCapability(subId, capability, tech);
899 if (!mmTelProvisioned) { // provisioning not required
900 log("setImsProvisioningStatusForCapability : not required "
901 + " capability " + capability + " tech " + tech);
902 return;
903 }
904
905 // write value to ImsProvisioningLoader
906 boolean isChanged = setAndNotifyMmTelProvisioningValue(subId, capability, tech,
907 isProvisioned);
908 if (!isChanged) {
909 log("status not changed mmtel capability " + capability + " tech " + tech);
910 return;
911 }
912
913 int slotId = getSlotId(subId);
914 // find matched key from capability and tech
915 int value = getIntValue(isProvisioned);
916 int key = getKeyFromCapability(capability, tech);
917 if (key != INVALID_VALUE) {
918 log("setImsProvisioningStatusForCapability : matched key " + key);
919 try {
920 // set key and value to vendor ImsService for MmTel
921 mMmTelFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
922
923 // notify provisioning status changed to ImsManager
924 updateImsServiceConfig(subId);
925 } catch (NullPointerException e) {
926 loge("can not access MmTelFeatureListener with capability " + capability);
927 }
928 }
929 }
930
931 /**
932 * return the provisioning status for RCS capability in specific radio tech
933 */
934 @VisibleForTesting
935 public boolean getRcsProvisioningStatusForCapability(int subId, int capability, int tech) {
936 boolean rcsProvisioned = isRcsProvisioningRequiredForCapability(subId, capability, tech);
937 if (!rcsProvisioned) { // provisioning not required
938 log("getRcsProvisioningStatusForCapability : not required"
939 + " capability " + capability + " tech " + tech);
940 return true;
941 }
942
943 // read data from ImsProvisioningLoader
944 int result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
945 capability, tech);
946 if (result == ImsProvisioningLoader.STATUS_NOT_SET) {
947 // not set means initial value
948 // read data from vendor ImsService and store that in ImsProvisioningLoader
949 result = getRcsValueFromImsService(subId, capability);
950 rcsProvisioned = getBoolValue(result);
951 if (result != ProvisioningManager.PROVISIONING_RESULT_UNKNOWN) {
952 setAndNotifyRcsProvisioningValueForAllTech(subId, capability, rcsProvisioned);
953 }
954 } else {
955 rcsProvisioned = getBoolValue(result);
956 }
957
958 log("getRcsProvisioningStatusForCapability : "
959 + " capability " + capability
960 + " tech " + tech
961 + " result " + rcsProvisioned);
962 return rcsProvisioned;
963 }
964
965 /**
966 * set RCS provisioning status in specific tech
967 */
968 @VisibleForTesting
969 public void setRcsProvisioningStatusForCapability(int subId, int capability, int tech,
970 boolean isProvisioned) {
971 boolean rcsProvisioned = isRcsProvisioningRequiredForCapability(subId, capability, tech);
972 if (!rcsProvisioned) { // provisioning not required
973 log("set rcs provisioning status but not required");
974 return;
975 }
976
977 // write status using ImsProvisioningLoader
978 boolean isChanged = setAndNotifyRcsProvisioningValue(subId, capability, tech,
979 isProvisioned);
980 if (!isChanged) {
981 log("status not changed rcs capability " + capability + " tech " + tech);
982 return;
983 }
984
985 int slotId = getSlotId(subId);
986 int key = ProvisioningManager.KEY_EAB_PROVISIONING_STATUS;
987 int value = getIntValue(isProvisioned);
988 try {
989 // set key and value to vendor ImsService for Rcs
990 mRcsFeatureListenersSlotMap.get(slotId).setProvisioningValue(key, value);
991 } catch (NullPointerException e) {
992 loge("can not access RcsFeatureListener with capability " + capability);
993 }
994 }
995
996 /**
997 * set RCS provisioning status in specific key and value
998 * @param key integer key, defined as one of
999 * {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS}
1000 * {@link ProvisioningManager#KEY_VT_PROVISIONING_STATUS}
1001 * {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE}
1002 * {@link ProvisioningManager#KEY_EAB_PROVISIONING_STATUS}
1003 * @param value in Integer format.
1004 * @return the result of setting the configuration value, defined as one of
1005 * {@link ImsConfigImplBase#CONFIG_RESULT_FAILED} or
1006 * {@link ImsConfigImplBase#CONFIG_RESULT_SUCCESS} or
1007 */
1008 @VisibleForTesting
1009 public int setProvisioningValue(int subId, int key, int value) {
1010 log("setProvisioningValue");
1011
1012 int retVal = ImsConfigImplBase.CONFIG_RESULT_FAILED;
1013 // check key value
1014 if (!Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(keyValue -> keyValue == key)) {
1015 log("not matched key " + key);
1016 return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
1017 }
1018
1019 // check subId
1020 int slotId = getSlotId(subId);
1021 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
1022 loge("Fail to retrieve slotId from subId");
1023 return ImsConfigImplBase.CONFIG_RESULT_FAILED;
1024 }
1025
1026 try {
1027 if (key == KEY_EAB_PROVISIONING_STATUS) {
1028 // set key and value to vendor ImsService for Rcs
1029 retVal = mRcsFeatureListenersSlotMap.get(slotId)
1030 .setProvisioningValue(key, value);
1031 } else {
1032 // set key and value to vendor ImsService for MmTel
1033 retVal = mMmTelFeatureListenersSlotMap.get(slotId)
1034 .setProvisioningValue(key, value);
1035 }
1036 } catch (NullPointerException e) {
1037 loge("can not access FeatureListener to set provisioning value");
1038 return ImsConfigImplBase.CONFIG_RESULT_FAILED;
1039 }
1040
1041 // update and notify provisioning status changed capability and tech from key
1042 updateCapabilityTechFromKey(subId, key, value);
1043
1044 if (key != KEY_EAB_PROVISIONING_STATUS) {
1045 // notify provisioning status changed to ImsManager
1046 updateImsServiceConfig(subId);
1047 }
1048
1049 return retVal;
1050 }
1051
1052 /**
1053 * get RCS provisioning status in specific key and value
1054 * @param key integer key, defined as one of
1055 * {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS}
1056 * {@link ProvisioningManager#KEY_VT_PROVISIONING_STATUS}
1057 * {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE}
1058 * {@link ProvisioningManager#KEY_EAB_PROVISIONING_STATUS}
1059 * @return the result of setting the configuration value, defined as one of
1060 * {@link ImsConfigImplBase#CONFIG_RESULT_FAILED} or
1061 * {@link ImsConfigImplBase#CONFIG_RESULT_SUCCESS} or
1062 * {@link ImsConfigImplBase#CONFIG_RESULT_UNKNOWN}
1063 */
1064 @VisibleForTesting
1065 public int getProvisioningValue(int subId, int key) {
1066 log("getProvisioningValue");
1067
1068 // check key value
1069 if (!Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(keyValue -> keyValue == key)) {
1070 log("not matched key " + key);
1071 return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
1072 }
1073
1074 // check subId
1075 int slotId = getSlotId(subId);
1076 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
1077 loge("Fail to retrieve slotId from subId");
1078 return ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
1079 }
1080
1081 // check data from ImsProvisioningLoader
1082 int capability = getCapabilityFromKey(key);
1083 int tech = getTechFromKey(key);
1084 int result;
1085 if (capability != INVALID_VALUE && tech != INVALID_VALUE) {
1086 if (key == KEY_EAB_PROVISIONING_STATUS) {
1087 result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_RCS,
1088 capability, tech);
1089 } else {
1090 result = mImsProvisioningLoader.getProvisioningStatus(subId, FEATURE_MMTEL,
1091 capability, tech);
1092 }
1093 if (result != ImsProvisioningLoader.STATUS_NOT_SET) {
1094 return result;
1095 }
1096 }
1097
1098 // get data from ImsService, update it in ImsProvisioningLoader
1099 if (key == KEY_EAB_PROVISIONING_STATUS) {
1100 result = getRcsValueFromImsService(subId, capability);
1101 if (result == ImsConfigImplBase.CONFIG_RESULT_UNKNOWN) {
1102 logw("getProvisioningValue : fail to get data from ImsService capability"
1103 + capability);
1104 return result;
1105 }
1106 setAndNotifyRcsProvisioningValueForAllTech(subId, capability, getBoolValue(result));
1107 return result;
1108 } else {
1109 result = getValueFromImsService(subId, capability, tech);
1110 if (result == ImsConfigImplBase.CONFIG_RESULT_UNKNOWN) {
1111 logw("getProvisioningValue : fail to get data from ImsService capability"
1112 + capability);
1113 return result;
1114 }
1115 setAndNotifyMmTelProvisioningValue(subId, capability, tech, getBoolValue(result));
1116 return result;
1117 }
1118 }
1119
1120 /**
1121 * get the handler
1122 */
1123 @VisibleForTesting
1124 public Handler getHandler() {
1125 return mHandler;
1126 }
1127
1128 private boolean isProvisioningRequired(int subId, int capability, int tech, boolean isMmTel) {
1129 String[] dataArray;
1130 if (isMmTel) {
1131 dataArray = getMmTelStringArrayFromCarrierConfig(subId);
1132 } else {
1133 dataArray = getRcsStringArrayFromCarrierConfig(subId);
1134 }
1135 if (dataArray == null) {
1136 logw("isProvisioningRequired : retrieve data from carrier config failed");
1137
1138 // KEY_MMTEL/RCS_REQUIRES_PROVISIONING_STRING_ARRAY is not exist in CarrierConfig that
1139 // means provisioning is not required
1140 return false;
1141 }
1142
1143 // create String with capability and tech
1144 String comp = capability + "," + tech;
1145
1146 // compare with carrier config
1147 for (String data : dataArray) {
1148 // existing same String {capability,tech} means provisioning required
1149 if (data.replaceAll("\\s", "").equals(comp)) {
1150 return true;
1151 }
1152 }
1153
1154 log("isProvisioningRequired : not matched capability " + capability + " tech " + tech);
1155 return false;
1156 }
1157
1158 @VisibleForTesting
1159 protected String[] getMmTelStringArrayFromCarrierConfig(int subId) {
1160 PersistableBundle imsCarrierConfigs = mCarrierConfigManager.getConfigByComponentForSubId(
1161 CarrierConfigManager.Ims.KEY_PREFIX, subId);
1162 return imsCarrierConfigs.getStringArray(
1163 CarrierConfigManager.Ims.KEY_MMTEL_REQUIRES_PROVISIONING_STRING_ARRAY);
1164 }
1165
1166 @VisibleForTesting
1167 protected String[] getRcsStringArrayFromCarrierConfig(int subId) {
1168 PersistableBundle imsCarrierConfigs = mCarrierConfigManager.getConfigByComponentForSubId(
1169 CarrierConfigManager.Ims.KEY_PREFIX, subId);
1170 return imsCarrierConfigs.getStringArray(
1171 CarrierConfigManager.Ims.KEY_RCS_REQUIRES_PROVISIONING_STRING_ARRAY);
1172 }
1173
1174 private int getValueFromImsService(int subId, int capability, int tech) {
1175 int config = ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
1176
1177 // operation is based on capability
1178 switch (capability) {
1179 case CAPABILITY_TYPE_VOICE:
1180 int item = (tech == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN)
1181 ? ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE
1182 : ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS;
1183 // read data from vendor ImsService
1184 config = mMmTelFeatureListenersSlotMap.get(getSlotId(subId))
1185 .getProvisioningValue(item);
1186 break;
1187 case CAPABILITY_TYPE_VIDEO:
1188 // read data from vendor ImsService
1189 config = mMmTelFeatureListenersSlotMap.get(getSlotId(subId))
1190 .getProvisioningValue(ProvisioningManager.KEY_VT_PROVISIONING_STATUS);
1191 break;
1192 default:
1193 log("Capability " + capability + " has been provisioning");
1194 break;
1195 }
1196
1197 return config;
1198 }
1199
1200 private int getRcsValueFromImsService(int subId, int capability) {
1201 int config = ImsConfigImplBase.CONFIG_RESULT_UNKNOWN;
1202
1203 if (capability == CAPABILITY_TYPE_PRESENCE_UCE) {
1204 try {
1205 config = mRcsFeatureListenersSlotMap.get(getSlotId(subId))
1206 .getProvisioningValue(ProvisioningManager.KEY_EAB_PROVISIONING_STATUS);
1207 } catch (NullPointerException e) {
1208 logw("can not access RcsFeatureListener");
1209 }
1210 } else {
1211 log("Capability " + capability + " has been provisioning");
1212 }
1213
1214 return config;
1215 }
1216
1217 private void onSubscriptionsChanged() {
1218 for (int index = 0; index < mMmTelFeatureListenersSlotMap.size(); index++) {
1219 MmTelFeatureListener m = mMmTelFeatureListenersSlotMap.get(index);
1220 m.setSubId(getSubId(index));
1221 }
1222 for (int index = 0; index < mRcsFeatureListenersSlotMap.size(); index++) {
1223 RcsFeatureListener r = mRcsFeatureListenersSlotMap.get(index);
1224 r.setSubId(getSubId(index));
1225 }
1226 for (int index = 0; index < mProvisioningCallbackManagersSlotMap.size(); index++) {
1227 ProvisioningCallbackManager m = mProvisioningCallbackManagersSlotMap.get(index);
1228 m.setSubId(getSubId(index));
1229 }
1230 }
1231
1232 private void updateCapabilityTechFromKey(int subId, int key, int value) {
1233 boolean isProvisioned = getBoolValue(value);
1234 int capability = getCapabilityFromKey(key);
1235 int tech = getTechFromKey(key);
1236
1237 if (capability == INVALID_VALUE || tech == INVALID_VALUE) {
1238 logw("updateCapabilityTechFromKey : unknown key " + key);
1239 return;
1240 }
1241
1242 if (key == KEY_VOLTE_PROVISIONING_STATUS
1243 || key == KEY_VT_PROVISIONING_STATUS
1244 || key == KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE) {
1245 setAndNotifyMmTelProvisioningValue(subId, capability, tech, isProvisioned);
1246 }
1247 if (key == KEY_EAB_PROVISIONING_STATUS) {
1248 setAndNotifyRcsProvisioningValueForAllTech(subId, capability, isProvisioned);
1249 }
1250 }
1251
1252 private int getCapabilityFromKey(int key) {
1253 int capability;
1254 switch (key) {
1255 case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS:
1256 // intentional fallthrough
1257 case ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE:
1258 capability = CAPABILITY_TYPE_VOICE;
1259 break;
1260 case ProvisioningManager.KEY_VT_PROVISIONING_STATUS:
1261 capability = CAPABILITY_TYPE_VIDEO;
1262 break;
1263 case ProvisioningManager.KEY_EAB_PROVISIONING_STATUS:
1264 // default CAPABILITY_TYPE_PRESENCE_UCE used for KEY_EAB_PROVISIONING_STATUS
1265 capability = CAPABILITY_TYPE_PRESENCE_UCE;
1266 break;
1267 default:
1268 capability = INVALID_VALUE;
1269 break;
1270 }
1271 return capability;
1272 }
1273
1274 private int getTechFromKey(int key) {
1275 int tech;
1276 switch (key) {
1277 case ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE:
1278 tech = ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
1279 break;
1280 case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS:
1281 // intentional fallthrough
1282 case ProvisioningManager.KEY_VT_PROVISIONING_STATUS:
1283 // intentional fallthrough
1284 case ProvisioningManager.KEY_EAB_PROVISIONING_STATUS:
1285 tech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
1286 break;
1287 default:
1288 tech = INVALID_VALUE;
1289 break;
1290 }
1291 return tech;
1292 }
1293
1294 private int getKeyFromCapability(int capability, int tech) {
1295 int key = INVALID_VALUE;
1296 if (capability == CAPABILITY_TYPE_VOICE && tech == REGISTRATION_TECH_IWLAN) {
1297 key = ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE;
1298 } else if (capability == CAPABILITY_TYPE_VOICE && tech == REGISTRATION_TECH_LTE) {
1299 key = ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS;
1300 } else if (capability == CAPABILITY_TYPE_VIDEO && tech == REGISTRATION_TECH_LTE) {
1301 key = ProvisioningManager.KEY_VT_PROVISIONING_STATUS;
1302 }
1303
1304 return key;
1305 }
1306
1307 protected int getSubId(int slotId) {
1308 final int[] subIds = mSubscriptionManager.getSubscriptionIds(slotId);
1309 int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1310 if (subIds != null && subIds.length >= 1) {
1311 subId = subIds[0];
1312 }
1313
1314 return subId;
1315 }
1316
1317 protected int getSlotId(int subId) {
1318 return mSubscriptionManager.getPhoneId(subId);
1319 }
1320
1321 protected ImsConfig getImsConfig(ImsManager imsManager) throws ImsException {
1322 return imsManager.getConfigInterface();
1323 }
1324
1325 protected ImsConfig getImsConfig(IImsConfig iImsConfig) {
1326 return new ImsConfig(iImsConfig);
1327 }
1328
1329 private int getIntValue(boolean isProvisioned) {
1330 return isProvisioned ? ProvisioningManager.PROVISIONING_VALUE_ENABLED
1331 : ProvisioningManager.PROVISIONING_VALUE_DISABLED;
1332 }
1333
1334 private boolean getBoolValue(int value) {
1335 return value == ProvisioningManager.PROVISIONING_VALUE_ENABLED ? true : false;
1336 }
1337
1338 private boolean setAndNotifyMmTelProvisioningValue(int subId, int capability, int tech,
1339 boolean isProvisioned) {
1340 boolean changed = mImsProvisioningLoader.setProvisioningStatus(subId, FEATURE_MMTEL,
1341 capability, tech, isProvisioned);
1342 // notify MmTel capability changed
1343 if (changed) {
1344 mHandler.sendMessage(mHandler.obtainMessage(EVENT_PROVISIONING_CAPABILITY_CHANGED,
1345 getSlotId(subId), 0, (Object) new FeatureProvisioningData(
1346 capability, tech, isProvisioned, /*isMmTel*/true)));
1347 }
1348
1349 return changed;
1350 }
1351
1352 private boolean setAndNotifyRcsProvisioningValue(int subId, int capability, int tech,
1353 boolean isProvisioned) {
1354 boolean isChanged = mImsProvisioningLoader.setProvisioningStatus(subId, FEATURE_RCS,
1355 capability, tech, isProvisioned);
1356
1357 if (isChanged) {
1358 int slotId = getSlotId(subId);
1359
1360 // notify RCS capability changed
1361 mHandler.sendMessage(mHandler.obtainMessage(EVENT_PROVISIONING_CAPABILITY_CHANGED,
1362 slotId, 0, (Object) new FeatureProvisioningData(
1363 capability, tech, isProvisioned, /*isMmtel*/false)));
1364 }
1365
1366 return isChanged;
1367 }
1368
1369 private boolean setAndNotifyRcsProvisioningValueForAllTech(int subId, int capability,
1370 boolean isProvisioned) {
1371 boolean isChanged = false;
1372
1373 for (int tech : LOCAL_RADIO_TECHS) {
1374 isChanged |= setAndNotifyRcsProvisioningValue(subId, capability, tech, isProvisioned);
1375 }
1376
1377 return isChanged;
1378 }
1379
1380 private void updateImsServiceConfig(int subId) {
1381 try {
1382 ImsManager imsManager = mMmTelFeatureListenersSlotMap.get(getSlotId(subId))
1383 .getImsManager();
1384 imsManager.updateImsServiceConfig();
1385 log("updateImsServiceConfig");
1386 } catch (NullPointerException e) {
1387 loge("updateImsServiceConfig : ImsService not ready");
1388 }
1389 }
1390
1391 protected boolean isValidSubId(int subId) {
1392 int slotId = getSlotId(subId);
1393 if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlot) {
1394 return false;
1395 }
1396
1397 return true;
1398 }
1399
1400 private void log(String s) {
1401 Rlog.d(TAG, s);
1402 }
1403
1404 private void log(String prefix, int slotId, String s) {
1405 Rlog.d(TAG, prefix + "[" + slotId + "] " + s);
1406 }
1407
1408 private void logi(String prefix, int slotId, String s) {
1409 Rlog.i(TAG, prefix + "[" + slotId + "] " + s);
1410 }
1411
1412 private void logw(String s) {
1413 Rlog.w(TAG, s);
1414 }
1415
1416 private void logw(String prefix, int slotId, String s) {
1417 Rlog.w(TAG, prefix + "[" + slotId + "] " + s);
1418 }
1419
1420 private void loge(String s) {
1421 Rlog.e(TAG, s);
1422 }
1423
1424 private void loge(String prefix, int slotId, String s) {
1425 Rlog.e(TAG, prefix + "[" + slotId + "] " + s);
1426 }
1427}