• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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