1 /* 2 * Copyright 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.phone; 18 19 import android.Manifest; 20 import android.app.role.OnRoleHoldersChangedListener; 21 import android.app.role.RoleManager; 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.pm.PackageManager; 27 import android.os.Build; 28 import android.os.Handler; 29 import android.os.HandlerThread; 30 import android.os.Looper; 31 import android.os.Message; 32 import android.os.PersistableBundle; 33 import android.os.RemoteException; 34 import android.os.UserHandle; 35 import android.telephony.CarrierConfigManager; 36 import android.telephony.SubscriptionManager; 37 import android.telephony.TelephonyRegistryManager; 38 import android.telephony.ims.ProvisioningManager; 39 import android.telephony.ims.RcsConfig; 40 import android.telephony.ims.aidl.IImsConfig; 41 import android.telephony.ims.aidl.IRcsConfigCallback; 42 import android.text.TextUtils; 43 import android.util.ArraySet; 44 import android.util.SparseArray; 45 46 import com.android.ims.FeatureConnector; 47 import com.android.ims.FeatureUpdates; 48 import com.android.ims.RcsFeatureManager; 49 import com.android.internal.annotations.VisibleForTesting; 50 import com.android.internal.telephony.util.HandlerExecutor; 51 import com.android.internal.util.CollectionUtils; 52 import com.android.telephony.Rlog; 53 54 import java.util.Arrays; 55 import java.util.HashMap; 56 import java.util.Iterator; 57 import java.util.List; 58 import java.util.concurrent.ConcurrentHashMap; 59 import java.util.concurrent.Executor; 60 61 /** 62 * Class to monitor RCS Provisioning Status 63 */ 64 public class RcsProvisioningMonitor { 65 private static final String TAG = "RcsProvisioningMonitor"; 66 private static final boolean DBG = Build.IS_ENG; 67 68 private static final int EVENT_SUB_CHANGED = 1; 69 private static final int EVENT_DMA_CHANGED = 2; 70 private static final int EVENT_CC_CHANGED = 3; 71 private static final int EVENT_CONFIG_RECEIVED = 4; 72 private static final int EVENT_RECONFIG_REQUEST = 5; 73 private static final int EVENT_DEVICE_CONFIG_OVERRIDE = 6; 74 private static final int EVENT_CARRIER_CONFIG_OVERRIDE = 7; 75 private static final int EVENT_RESET = 8; 76 private static final int EVENT_FEATURE_ENABLED_OVERRIDE = 9; 77 78 private final PhoneGlobals mPhone; 79 private final Handler mHandler; 80 // Cache the RCS provsioning info and related sub id 81 private final ConcurrentHashMap<Integer, RcsProvisioningInfo> mRcsProvisioningInfos = 82 new ConcurrentHashMap<>(); 83 private Boolean mDeviceSingleRegistrationEnabledOverride; 84 private final HashMap<Integer, Boolean> mCarrierSingleRegistrationEnabledOverride = 85 new HashMap<>(); 86 private final ConcurrentHashMap<Integer, Boolean> mImsFeatureValidationOverride = 87 new ConcurrentHashMap<>(); 88 private String mDmaPackageName; 89 private final SparseArray<RcsFeatureListener> mRcsFeatureListeners = new SparseArray<>(); 90 private volatile boolean mTestModeEnabled; 91 92 private final CarrierConfigManager mCarrierConfigManager; 93 private final DmaChangedListener mDmaChangedListener; 94 private final SubscriptionManager mSubscriptionManager; 95 private final TelephonyRegistryManager mTelephonyRegistryManager; 96 private final RoleManagerAdapter mRoleManager; 97 private FeatureConnectorFactory<RcsFeatureManager> mFeatureFactory; 98 99 private static RcsProvisioningMonitor sInstance; 100 101 private final SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener = 102 new SubscriptionManager.OnSubscriptionsChangedListener() { 103 @Override 104 public void onSubscriptionsChanged() { 105 if (!mHandler.hasMessages(EVENT_SUB_CHANGED)) { 106 mHandler.sendEmptyMessage(EVENT_SUB_CHANGED); 107 } 108 } 109 }; 110 111 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 112 @Override 113 public void onReceive(Context context, Intent intent) { 114 if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals( 115 intent.getAction())) { 116 int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, 117 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 118 logv("Carrier-config changed for sub : " + subId); 119 if (SubscriptionManager.isValidSubscriptionId(subId) 120 && !mHandler.hasMessages(EVENT_CC_CHANGED)) { 121 mHandler.sendEmptyMessage(EVENT_CC_CHANGED); 122 } 123 } 124 } 125 }; 126 127 private final class DmaChangedListener implements OnRoleHoldersChangedListener { 128 @Override onRoleHoldersChanged(String role, UserHandle user)129 public void onRoleHoldersChanged(String role, UserHandle user) { 130 if (RoleManager.ROLE_SMS.equals(role)) { 131 logv("default messaging application changed."); 132 mHandler.sendEmptyMessage(EVENT_DMA_CHANGED); 133 } 134 } 135 register()136 public void register() { 137 try { 138 mRoleManager.addOnRoleHoldersChangedListenerAsUser( 139 mPhone.getMainExecutor(), this, UserHandle.SYSTEM); 140 } catch (RuntimeException e) { 141 loge("Could not register dma change listener due to " + e); 142 } 143 } 144 unregister()145 public void unregister() { 146 try { 147 mRoleManager.removeOnRoleHoldersChangedListenerAsUser(this, UserHandle.SYSTEM); 148 } catch (RuntimeException e) { 149 loge("Could not unregister dma change listener due to " + e); 150 } 151 } 152 } 153 154 private final class MyHandler extends Handler { MyHandler(Looper looper)155 MyHandler(Looper looper) { 156 super(looper); 157 } 158 159 @Override handleMessage(Message msg)160 public void handleMessage(Message msg) { 161 logv("handleMessage: " + msg); 162 switch (msg.what) { 163 case EVENT_SUB_CHANGED: 164 onSubChanged(); 165 break; 166 case EVENT_DMA_CHANGED: 167 onDefaultMessagingApplicationChanged(); 168 break; 169 case EVENT_CC_CHANGED: 170 onCarrierConfigChange(); 171 break; 172 case EVENT_CONFIG_RECEIVED: 173 onConfigReceived(msg.arg1, (byte[]) msg.obj, msg.arg2 == 1); 174 break; 175 case EVENT_RECONFIG_REQUEST: 176 onReconfigRequest(msg.arg1); 177 break; 178 case EVENT_DEVICE_CONFIG_OVERRIDE: 179 Boolean deviceEnabled = (Boolean) msg.obj; 180 if (!booleanEquals(deviceEnabled, mDeviceSingleRegistrationEnabledOverride)) { 181 mDeviceSingleRegistrationEnabledOverride = deviceEnabled; 182 onCarrierConfigChange(); 183 } 184 break; 185 case EVENT_CARRIER_CONFIG_OVERRIDE: 186 Boolean carrierEnabledOverride = (Boolean) msg.obj; 187 Boolean carrierEnabled = mCarrierSingleRegistrationEnabledOverride.put( 188 msg.arg1, carrierEnabledOverride); 189 if (!booleanEquals(carrierEnabledOverride, carrierEnabled)) { 190 onCarrierConfigChange(); 191 } 192 break; 193 case EVENT_RESET: 194 reset(); 195 break; 196 default: 197 loge("Unhandled event " + msg.what); 198 } 199 } 200 } 201 202 private final class RcsProvisioningInfo { 203 private int mSubId; 204 private volatile int mSingleRegistrationCapability; 205 private volatile byte[] mConfig; 206 private ArraySet<IRcsConfigCallback> mRcsConfigCallbacks; 207 private IImsConfig mIImsConfig; 208 private boolean mHasReconfigRequest; 209 RcsProvisioningInfo(int subId, int singleRegistrationCapability, byte[] config)210 RcsProvisioningInfo(int subId, int singleRegistrationCapability, byte[] config) { 211 mSubId = subId; 212 mSingleRegistrationCapability = singleRegistrationCapability; 213 mConfig = config; 214 mRcsConfigCallbacks = new ArraySet<>(); 215 registerRcsFeatureListener(this); 216 } 217 getSubId()218 int getSubId() { 219 return mSubId; 220 } 221 setSingleRegistrationCapability(int singleRegistrationCapability)222 void setSingleRegistrationCapability(int singleRegistrationCapability) { 223 mSingleRegistrationCapability = singleRegistrationCapability; 224 } 225 getSingleRegistrationCapability()226 int getSingleRegistrationCapability() { 227 return mSingleRegistrationCapability; 228 } 229 setConfig(byte[] config)230 void setConfig(byte[] config) { 231 if (!Arrays.equals(mConfig, config)) { 232 mConfig = config; 233 if (mConfig != null) { 234 notifyRcsAutoConfigurationReceived(); 235 } else { 236 notifyRcsAutoConfigurationRemoved(); 237 } 238 } 239 } 240 getConfig()241 byte[] getConfig() { 242 return mConfig; 243 } 244 addRcsConfigCallback(IRcsConfigCallback cb)245 boolean addRcsConfigCallback(IRcsConfigCallback cb) { 246 if (mIImsConfig == null) { 247 logd("fail to addRcsConfigCallback as imsConfig is null"); 248 return false; 249 } 250 251 synchronized (mRcsConfigCallbacks) { 252 try { 253 mIImsConfig.addRcsConfigCallback(cb); 254 } catch (RemoteException e) { 255 loge("fail to addRcsConfigCallback due to " + e); 256 return false; 257 } 258 mRcsConfigCallbacks.add(cb); 259 } 260 return true; 261 } 262 removeRcsConfigCallback(IRcsConfigCallback cb)263 boolean removeRcsConfigCallback(IRcsConfigCallback cb) { 264 boolean result = true; 265 266 synchronized (mRcsConfigCallbacks) { 267 if (mIImsConfig != null) { 268 try { 269 mIImsConfig.removeRcsConfigCallback(cb); 270 } catch (RemoteException e) { 271 loge("fail to removeRcsConfigCallback due to " + e); 272 } 273 } else { 274 // Return false but continue to remove the callback 275 result = false; 276 } 277 278 try { 279 cb.onRemoved(); 280 } catch (RemoteException e) { 281 logd("Failed to notify onRemoved due to dead binder of " + cb); 282 } 283 mRcsConfigCallbacks.remove(cb); 284 } 285 return result; 286 } 287 triggerRcsReconfiguration()288 void triggerRcsReconfiguration() { 289 if (mIImsConfig != null) { 290 try { 291 logv("triggerRcsReconfiguration for sub:" + mSubId); 292 mIImsConfig.triggerRcsReconfiguration(); 293 mHasReconfigRequest = false; 294 } catch (RemoteException e) { 295 loge("triggerRcsReconfiguration failed due to " + e); 296 } 297 } else { 298 logd("triggerRcsReconfiguration failed due to IImsConfig null."); 299 mHasReconfigRequest = true; 300 } 301 } 302 destroy()303 void destroy() { 304 unregisterRcsFeatureListener(this); 305 clear(); 306 mIImsConfig = null; 307 mRcsConfigCallbacks = null; 308 } 309 clear()310 void clear() { 311 setConfig(null); 312 clearCallbacks(); 313 } 314 onRcsStatusChanged(IImsConfig binder)315 void onRcsStatusChanged(IImsConfig binder) { 316 logv("onRcsStatusChanged for sub:" + mSubId + ", IImsConfig?" + binder); 317 if (mIImsConfig != binder) { 318 mIImsConfig = binder; 319 if (mIImsConfig != null) { 320 if (mHasReconfigRequest) { 321 triggerRcsReconfiguration(); 322 } else { 323 notifyRcsAutoConfigurationReceived(); 324 } 325 } else { 326 // clear callbacks if rcs disconnected 327 clearCallbacks(); 328 } 329 } 330 } 331 notifyRcsAutoConfigurationReceived()332 private void notifyRcsAutoConfigurationReceived() { 333 if (mConfig == null) { 334 logd("Rcs config is null for sub : " + mSubId); 335 return; 336 } 337 338 if (mIImsConfig != null) { 339 try { 340 logv("notifyRcsAutoConfigurationReceived for sub:" + mSubId); 341 mIImsConfig.notifyRcsAutoConfigurationReceived(mConfig, false); 342 } catch (RemoteException e) { 343 loge("notifyRcsAutoConfigurationReceived failed due to " + e); 344 } 345 } else { 346 logd("notifyRcsAutoConfigurationReceived failed due to IImsConfig null."); 347 } 348 } 349 notifyRcsAutoConfigurationRemoved()350 private void notifyRcsAutoConfigurationRemoved() { 351 if (mIImsConfig != null) { 352 try { 353 logv("notifyRcsAutoConfigurationRemoved for sub:" + mSubId); 354 mIImsConfig.notifyRcsAutoConfigurationRemoved(); 355 } catch (RemoteException e) { 356 loge("notifyRcsAutoConfigurationRemoved failed due to " + e); 357 } 358 } else { 359 logd("notifyRcsAutoConfigurationRemoved failed due to IImsConfig null."); 360 } 361 } 362 clearCallbacks()363 private void clearCallbacks() { 364 synchronized (mRcsConfigCallbacks) { 365 Iterator<IRcsConfigCallback> it = mRcsConfigCallbacks.iterator(); 366 while (it.hasNext()) { 367 IRcsConfigCallback cb = it.next(); 368 if (mIImsConfig != null) { 369 try { 370 mIImsConfig.removeRcsConfigCallback(cb); 371 } catch (RemoteException e) { 372 loge("fail to removeRcsConfigCallback due to " + e); 373 } 374 } 375 try { 376 cb.onRemoved(); 377 } catch (RemoteException e) { 378 logd("Failed to notify onRemoved due to dead binder of " + cb); 379 } 380 it.remove(); 381 } 382 } 383 } 384 } 385 386 @VisibleForTesting 387 public interface FeatureConnectorFactory<U extends FeatureUpdates> { 388 /** 389 * @return a {@link FeatureConnector} associated for the given {@link FeatureUpdates} 390 * and slot index. 391 */ create(Context context, int slotIndex, FeatureConnector.Listener<U> listener, Executor executor, String logPrefix)392 FeatureConnector<U> create(Context context, int slotIndex, 393 FeatureConnector.Listener<U> listener, Executor executor, String logPrefix); 394 } 395 396 private final class RcsFeatureListener implements FeatureConnector.Listener<RcsFeatureManager> { 397 private final ArraySet<RcsProvisioningInfo> mRcsProvisioningInfos = new ArraySet<>(); 398 private RcsFeatureManager mRcsFeatureManager; 399 private FeatureConnector<RcsFeatureManager> mConnector; 400 RcsFeatureListener(int slotId)401 RcsFeatureListener(int slotId) { 402 mConnector = mFeatureFactory.create( 403 mPhone, slotId, this, new HandlerExecutor(mHandler), TAG); 404 mConnector.connect(); 405 } 406 destroy()407 void destroy() { 408 mConnector.disconnect(); 409 mConnector = null; 410 mRcsFeatureManager = null; 411 mRcsProvisioningInfos.clear(); 412 } 413 addRcsProvisioningInfo(RcsProvisioningInfo info)414 void addRcsProvisioningInfo(RcsProvisioningInfo info) { 415 if (!mRcsProvisioningInfos.contains(info)) { 416 mRcsProvisioningInfos.add(info); 417 info.onRcsStatusChanged(mRcsFeatureManager == null ? null 418 : mRcsFeatureManager.getConfig()); 419 } 420 } 421 removeRcsProvisioningInfo(RcsProvisioningInfo info)422 void removeRcsProvisioningInfo(RcsProvisioningInfo info) { 423 mRcsProvisioningInfos.remove(info); 424 } 425 426 @Override connectionReady(RcsFeatureManager manager)427 public void connectionReady(RcsFeatureManager manager) { 428 mRcsFeatureManager = manager; 429 mRcsProvisioningInfos.forEach(v -> v.onRcsStatusChanged(manager.getConfig())); 430 } 431 432 @Override connectionUnavailable(int reason)433 public void connectionUnavailable(int reason) { 434 mRcsFeatureManager = null; 435 mRcsProvisioningInfos.forEach(v -> v.onRcsStatusChanged(null)); 436 } 437 } 438 439 @VisibleForTesting RcsProvisioningMonitor(PhoneGlobals app, Looper looper, RoleManagerAdapter roleManager, FeatureConnectorFactory<RcsFeatureManager> factory)440 public RcsProvisioningMonitor(PhoneGlobals app, Looper looper, RoleManagerAdapter roleManager, 441 FeatureConnectorFactory<RcsFeatureManager> factory) { 442 mPhone = app; 443 mHandler = new MyHandler(looper); 444 mCarrierConfigManager = mPhone.getSystemService(CarrierConfigManager.class); 445 mSubscriptionManager = mPhone.getSystemService(SubscriptionManager.class); 446 mTelephonyRegistryManager = mPhone.getSystemService(TelephonyRegistryManager.class); 447 mRoleManager = roleManager; 448 mDmaPackageName = getDmaPackageName(); 449 logv("DMA is " + mDmaPackageName); 450 mDmaChangedListener = new DmaChangedListener(); 451 mFeatureFactory = factory; 452 init(); 453 } 454 455 /** 456 * create an instance 457 */ make(PhoneGlobals app)458 public static RcsProvisioningMonitor make(PhoneGlobals app) { 459 if (sInstance == null) { 460 logd("RcsProvisioningMonitor created."); 461 HandlerThread handlerThread = new HandlerThread(TAG); 462 handlerThread.start(); 463 sInstance = new RcsProvisioningMonitor(app, handlerThread.getLooper(), 464 new RoleManagerAdapterImpl(app), RcsFeatureManager::getConnector); 465 } 466 return sInstance; 467 } 468 469 /** 470 * get the instance 471 */ getInstance()472 public static RcsProvisioningMonitor getInstance() { 473 return sInstance; 474 } 475 init()476 private void init() { 477 logd("init."); 478 IntentFilter filter = new IntentFilter(); 479 filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 480 mPhone.registerReceiver(mReceiver, filter); 481 mTelephonyRegistryManager.addOnSubscriptionsChangedListener( 482 mSubChangedListener, mSubChangedListener.getHandlerExecutor()); 483 mDmaChangedListener.register(); 484 //initialize configs for all active sub 485 onSubChanged(); 486 } 487 release()488 private void release() { 489 logd("release."); 490 mDmaChangedListener.unregister(); 491 mTelephonyRegistryManager.removeOnSubscriptionsChangedListener(mSubChangedListener); 492 mPhone.unregisterReceiver(mReceiver); 493 for (int i = 0; i < mRcsFeatureListeners.size(); i++) { 494 mRcsFeatureListeners.valueAt(i).destroy(); 495 } 496 mRcsFeatureListeners.clear(); 497 mRcsProvisioningInfos.forEach((k, v)->v.destroy()); 498 mRcsProvisioningInfos.clear(); 499 mCarrierSingleRegistrationEnabledOverride.clear(); 500 } 501 reset()502 private void reset() { 503 release(); 504 init(); 505 } 506 507 /** 508 * destroy the instance 509 */ 510 @VisibleForTesting destroy()511 public void destroy() { 512 logd("destroy it."); 513 release(); 514 mHandler.getLooper().quit(); 515 } 516 517 /** 518 * get the handler 519 */ 520 @VisibleForTesting getHandler()521 public Handler getHandler() { 522 return mHandler; 523 } 524 525 /** 526 * Gets the config for a subscription 527 */ 528 @VisibleForTesting getConfig(int subId)529 public byte[] getConfig(int subId) { 530 if (mRcsProvisioningInfos.containsKey(subId)) { 531 return mRcsProvisioningInfos.get(subId).getConfig(); 532 } 533 return null; 534 } 535 536 /** 537 * Returns whether Rcs Volte single registration is enabled for the sub. 538 */ isRcsVolteSingleRegistrationEnabled(int subId)539 public Boolean isRcsVolteSingleRegistrationEnabled(int subId) { 540 if (mRcsProvisioningInfos.containsKey(subId)) { 541 return mRcsProvisioningInfos.get(subId).getSingleRegistrationCapability() 542 == ProvisioningManager.STATUS_CAPABLE; 543 } 544 return null; 545 } 546 547 /** 548 * Called when the new rcs config is received 549 */ updateConfig(int subId, byte[] config, boolean isCompressed)550 public void updateConfig(int subId, byte[] config, boolean isCompressed) { 551 mHandler.sendMessage(mHandler.obtainMessage( 552 EVENT_CONFIG_RECEIVED, subId, isCompressed ? 1 : 0, config)); 553 } 554 555 /** 556 * Called when the application needs rcs re-config 557 */ requestReconfig(int subId)558 public void requestReconfig(int subId) { 559 mHandler.sendMessage(mHandler.obtainMessage(EVENT_RECONFIG_REQUEST, subId, 0)); 560 } 561 562 /** 563 * Called when the application registers rcs provisioning callback 564 */ registerRcsProvisioningCallback(int subId, IRcsConfigCallback cb)565 public boolean registerRcsProvisioningCallback(int subId, IRcsConfigCallback cb) { 566 RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId); 567 // should not happen in normal case 568 if (info == null) { 569 logd("fail to register rcs provisioning callback due to subscription unavailable"); 570 return false; 571 } 572 573 return info.addRcsConfigCallback(cb); 574 } 575 576 /** 577 * Called when the application unregisters rcs provisioning callback 578 */ unregisterRcsProvisioningCallback(int subId, IRcsConfigCallback cb)579 public boolean unregisterRcsProvisioningCallback(int subId, IRcsConfigCallback cb) { 580 RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId); 581 // should not happen in normal case 582 if (info == null) { 583 logd("fail to unregister rcs provisioning changed due to subscription unavailable"); 584 return false; 585 } 586 587 return info.removeRcsConfigCallback(cb); 588 } 589 590 /** 591 * Enables or disables test mode. 592 * 593 * <p> If test mode is enabled, any rcs config change will not update the database. 594 */ setTestModeEnabled(boolean enabled)595 public void setTestModeEnabled(boolean enabled) { 596 logv("setTestModeEnabled as " + enabled); 597 if (mTestModeEnabled != enabled) { 598 mTestModeEnabled = enabled; 599 mHandler.sendMessage(mHandler.obtainMessage(EVENT_RESET)); 600 } 601 } 602 603 604 /** 605 * Returns whether the test mode is enabled. 606 */ getTestModeEnabled()607 public boolean getTestModeEnabled() { 608 return mTestModeEnabled; 609 } 610 611 /** 612 * override the device config whether single registration is enabled 613 */ overrideDeviceSingleRegistrationEnabled(Boolean enabled)614 public void overrideDeviceSingleRegistrationEnabled(Boolean enabled) { 615 mHandler.sendMessage(mHandler.obtainMessage(EVENT_DEVICE_CONFIG_OVERRIDE, enabled)); 616 } 617 618 /** 619 * Overrides the carrier config whether single registration is enabled 620 */ overrideCarrierSingleRegistrationEnabled(int subId, Boolean enabled)621 public boolean overrideCarrierSingleRegistrationEnabled(int subId, Boolean enabled) { 622 if (!mRcsProvisioningInfos.containsKey(subId)) { 623 return false; 624 } 625 mHandler.sendMessage(mHandler.obtainMessage( 626 EVENT_CARRIER_CONFIG_OVERRIDE, subId, 0, enabled)); 627 return true; 628 } 629 630 /** 631 * override the rcs feature validation result for a subscription 632 */ overrideImsFeatureValidation(int subId, Boolean enabled)633 public boolean overrideImsFeatureValidation(int subId, Boolean enabled) { 634 if (enabled == null) { 635 mImsFeatureValidationOverride.remove(subId); 636 } else { 637 mImsFeatureValidationOverride.put(subId, enabled); 638 } 639 return true; 640 } 641 642 /** 643 * Returns the device config whether single registration is enabled 644 */ getDeviceSingleRegistrationEnabled()645 public boolean getDeviceSingleRegistrationEnabled() { 646 for (RcsProvisioningInfo info : mRcsProvisioningInfos.values()) { 647 return (info.getSingleRegistrationCapability() 648 & ProvisioningManager.STATUS_DEVICE_NOT_CAPABLE) == 0; 649 } 650 return false; 651 } 652 653 /** 654 * Returns the carrier config whether single registration is enabled 655 */ getCarrierSingleRegistrationEnabled(int subId)656 public boolean getCarrierSingleRegistrationEnabled(int subId) { 657 if (mRcsProvisioningInfos.containsKey(subId)) { 658 return (mRcsProvisioningInfos.get(subId).getSingleRegistrationCapability() 659 & ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE) == 0; 660 } 661 return false; 662 } 663 664 /** 665 * Returns the rcs feature validation override value, null if it is not set. 666 */ getImsFeatureValidationOverride(int subId)667 public Boolean getImsFeatureValidationOverride(int subId) { 668 return mImsFeatureValidationOverride.get(subId); 669 } 670 onDefaultMessagingApplicationChanged()671 private void onDefaultMessagingApplicationChanged() { 672 final String packageName = getDmaPackageName(); 673 if (!TextUtils.equals(mDmaPackageName, packageName)) { 674 mDmaPackageName = packageName; 675 logv("new default messaging application " + mDmaPackageName); 676 677 mRcsProvisioningInfos.forEach((k, v) -> { 678 notifyDmaForSub(k, v.getSingleRegistrationCapability()); 679 680 byte[] cachedConfig = v.getConfig(); 681 //clear old callbacks 682 v.clear(); 683 if (isAcsUsed(k)) { 684 logv("acs used, trigger to re-configure."); 685 updateConfigForSub(k, null, true); 686 v.triggerRcsReconfiguration(); 687 } else { 688 logv("acs not used, set cached config and notify."); 689 v.setConfig(cachedConfig); 690 } 691 }); 692 } 693 } 694 updateConfigForSub(int subId, byte[] config, boolean isCompressed)695 private void updateConfigForSub(int subId, byte[] config, boolean isCompressed) { 696 logv("updateConfigForSub, subId:" + subId + ", mTestModeEnabled:" + mTestModeEnabled); 697 if (!mTestModeEnabled) { 698 RcsConfig.updateConfigForSub(mPhone, subId, config, isCompressed); 699 } 700 } 701 loadConfigForSub(int subId)702 private byte[] loadConfigForSub(int subId) { 703 logv("loadConfigForSub, subId:" + subId + ", mTestModeEnabled:" + mTestModeEnabled); 704 if (!mTestModeEnabled) { 705 return RcsConfig.loadRcsConfigForSub(mPhone, subId, false); 706 } 707 return null; 708 } 709 isAcsUsed(int subId)710 private boolean isAcsUsed(int subId) { 711 PersistableBundle b = mCarrierConfigManager.getConfigForSubId(subId); 712 if (b == null) { 713 return false; 714 } 715 return b.getBoolean(CarrierConfigManager.KEY_USE_ACS_FOR_RCS_BOOL); 716 } 717 isSingleRegistrationRequiredByCarrier(int subId)718 private boolean isSingleRegistrationRequiredByCarrier(int subId) { 719 Boolean enabledByOverride = mCarrierSingleRegistrationEnabledOverride.get(subId); 720 if (enabledByOverride != null) { 721 return enabledByOverride; 722 } 723 724 PersistableBundle b = mCarrierConfigManager.getConfigForSubId(subId); 725 if (b == null) { 726 return false; 727 } 728 return b.getBoolean(CarrierConfigManager.Ims.KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL); 729 } 730 getSingleRegistrationCapableValue(int subId)731 private int getSingleRegistrationCapableValue(int subId) { 732 boolean isSingleRegistrationEnabledOnDevice = 733 mDeviceSingleRegistrationEnabledOverride != null 734 ? mDeviceSingleRegistrationEnabledOverride 735 : mPhone.getPackageManager().hasSystemFeature( 736 PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION); 737 738 int value = (isSingleRegistrationEnabledOnDevice ? 0 739 : ProvisioningManager.STATUS_DEVICE_NOT_CAPABLE) | ( 740 isSingleRegistrationRequiredByCarrier(subId) ? 0 741 : ProvisioningManager.STATUS_CARRIER_NOT_CAPABLE); 742 logv("SingleRegistrationCapableValue : " + value); 743 return value; 744 } 745 onCarrierConfigChange()746 private void onCarrierConfigChange() { 747 logv("onCarrierConfigChange"); 748 mRcsProvisioningInfos.forEach((subId, info) -> { 749 int value = getSingleRegistrationCapableValue(subId); 750 if (value != info.getSingleRegistrationCapability()) { 751 info.setSingleRegistrationCapability(value); 752 notifyDmaForSub(subId, value); 753 } 754 }); 755 } 756 onSubChanged()757 private void onSubChanged() { 758 final int[] activeSubs = mSubscriptionManager.getActiveSubscriptionIdList(); 759 final ArraySet<Integer> subsToBeDeactivated = 760 new ArraySet<>(mRcsProvisioningInfos.keySet()); 761 762 for (int i : activeSubs) { 763 subsToBeDeactivated.remove(i); 764 if (!mRcsProvisioningInfos.containsKey(i)) { 765 byte[] data = loadConfigForSub(i); 766 int capability = getSingleRegistrationCapableValue(i); 767 logv("new info is created for sub : " + i + ", single registration capability :" 768 + capability + ", rcs config : " + data); 769 mRcsProvisioningInfos.put(i, new RcsProvisioningInfo(i, capability, data)); 770 notifyDmaForSub(i, capability); 771 } 772 } 773 774 subsToBeDeactivated.forEach(i -> { 775 RcsProvisioningInfo info = mRcsProvisioningInfos.remove(i); 776 if (info != null) { 777 info.destroy(); 778 } 779 }); 780 } 781 onConfigReceived(int subId, byte[] config, boolean isCompressed)782 private void onConfigReceived(int subId, byte[] config, boolean isCompressed) { 783 logv("onConfigReceived, subId:" + subId + ", config:" 784 + config + ", isCompressed:" + isCompressed); 785 RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId); 786 info.setConfig(isCompressed ? RcsConfig.decompressGzip(config) : config); 787 updateConfigForSub(subId, config, isCompressed); 788 } 789 onReconfigRequest(int subId)790 private void onReconfigRequest(int subId) { 791 logv("onReconfigRequest, subId:" + subId); 792 RcsProvisioningInfo info = mRcsProvisioningInfos.get(subId); 793 if (info != null) { 794 info.setConfig(null); 795 // clear rcs config stored in db 796 updateConfigForSub(subId, null, true); 797 info.triggerRcsReconfiguration(); 798 } 799 } 800 notifyDmaForSub(int subId, int capability)801 private void notifyDmaForSub(int subId, int capability) { 802 final Intent intent = new Intent( 803 ProvisioningManager.ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE); 804 intent.setPackage(mDmaPackageName); 805 intent.putExtra(ProvisioningManager.EXTRA_SUBSCRIPTION_ID, subId); 806 intent.putExtra(ProvisioningManager.EXTRA_STATUS, capability); 807 logv("notify " + intent + ", sub:" + subId + ", capability:" + capability); 808 // Only send permission to the default sms app if it has the correct permissions 809 // except test mode enabled 810 if (!mTestModeEnabled) { 811 mPhone.sendBroadcast(intent, Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION); 812 } else { 813 mPhone.sendBroadcast(intent); 814 } 815 } 816 getDmaPackageName()817 private String getDmaPackageName() { 818 try { 819 return CollectionUtils.firstOrNull(mRoleManager.getRoleHolders(RoleManager.ROLE_SMS)); 820 } catch (RuntimeException e) { 821 loge("Could not get dma name due to " + e); 822 return null; 823 } 824 } 825 registerRcsFeatureListener(RcsProvisioningInfo info)826 void registerRcsFeatureListener(RcsProvisioningInfo info) { 827 int slotId = SubscriptionManager.getSlotIndex(info.getSubId()); 828 RcsFeatureListener cb = mRcsFeatureListeners.get(slotId); 829 if (cb == null) { 830 cb = new RcsFeatureListener(slotId); 831 mRcsFeatureListeners.put(slotId, cb); 832 } 833 cb.addRcsProvisioningInfo(info); 834 } 835 unregisterRcsFeatureListener(RcsProvisioningInfo info)836 void unregisterRcsFeatureListener(RcsProvisioningInfo info) { 837 // make sure the info to be removed in any case, even the slotId changed or invalid. 838 for (int i = 0; i < mRcsFeatureListeners.size(); i++) { 839 mRcsFeatureListeners.valueAt(i).removeRcsProvisioningInfo(info); 840 } 841 } 842 booleanEquals(Boolean val1, Boolean val2)843 private static boolean booleanEquals(Boolean val1, Boolean val2) { 844 return (val1 == null && val2 == null) 845 || (Boolean.TRUE.equals(val1) && Boolean.TRUE.equals(val2)) 846 || (Boolean.FALSE.equals(val1) && Boolean.FALSE.equals(val2)); 847 } 848 logv(String msg)849 private static void logv(String msg) { 850 if (DBG) { 851 Rlog.d(TAG, msg); 852 } 853 } 854 logd(String msg)855 private static void logd(String msg) { 856 Rlog.d(TAG, msg); 857 } 858 loge(String msg)859 private static void loge(String msg) { 860 Rlog.e(TAG, msg); 861 } 862 863 /** 864 * {@link RoleManager} is final so we have to wrap the implementation for testing. 865 */ 866 @VisibleForTesting 867 public interface RoleManagerAdapter { 868 /** See {@link RoleManager#getRoleHolders(String)} */ getRoleHolders(String roleName)869 List<String> getRoleHolders(String roleName); 870 /** See {@link RoleManager#addOnRoleHoldersChangedListenerAsUser} */ addOnRoleHoldersChangedListenerAsUser(Executor executor, OnRoleHoldersChangedListener listener, UserHandle user)871 void addOnRoleHoldersChangedListenerAsUser(Executor executor, 872 OnRoleHoldersChangedListener listener, UserHandle user); 873 /** See {@link RoleManager#removeOnRoleHoldersChangedListenerAsUser} */ removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener listener, UserHandle user)874 void removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener listener, 875 UserHandle user); 876 } 877 878 private static class RoleManagerAdapterImpl implements RoleManagerAdapter { 879 private final RoleManager mRoleManager; 880 RoleManagerAdapterImpl(Context context)881 private RoleManagerAdapterImpl(Context context) { 882 mRoleManager = context.getSystemService(RoleManager.class); 883 } 884 885 @Override getRoleHolders(String roleName)886 public List<String> getRoleHolders(String roleName) { 887 return mRoleManager.getRoleHolders(roleName); 888 } 889 890 @Override addOnRoleHoldersChangedListenerAsUser(Executor executor, OnRoleHoldersChangedListener listener, UserHandle user)891 public void addOnRoleHoldersChangedListenerAsUser(Executor executor, 892 OnRoleHoldersChangedListener listener, UserHandle user) { 893 mRoleManager.addOnRoleHoldersChangedListenerAsUser(executor, listener, user); 894 } 895 896 @Override removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener listener, UserHandle user)897 public void removeOnRoleHoldersChangedListenerAsUser(OnRoleHoldersChangedListener listener, 898 UserHandle user) { 899 mRoleManager.removeOnRoleHoldersChangedListenerAsUser(listener, user); 900 } 901 } 902 } 903