1 /*
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 
17 package com.android.telephony.qns;
18 
19 import static android.telephony.SubscriptionManager.EXTRA_SLOT_INDEX;
20 import static android.telephony.ims.ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED;
21 import static android.telephony.ims.ImsMmTelManager.WIFI_MODE_WIFI_ONLY;
22 import static android.telephony.ims.ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED;
23 
24 import static com.android.telephony.qns.wfc.WfcActivationHelper.ACTION_TRY_WFC_CONNECTION;
25 import static com.android.telephony.qns.wfc.WfcActivationHelper.EXTRA_SUB_ID;
26 import static com.android.telephony.qns.wfc.WfcActivationHelper.EXTRA_TRY_STATUS;
27 import static com.android.telephony.qns.wfc.WfcActivationHelper.STATUS_START;
28 
29 import android.annotation.IntDef;
30 import android.content.BroadcastReceiver;
31 import android.content.ContentResolver;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.IntentFilter;
35 import android.database.ContentObserver;
36 import android.net.Uri;
37 import android.net.wifi.WifiManager;
38 import android.os.Handler;
39 import android.os.HandlerThread;
40 import android.os.Looper;
41 import android.os.Message;
42 import android.provider.Settings;
43 import android.telephony.CarrierConfigManager;
44 import android.telephony.SubscriptionManager;
45 import android.telephony.TelephonyManager;
46 import android.telephony.ims.ProvisioningManager;
47 import android.util.Log;
48 import android.util.SparseArray;
49 
50 import com.android.internal.annotations.VisibleForTesting;
51 import com.android.internal.telephony.TelephonyIntents;
52 
53 import java.util.HashSet;
54 import java.util.List;
55 import java.util.Set;
56 
57 /** QnsEventDispatcher Delivers Broadcasted Intent & change on setting to registered Handlers. */
58 class QnsEventDispatcher {
59 
60     @IntDef(
61             prefix = {"QNS_EVENT_"},
62             value = {
63                 QNS_EVENT_BASE,
64                 QNS_EVENT_CARRIER_CONFIG_CHANGED,
65                 QNS_EVENT_CARRIER_CONFIG_UNKNOWN_CARRIER,
66                 QNS_EVENT_WIFI_DISABLING,
67                 QNS_EVENT_WIFI_AP_CHANGED,
68                 QNS_EVENT_APM_DISABLED,
69                 QNS_EVENT_APM_ENABLED,
70                 QNS_EVENT_WFC_ENABLED,
71                 QNS_EVENT_WFC_DISABLED,
72                 QNS_EVENT_WFC_MODE_TO_WIFI_ONLY,
73                 QNS_EVENT_WFC_MODE_TO_CELLULAR_PREFERRED,
74                 QNS_EVENT_WFC_MODE_TO_WIFI_PREFERRED,
75                 QNS_EVENT_WFC_ROAMING_ENABLED,
76                 QNS_EVENT_WFC_ROAMING_DISABLED,
77                 QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_ONLY,
78                 QNS_EVENT_WFC_ROAMING_MODE_TO_CELLULAR_PREFERRED,
79                 QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_PREFERRED,
80                 QNS_EVENT_CROSS_SIM_CALLING_ENABLED,
81                 QNS_EVENT_CROSS_SIM_CALLING_DISABLED,
82                 QNS_EVENT_EMERGENCY_CALLBACK_MODE_ON,
83                 QNS_EVENT_EMERGENCY_CALLBACK_MODE_OFF,
84                 QNS_EVENT_WFC_PLATFORM_ENABLED,
85                 QNS_EVENT_WFC_PLATFORM_DISABLED,
86                 QNS_EVENT_SIM_ABSENT,
87                 QNS_EVENT_SIM_LOADED,
88                 QNS_EVENT_WIFI_ENABLED,
89             })
90     @interface QnsEventType {}
91 
92     static final int QNS_EVENT_BASE = 0;
93     static final int QNS_EVENT_CARRIER_CONFIG_CHANGED = QNS_EVENT_BASE + 1;
94     static final int QNS_EVENT_CARRIER_CONFIG_UNKNOWN_CARRIER = QNS_EVENT_BASE + 2;
95     static final int QNS_EVENT_WIFI_DISABLING = QNS_EVENT_BASE + 3;
96     static final int QNS_EVENT_WIFI_AP_CHANGED = QNS_EVENT_BASE + 4;
97     static final int QNS_EVENT_APM_DISABLED = QNS_EVENT_BASE + 5;
98     static final int QNS_EVENT_APM_ENABLED = QNS_EVENT_BASE + 6;
99     static final int QNS_EVENT_WFC_ENABLED = QNS_EVENT_BASE + 7;
100     static final int QNS_EVENT_WFC_DISABLED = QNS_EVENT_BASE + 8;
101     static final int QNS_EVENT_WFC_MODE_TO_WIFI_ONLY = QNS_EVENT_BASE + 9;
102     static final int QNS_EVENT_WFC_MODE_TO_CELLULAR_PREFERRED = QNS_EVENT_BASE + 10;
103     static final int QNS_EVENT_WFC_MODE_TO_WIFI_PREFERRED = QNS_EVENT_BASE + 11;
104     static final int QNS_EVENT_WFC_ROAMING_ENABLED = QNS_EVENT_BASE + 12;
105     static final int QNS_EVENT_WFC_ROAMING_DISABLED = QNS_EVENT_BASE + 13;
106     static final int QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_ONLY = QNS_EVENT_BASE + 14;
107     static final int QNS_EVENT_WFC_ROAMING_MODE_TO_CELLULAR_PREFERRED = QNS_EVENT_BASE + 15;
108     static final int QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_PREFERRED = QNS_EVENT_BASE + 16;
109     static final int QNS_EVENT_CROSS_SIM_CALLING_ENABLED = QNS_EVENT_BASE + 17;
110     static final int QNS_EVENT_CROSS_SIM_CALLING_DISABLED = QNS_EVENT_BASE + 18;
111     static final int QNS_EVENT_EMERGENCY_CALLBACK_MODE_ON = QNS_EVENT_BASE + 19;
112     static final int QNS_EVENT_EMERGENCY_CALLBACK_MODE_OFF = QNS_EVENT_BASE + 20;
113     static final int QNS_EVENT_WFC_PLATFORM_ENABLED = QNS_EVENT_BASE + 21;
114     static final int QNS_EVENT_WFC_PLATFORM_DISABLED = QNS_EVENT_BASE + 22;
115     static final int QNS_EVENT_SIM_ABSENT = QNS_EVENT_BASE + 23;
116     static final int QNS_EVENT_SIM_LOADED = QNS_EVENT_BASE + 24;
117     static final int QNS_EVENT_WIFI_ENABLED = QNS_EVENT_BASE + 25;
118     static final int QNS_EVENT_TRY_WFC_ACTIVATION = QNS_EVENT_BASE + 100;
119     static final int QNS_EVENT_CANCEL_TRY_WFC_ACTIVATION = QNS_EVENT_BASE + 101;
120     private static final int EVENT_PROVISIONING_INFO_CHANGED = QNS_EVENT_BASE + 200;
121     private static Boolean sIsAirplaneModeOn;
122     private static int sWiFiState = WifiManager.WIFI_STATE_UNKNOWN;
123     private final String mLogTag;
124     private final Context mContext;
125     private final int mSlotIndex;
126     SparseArray<Set<Handler>> mEventHandlers = new SparseArray<>();
127     private int mSubId;
128     private Uri mCrossSimCallingUri;
129     private Uri mWfcEnabledUri;
130     private Uri mWfcModeUri;
131     private Uri mWfcRoamingEnabledUri;
132     private Uri mWfcRoamingModeUri;
133     @VisibleForTesting UserSettingObserver mUserSettingObserver;
134     private HandlerThread mUserSettingHandlerThread;
135     boolean mLastWfcEnabledByPlatform = false;
136     boolean mLastCrossSimCallingEnabled = false;
137     boolean mLastWfcEnabled = false;
138     int mLastWfcMode = WIFI_MODE_CELLULAR_PREFERRED;
139     boolean mLastWfcRoamingEnabled = false;
140     int mLastWfcModeRoaming = WIFI_MODE_WIFI_PREFERRED;
141     protected final QnsProvisioningListener mQnsProvisioningListener;
142     protected final QnsImsManager mQnsImsManager;
143     private QnsProvisioningListener.QnsProvisioningInfo mLastProvisioningInfo;
144     @VisibleForTesting final QnsEventDispatcherHandler mQnsEventDispatcherHandler;
145 
146     @VisibleForTesting
147     final BroadcastReceiver mIntentReceiver =
148             new BroadcastReceiver() {
149                 @Override
150                 public void onReceive(Context context, Intent intent) {
151                     String action = intent.getAction();
152                     int event;
153                     Log.d(mLogTag, "onReceive: " + action);
154                     switch (action) {
155                         case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
156                             int slotId =
157                                     intent.getIntExtra(
158                                             CarrierConfigManager.EXTRA_SLOT_INDEX,
159                                             SubscriptionManager.INVALID_SIM_SLOT_INDEX);
160                             int carrierId =
161                                     intent.getIntExtra(
162                                             TelephonyManager.EXTRA_CARRIER_ID,
163                                             TelephonyManager.UNKNOWN_CARRIER_ID);
164 
165                             onCarrierConfigChanged(context, slotId, carrierId);
166                             break;
167 
168                         case TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED:
169                         case TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED:
170                             slotId =
171                                     intent.getIntExtra(
172                                             CarrierConfigManager.EXTRA_SLOT_INDEX,
173                                             SubscriptionManager.INVALID_SIM_SLOT_INDEX);
174                             int simState =
175                                     intent.getIntExtra(
176                                             TelephonyManager.EXTRA_SIM_STATE,
177                                             TelephonyManager.SIM_STATE_UNKNOWN);
178                             onSimStateChanged(slotId, simState);
179                             break;
180 
181                         case Intent.ACTION_AIRPLANE_MODE_CHANGED:
182                             Boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
183                             if (sIsAirplaneModeOn != null
184                                     && sIsAirplaneModeOn.equals(isAirplaneModeOn)) {
185                                 // no change in apm state
186                                 break;
187                             }
188                             sIsAirplaneModeOn = isAirplaneModeOn;
189                             event =
190                                     sIsAirplaneModeOn
191                                             ? QNS_EVENT_APM_ENABLED
192                                             : QNS_EVENT_APM_DISABLED;
193                             updateHandlers(event);
194                             break;
195 
196                         case WifiManager.WIFI_STATE_CHANGED_ACTION:
197                             int wifiState =
198                                     intent.getIntExtra(
199                                             WifiManager.EXTRA_WIFI_STATE,
200                                             WifiManager.WIFI_STATE_UNKNOWN);
201                             if (wifiState != sWiFiState) {
202                                 sWiFiState = wifiState;
203                                 if (wifiState == WifiManager.WIFI_STATE_DISABLING) {
204                                     event = QNS_EVENT_WIFI_DISABLING;
205                                 } else if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
206                                     event = QNS_EVENT_WIFI_ENABLED;
207                                 } else {
208                                     break;
209                                 }
210                                 updateHandlers(event);
211                             }
212                             break;
213 
214                         case TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED:
215                             boolean emergencyMode =
216                                     intent.getBooleanExtra(
217                                             TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false);
218                             event =
219                                     emergencyMode
220                                             ? QNS_EVENT_EMERGENCY_CALLBACK_MODE_ON
221                                             : QNS_EVENT_EMERGENCY_CALLBACK_MODE_OFF;
222                             int slotIndex = intent.getIntExtra(EXTRA_SLOT_INDEX, 0);
223                             // getInstance(mContext, slotIndex).
224                             if (mSlotIndex == slotIndex) {
225                                 updateHandlers(event);
226                             }
227                             break;
228                     }
229                 }
230             };
231 
232     final BroadcastReceiver mWfcActivationIntentReceiver =
233             new BroadcastReceiver() {
234                 @Override
235                 public void onReceive(Context context, Intent intent) {
236                     String action = intent.getAction();
237                     int event;
238                     Log.d(mLogTag, "mWfcActivationIntentReceiver onReceive: " + action);
239                     switch (action) {
240                         case ACTION_TRY_WFC_CONNECTION:
241                             int subId = intent.getIntExtra(EXTRA_SUB_ID, -1);
242                             if (subId != mSubId) {
243                                 Log.d(mLogTag, "Intent subId: " + subId + ", mSubId: " + mSubId);
244                                 break;
245                             }
246                             int request = intent.getIntExtra(EXTRA_TRY_STATUS, 0);
247                             event =
248                                     request == STATUS_START
249                                             ? QNS_EVENT_TRY_WFC_ACTIVATION
250                                             : QNS_EVENT_CANCEL_TRY_WFC_ACTIVATION;
251                             updateHandlers(event);
252                             break;
253                     }
254                 }
255             };
256 
257     /** QnsEventDispatcher constructor */
QnsEventDispatcher( Context context, QnsProvisioningListener provisioningListener, QnsImsManager imsManager, int slotIndex)258     QnsEventDispatcher(
259             Context context,
260             QnsProvisioningListener provisioningListener,
261             QnsImsManager imsManager,
262             int slotIndex) {
263         mContext = context;
264         mSlotIndex = slotIndex;
265         mLogTag = QnsEventDispatcher.class.getSimpleName() + "[" + mSlotIndex + "]";
266         mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
267         mQnsProvisioningListener = provisioningListener;
268         mQnsImsManager = imsManager;
269         final ContentResolver cr = mContext.getContentResolver();
270         int airplaneMode = Settings.Global.getInt(cr, Settings.Global.AIRPLANE_MODE_ON, 0);
271         sIsAirplaneModeOn = (airplaneMode == 1);
272         IntentFilter intentFilter = new IntentFilter();
273         intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
274         intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
275         intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
276         intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
277         intentFilter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
278         intentFilter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
279         mContext.registerReceiver(mIntentReceiver, intentFilter);
280 
281         IntentFilter wfcIntentFilter = new IntentFilter();
282         wfcIntentFilter.addAction(ACTION_TRY_WFC_CONNECTION);
283         mContext.registerReceiver(
284                 mWfcActivationIntentReceiver, wfcIntentFilter, Context.RECEIVER_NOT_EXPORTED);
285 
286         HandlerThread handlerThread = new HandlerThread(mLogTag);
287         handlerThread.start();
288         mQnsEventDispatcherHandler = new QnsEventDispatcherHandler(handlerThread.getLooper());
289         mQnsEventDispatcherHandler.post(() -> loadAndNotifyWfcSettings(mContext, mSlotIndex));
290 
291         mLastProvisioningInfo = new QnsProvisioningListener.QnsProvisioningInfo();
292         mQnsProvisioningListener.registerProvisioningItemInfoChanged(
293                 mQnsEventDispatcherHandler, EVENT_PROVISIONING_INFO_CHANGED, null, true);
294     }
295 
loadAndNotifyWfcSettings(Context context, int slotIndex)296     private synchronized void loadAndNotifyWfcSettings(Context context, int slotIndex) {
297         int subId = QnsUtils.getSubId(context, slotIndex);
298         Log.d(mLogTag, "loadAndNotifyWfcSettings for sub:" + subId);
299         if (subId != mSubId) {
300             unregisterContentObserver();
301             mSubId = subId;
302             registerContentObserver();
303         }
304         notifyWfcEnabledByPlatform();
305         notifyCurrentSetting(mCrossSimCallingUri, true);
306         notifyCurrentSetting(mWfcEnabledUri, true);
307         notifyCurrentSetting(mWfcModeUri, true);
308         notifyCurrentSetting(mWfcRoamingEnabledUri, true);
309         notifyCurrentSetting(mWfcRoamingModeUri, true);
310     }
311 
onCarrierConfigChanged(Context context, int slotId, int carrierId)312     private synchronized void onCarrierConfigChanged(Context context, int slotId, int carrierId) {
313         if (slotId != mSlotIndex) {
314             return;
315         }
316 
317         Log.d(mLogTag, "onCarrierConfigChanged");
318         loadAndNotifyWfcSettings(context, slotId);
319 
320         int event;
321         if (carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
322             event = QNS_EVENT_CARRIER_CONFIG_CHANGED;
323         } else {
324             event = QNS_EVENT_CARRIER_CONFIG_UNKNOWN_CARRIER;
325         }
326 
327         updateHandlers(event);
328     }
329 
registerEvent(List<Integer> events, Handler handler)330     synchronized void registerEvent(List<Integer> events, Handler handler) {
331         for (@QnsEventType int event : events) {
332             if (mEventHandlers.contains(event)) {
333                 mEventHandlers.get(event).add(handler);
334             } else {
335                 Set<Handler> handlers = new HashSet<>();
336                 handlers.add(handler);
337                 mEventHandlers.append(event, handlers);
338             }
339         }
340         notifyImmediately(events, handler);
341     }
342 
onSimStateChanged(int slotId, int simState)343     private void onSimStateChanged(int slotId, int simState) {
344         if (slotId != mSlotIndex) {
345             return;
346         }
347         if (simState == TelephonyManager.SIM_STATE_ABSENT) {
348             updateHandlers(QNS_EVENT_SIM_ABSENT);
349         } else if (simState == TelephonyManager.SIM_STATE_LOADED) {
350             updateHandlers(QNS_EVENT_SIM_LOADED);
351         }
352     }
353 
notifyImmediately(List<Integer> events, Handler handler)354     private synchronized void notifyImmediately(List<Integer> events, Handler handler) {
355         boolean bWfcPlatformSetting = false;
356         boolean bWfcSetting = false;
357         boolean bWfcModeSetting = false;
358         boolean bWfcRoamingSetting = false;
359         boolean bWfcRoamingModeSetting = false;
360         boolean bCrossSimSetting = false;
361         for (@QnsEventType int event : events) {
362             switch (event) {
363                 case QNS_EVENT_WFC_PLATFORM_ENABLED:
364                 case QNS_EVENT_WFC_PLATFORM_DISABLED:
365                     bWfcPlatformSetting = true;
366                     break;
367                 case QNS_EVENT_WFC_ENABLED:
368                 case QNS_EVENT_WFC_DISABLED:
369                     bWfcSetting = true;
370                     break;
371                 case QNS_EVENT_WFC_ROAMING_ENABLED:
372                 case QNS_EVENT_WFC_ROAMING_DISABLED:
373                     bWfcRoamingSetting = true;
374                     break;
375                 case QNS_EVENT_WFC_MODE_TO_WIFI_ONLY:
376                 case QNS_EVENT_WFC_MODE_TO_CELLULAR_PREFERRED:
377                 case QNS_EVENT_WFC_MODE_TO_WIFI_PREFERRED:
378                     bWfcModeSetting = true;
379                     break;
380                 case QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_ONLY:
381                 case QNS_EVENT_WFC_ROAMING_MODE_TO_CELLULAR_PREFERRED:
382                 case QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_PREFERRED:
383                     bWfcRoamingModeSetting = true;
384                     break;
385                 case QnsEventDispatcher.QNS_EVENT_CROSS_SIM_CALLING_ENABLED:
386                 case QnsEventDispatcher.QNS_EVENT_CROSS_SIM_CALLING_DISABLED:
387                     bCrossSimSetting = true;
388                     break;
389             }
390         }
391 
392         if (bWfcPlatformSetting) {
393             if (mLastWfcEnabledByPlatform) {
394                 updateHandler(handler, QNS_EVENT_WFC_PLATFORM_ENABLED);
395             } else {
396                 updateHandler(handler, QNS_EVENT_WFC_PLATFORM_DISABLED);
397             }
398             // checks again whether setting is changed.
399             notifyWfcEnabledByPlatform();
400         }
401         if (bWfcSetting) {
402             if (mLastWfcEnabled) {
403                 updateHandler(handler, QNS_EVENT_WFC_ENABLED);
404             } else {
405                 updateHandler(handler, QNS_EVENT_WFC_DISABLED);
406             }
407             // checks again whether setting is changed.
408             notifyCurrentSetting(mWfcEnabledUri, false);
409         }
410         if (bWfcModeSetting) {
411             switch (mLastWfcMode) {
412                 case WIFI_MODE_WIFI_ONLY:
413                     updateHandler(handler, QNS_EVENT_WFC_MODE_TO_WIFI_ONLY);
414                     break;
415                 case WIFI_MODE_CELLULAR_PREFERRED:
416                     updateHandler(handler, QNS_EVENT_WFC_MODE_TO_CELLULAR_PREFERRED);
417                     break;
418                 case WIFI_MODE_WIFI_PREFERRED:
419                     updateHandler(handler, QNS_EVENT_WFC_MODE_TO_WIFI_PREFERRED);
420                     break;
421             }
422             // checks again whether setting is changed.
423             notifyCurrentSetting(mWfcModeUri, false);
424         }
425         if (bWfcRoamingSetting) {
426             if (mLastWfcRoamingEnabled) {
427                 updateHandler(handler, QNS_EVENT_WFC_ROAMING_ENABLED);
428             } else {
429                 updateHandler(handler, QNS_EVENT_WFC_ROAMING_DISABLED);
430             }
431             // checks again whether setting is changed.
432             notifyCurrentSetting(mWfcRoamingEnabledUri, false);
433         }
434         if (bWfcRoamingModeSetting) {
435             switch (mLastWfcModeRoaming) {
436                 case WIFI_MODE_WIFI_ONLY:
437                     updateHandler(handler, QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_ONLY);
438                     break;
439                 case WIFI_MODE_CELLULAR_PREFERRED:
440                     updateHandler(handler, QNS_EVENT_WFC_ROAMING_MODE_TO_CELLULAR_PREFERRED);
441                     break;
442                 case WIFI_MODE_WIFI_PREFERRED:
443                     updateHandler(handler, QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_PREFERRED);
444                     break;
445             }
446             // checks again whether setting is changed.
447             notifyCurrentSetting(mWfcRoamingModeUri, false);
448         }
449         if (bCrossSimSetting) {
450             if (mLastCrossSimCallingEnabled) {
451                 updateHandler(handler, QNS_EVENT_CROSS_SIM_CALLING_ENABLED);
452             } else {
453                 updateHandler(handler, QNS_EVENT_CROSS_SIM_CALLING_DISABLED);
454             }
455             // checks again whether setting is changed.
456             notifyCurrentSetting(mCrossSimCallingUri, false);
457         }
458     }
459 
unregisterEvent(Handler handler)460     synchronized void unregisterEvent(Handler handler) {
461         for (int i = 0; i < mEventHandlers.size(); i++) {
462             Set<Handler> handlers = mEventHandlers.valueAt(i);
463             handlers.remove(handler);
464             if (handlers.isEmpty()) {
465                 mEventHandlers.delete(mEventHandlers.keyAt(i));
466                 i--;
467             }
468         }
469         if (mEventHandlers.size() == 0) {
470             close();
471         }
472     }
473 
close()474     public void close() {
475         try {
476             mContext.unregisterReceiver(mIntentReceiver);
477         } catch (IllegalArgumentException ignored) {
478         }
479         if (mUserSettingObserver != null) {
480             mContext.getContentResolver().unregisterContentObserver(mUserSettingObserver);
481         }
482         if (mUserSettingHandlerThread != null) {
483             mUserSettingHandlerThread.quit();
484         }
485         if (mQnsProvisioningListener != null) {
486             mQnsProvisioningListener.unregisterProvisioningItemInfoChanged(
487                     mQnsEventDispatcherHandler);
488         }
489     }
490 
unregisterContentObserver()491     private synchronized void unregisterContentObserver() {
492         if (mUserSettingObserver != null) {
493             mContext.getContentResolver().unregisterContentObserver(mUserSettingObserver);
494         }
495         mCrossSimCallingUri = null;
496         mWfcEnabledUri = null;
497         mWfcModeUri = null;
498         mWfcRoamingEnabledUri = null;
499         mWfcRoamingModeUri = null;
500     }
501 
registerContentObserver()502     private void registerContentObserver() {
503         // Register for content observer
504         if (mUserSettingObserver == null) {
505             Log.d(mLogTag, "create mUserSettingObserver");
506             mUserSettingHandlerThread = new HandlerThread(QnsEventDispatcher.class.getSimpleName());
507             mUserSettingHandlerThread.start();
508             Looper looper = mUserSettingHandlerThread.getLooper();
509             Handler handler = new Handler(looper);
510             mUserSettingObserver = new UserSettingObserver(handler);
511 
512             // init
513             mLastWfcEnabledByPlatform = QnsUtils.isWfcEnabledByPlatform(mQnsImsManager);
514             mLastCrossSimCallingEnabled = QnsUtils.isCrossSimCallingEnabled(mQnsImsManager);
515             mLastWfcEnabled =
516                     QnsUtils.isWfcEnabled(mQnsImsManager, mQnsProvisioningListener, false);
517             mLastWfcMode = QnsUtils.getWfcMode(mQnsImsManager, false);
518             mLastWfcRoamingEnabled =
519                     QnsUtils.isWfcEnabled(mQnsImsManager, mQnsProvisioningListener, true);
520             mLastWfcModeRoaming = QnsUtils.getWfcMode(mQnsImsManager, true);
521         }
522 
523         if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
524             return;
525         }
526 
527         StringBuilder sb = new StringBuilder("registerContentObserver");
528         sb.append(" subId:").append(mSubId);
529         ContentResolver resolver = mContext.getContentResolver();
530 
531         // Update current Cross Sim Calling setting
532         Uri crossSimCallingUri = getUri(SubscriptionManager.CROSS_SIM_ENABLED_CONTENT_URI, mSubId);
533         if (!crossSimCallingUri.equals(mCrossSimCallingUri)) {
534             mCrossSimCallingUri = crossSimCallingUri;
535             sb.append(" crossSimCallingUri/").append(mSubId);
536             resolver.registerContentObserver(mCrossSimCallingUri, true, mUserSettingObserver);
537         }
538 
539         // Update current Wi-Fi Calling setting
540         Uri wfcEnabledUri = getUri(SubscriptionManager.WFC_ENABLED_CONTENT_URI, mSubId);
541         if (!wfcEnabledUri.equals(mWfcEnabledUri)) {
542             mWfcEnabledUri = wfcEnabledUri;
543             sb.append(" wfcEnabledUri/").append(mSubId);
544             resolver.registerContentObserver(mWfcEnabledUri, true, mUserSettingObserver);
545         }
546 
547         // Update current Wi-Fi Calling Mode setting
548         Uri wfcModeUri = getUri(SubscriptionManager.WFC_MODE_CONTENT_URI, mSubId);
549         if (!wfcModeUri.equals(mWfcModeUri)) {
550             mWfcModeUri = wfcModeUri;
551             sb.append(" wfcModeUri/").append(mSubId);
552             resolver.registerContentObserver(mWfcModeUri, true, mUserSettingObserver);
553         }
554 
555         // Update current Wi-Fi Calling setting for roaming
556         Uri wfcRoamEnabledUri = getUri(SubscriptionManager.WFC_ROAMING_ENABLED_CONTENT_URI, mSubId);
557         if (!wfcRoamEnabledUri.equals(mWfcRoamingEnabledUri)) {
558             mWfcRoamingEnabledUri = wfcRoamEnabledUri;
559             sb.append(" wfcRoamEnabledUri/").append(mSubId);
560             resolver.registerContentObserver(mWfcRoamingEnabledUri, true, mUserSettingObserver);
561         }
562 
563         // Update current Wi-Fi Calling Mode setting for roaming
564         Uri wfcRoamingModeUri = getUri(SubscriptionManager.WFC_ROAMING_MODE_CONTENT_URI, mSubId);
565         if (!wfcRoamingModeUri.equals(mWfcRoamingModeUri)) {
566             mWfcRoamingModeUri = wfcRoamingModeUri;
567             sb.append(" wfcRoamingModeUri/").append(mSubId);
568             resolver.registerContentObserver(mWfcRoamingModeUri, true, mUserSettingObserver);
569         }
570 
571         Log.d(mLogTag, sb.toString());
572     }
573 
getUri(Uri uri, int subId)574     private Uri getUri(Uri uri, int subId) {
575         return Uri.withAppendedPath(uri, String.valueOf(subId));
576     }
577 
notifyCurrentSetting(Uri uri, boolean bForceUpdate)578     void notifyCurrentSetting(Uri uri, boolean bForceUpdate) {
579         if (uri == null) {
580             return;
581         }
582         try {
583             String uriString = uri.getPath();
584             int subIndex = Integer.parseInt(uriString.substring(uriString.lastIndexOf('/') + 1));
585             int slotIndex = SubscriptionManager.getSlotIndex(subIndex);
586             int event = QNS_EVENT_BASE;
587 
588             if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
589                 Log.e(mLogTag, "Invalid slot index: " + slotIndex);
590                 return;
591             }
592 
593             StringBuilder sb = new StringBuilder("notifyCurrentSetting");
594             sb.append(", bForceUpdate:").append(bForceUpdate);
595 
596             Log.d(mLogTag, "CrossSimCallingUri:" + mCrossSimCallingUri);
597             Log.d(mLogTag, "mWfcEnabledUri:" + mWfcEnabledUri);
598             Log.d(mLogTag, "mWfcModeUri:" + mWfcModeUri);
599             Log.d(mLogTag, "mWfcRoamingEnabledUri:" + mWfcRoamingEnabledUri);
600             Log.d(mLogTag, "mWfcRoamingModeUri:" + mWfcRoamingModeUri);
601 
602             if (uri.equals(mCrossSimCallingUri)) {
603                 boolean isCrossSimCallingEnabled =
604                         QnsUtils.isCrossSimCallingEnabled(mQnsImsManager);
605                 if (mLastCrossSimCallingEnabled != isCrossSimCallingEnabled || bForceUpdate) {
606                     if (isCrossSimCallingEnabled) {
607                         event = QNS_EVENT_CROSS_SIM_CALLING_ENABLED;
608                     } else {
609                         event = QNS_EVENT_CROSS_SIM_CALLING_DISABLED;
610                     }
611                     mLastCrossSimCallingEnabled = isCrossSimCallingEnabled;
612                     sb.append(", isCrossSimCallingEnabled:").append(isCrossSimCallingEnabled);
613                     Log.d(mLogTag, sb.toString());
614                     updateHandlers(event);
615                 }
616             } else if (uri.equals(mWfcEnabledUri)) {
617                 boolean isWfcEnabled =
618                         QnsUtils.isWfcEnabled(mQnsImsManager, mQnsProvisioningListener, false);
619                 if (mLastWfcEnabled != isWfcEnabled || bForceUpdate) {
620                     if (isWfcEnabled) {
621                         event = QNS_EVENT_WFC_ENABLED;
622                     } else {
623                         event = QNS_EVENT_WFC_DISABLED;
624                     }
625                     mLastWfcEnabled = isWfcEnabled;
626                     sb.append(", isWfcEnabled:").append(isWfcEnabled);
627                     Log.d(mLogTag, sb.toString());
628                     updateHandlers(event);
629                 }
630             } else if (uri.equals(mWfcModeUri)) {
631                 int wfcMode = QnsUtils.getWfcMode(mQnsImsManager, false);
632                 if (mLastWfcMode != wfcMode || bForceUpdate) {
633                     switch (wfcMode) {
634                         case WIFI_MODE_WIFI_ONLY:
635                             event = QNS_EVENT_WFC_MODE_TO_WIFI_ONLY;
636                             break;
637                         case WIFI_MODE_CELLULAR_PREFERRED:
638                             event = QNS_EVENT_WFC_MODE_TO_CELLULAR_PREFERRED;
639                             break;
640                         case WIFI_MODE_WIFI_PREFERRED:
641                             event = QNS_EVENT_WFC_MODE_TO_WIFI_PREFERRED;
642                             break;
643                     }
644                     mLastWfcMode = wfcMode;
645                     sb.append(", wfcMode:").append(wfcMode);
646                     Log.d(mLogTag, sb.toString());
647                     updateHandlers(event);
648                 }
649             } else if (uri.equals(mWfcRoamingEnabledUri)) {
650                 boolean isWfcRoamingEnabled =
651                         QnsUtils.isWfcEnabled(mQnsImsManager, mQnsProvisioningListener, true);
652                 if (mLastWfcRoamingEnabled != isWfcRoamingEnabled || bForceUpdate) {
653                     if (isWfcRoamingEnabled) {
654                         event = QNS_EVENT_WFC_ROAMING_ENABLED;
655                     } else {
656                         event = QNS_EVENT_WFC_ROAMING_DISABLED;
657                     }
658                     mLastWfcRoamingEnabled = isWfcRoamingEnabled;
659                     sb.append(", isWfcRoamingEnabled:").append(isWfcRoamingEnabled);
660                     Log.d(mLogTag, sb.toString());
661                     updateHandlers(event);
662                 }
663             } else if (uri.equals(mWfcRoamingModeUri)) {
664                 int wfcModeRoaming = QnsUtils.getWfcMode(mQnsImsManager, true);
665                 if (mLastWfcModeRoaming != wfcModeRoaming || bForceUpdate) {
666                     switch (wfcModeRoaming) {
667                         case WIFI_MODE_WIFI_ONLY:
668                             event = QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_ONLY;
669                             break;
670                         case WIFI_MODE_CELLULAR_PREFERRED:
671                             event = QNS_EVENT_WFC_ROAMING_MODE_TO_CELLULAR_PREFERRED;
672                             break;
673                         case WIFI_MODE_WIFI_PREFERRED:
674                             event = QNS_EVENT_WFC_ROAMING_MODE_TO_WIFI_PREFERRED;
675                             break;
676                     }
677                     mLastWfcModeRoaming = wfcModeRoaming;
678                     sb.append(", wfcModeRoaming:").append(wfcModeRoaming);
679                     Log.d(mLogTag, sb.toString());
680                     updateHandlers(event);
681                 }
682             } else {
683                 Log.e(mLogTag, "Unknown Uri : " + uri);
684             }
685         } catch (Exception e) {
686             Log.e(mLogTag, "notifyCurrentSetting got exception:" + e);
687             e.printStackTrace();
688         }
689     }
690 
notifyWfcEnabledByPlatform()691     void notifyWfcEnabledByPlatform() {
692         boolean isWfcEnabledByPlatform = QnsUtils.isWfcEnabledByPlatform(mQnsImsManager);
693         if (mLastWfcEnabledByPlatform != isWfcEnabledByPlatform) {
694             mLastWfcEnabledByPlatform = isWfcEnabledByPlatform;
695             Log.d(mLogTag, "notifyWfcEnabledByPlatform:" + isWfcEnabledByPlatform);
696             if (isWfcEnabledByPlatform) {
697                 updateHandlers(QNS_EVENT_WFC_PLATFORM_ENABLED);
698             } else {
699                 updateHandlers(QNS_EVENT_WFC_PLATFORM_DISABLED);
700             }
701         }
702     }
703 
updateHandler(Handler handler, int event)704     private synchronized void updateHandler(Handler handler, int event) {
705         try {
706             if (mEventHandlers.get(event).contains(handler)) {
707                 Log.d(mLogTag, "Updating handler for the event: " + event);
708                 handler.obtainMessage(event).sendToTarget();
709             }
710         } catch (Exception e) {
711             Log.e(mLogTag, "updateHandler got exception e:" + e);
712         }
713     }
714 
updateHandlers(int event)715     private synchronized void updateHandlers(int event) {
716         if (mEventHandlers.contains(event)) {
717             Log.d(mLogTag, "Updating handlers for the event: " + event);
718             for (Handler handler : mEventHandlers.get(event)) {
719                 handler.obtainMessage(event).sendToTarget();
720             }
721         }
722     }
723 
724     @VisibleForTesting
725     class UserSettingObserver extends ContentObserver {
UserSettingObserver(Handler h)726         UserSettingObserver(Handler h) {
727             super(h);
728         }
729 
730         @Override
onChange(boolean selfChange, Uri uri)731         public void onChange(boolean selfChange, Uri uri) {
732             Log.d(mLogTag, "onUserSettingChanged");
733             onUserSettingChanged(uri);
734         }
735     }
736 
onUserSettingChanged(Uri uri)737     private synchronized void onUserSettingChanged(Uri uri) {
738         if (mCrossSimCallingUri.equals(uri)) {
739             notifyCurrentSetting(uri, false);
740         } else if (mWfcEnabledUri.equals(uri)) {
741             // checks platform changes first.
742             notifyWfcEnabledByPlatform();
743 
744             notifyCurrentSetting(uri, false);
745         } else if (mWfcModeUri.equals(uri)) {
746             notifyCurrentSetting(uri, false);
747         } else if (mWfcRoamingEnabledUri.equals(uri)) {
748             // checks platform changes first.
749             notifyWfcEnabledByPlatform();
750 
751             notifyCurrentSetting(uri, false);
752         } else if (mWfcRoamingModeUri.equals(uri)) {
753             notifyCurrentSetting(uri, false);
754         }
755     }
756 
757     private class QnsEventDispatcherHandler extends Handler {
758         /**
759          * Use the provided {@link Looper} instead of the default one.
760          *
761          * @param looper The looper, must not be null.
762          */
QnsEventDispatcherHandler(Looper looper)763         QnsEventDispatcherHandler(Looper looper) {
764             super(looper);
765         }
766 
767         @Override
handleMessage(Message message)768         public void handleMessage(Message message) {
769             Log.d(mLogTag, "handleMessage msg=" + message.what);
770             QnsAsyncResult ar = (QnsAsyncResult) message.obj;
771             switch (message.what) {
772                 case EVENT_PROVISIONING_INFO_CHANGED:
773                     onProvisioningInfoChanged(
774                             (QnsProvisioningListener.QnsProvisioningInfo) ar.mResult);
775                     break;
776                 default:
777                     break;
778             }
779         }
780     }
781 
onProvisioningInfoChanged( QnsProvisioningListener.QnsProvisioningInfo info)782     private synchronized void onProvisioningInfoChanged(
783             QnsProvisioningListener.QnsProvisioningInfo info) {
784 
785         Log.d(mLogTag, "onProvisioningInfoChanged info:" + info);
786 
787         if (!info.equalsIntegerItem(
788                 mLastProvisioningInfo,
789                 ProvisioningManager.KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE)) {
790             Log.d(
791                     mLogTag,
792                     "onProvisioningInfoChanged, KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE("
793                             + ProvisioningManager.KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE
794                             + ") is provisioned to "
795                             + info.getIntegerItem(
796                                     ProvisioningManager
797                                             .KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE));
798             // checks platform changes first.
799             notifyWfcEnabledByPlatform();
800             notifyCurrentSetting(mWfcRoamingEnabledUri, false);
801         }
802         if (!info.equalsIntegerItem(
803                 mLastProvisioningInfo, ProvisioningManager.KEY_VOICE_OVER_WIFI_MODE_OVERRIDE)) {
804             Log.d(
805                     mLogTag,
806                     "onProvisioningInfoChanged, KEY_VOICE_OVER_WIFI_MODE_OVERRIDE("
807                             + ProvisioningManager.KEY_VOICE_OVER_WIFI_MODE_OVERRIDE
808                             + ") is provisioned to "
809                             + info.getIntegerItem(
810                                     ProvisioningManager.KEY_VOICE_OVER_WIFI_MODE_OVERRIDE));
811             notifyCurrentSetting(mWfcModeUri, false);
812         }
813         if (!info.equalsIntegerItem(
814                 mLastProvisioningInfo, ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE)) {
815             Log.d(
816                     mLogTag,
817                     "onProvisioningInfoChanged, KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE("
818                             + ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE
819                             + ") is provisioned to "
820                             + info.getIntegerItem(
821                                     ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE));
822             // checks platform changes first.
823             notifyWfcEnabledByPlatform();
824             notifyCurrentSetting(mWfcEnabledUri, false);
825         }
826 
827         mLastProvisioningInfo = info;
828     }
829 
isAirplaneModeToggleOn()830     boolean isAirplaneModeToggleOn() {
831         return sIsAirplaneModeOn;
832     }
833 }
834