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.google.android.iwlan; 18 19 import android.content.ContentResolver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.database.ContentObserver; 23 import android.net.Uri; 24 import android.net.wifi.WifiInfo; 25 import android.net.wifi.WifiManager; 26 import android.os.Handler; 27 import android.os.HandlerThread; 28 import android.os.Looper; 29 import android.support.annotation.IntDef; 30 import android.support.annotation.NonNull; 31 import android.telephony.CellInfo; 32 import android.telephony.SubscriptionManager; 33 import android.telephony.TelephonyCallback; 34 import android.telephony.TelephonyManager; 35 import android.telephony.ims.ImsManager; 36 import android.telephony.ims.ImsMmTelManager; 37 import android.util.Log; 38 import android.util.SparseArray; 39 40 import com.android.internal.annotations.VisibleForTesting; 41 42 import com.google.android.iwlan.flags.FeatureFlags; 43 import com.google.android.iwlan.flags.FeatureFlagsImpl; 44 45 import java.util.HashSet; 46 import java.util.List; 47 import java.util.Map; 48 import java.util.Objects; 49 import java.util.Set; 50 import java.util.concurrent.ConcurrentHashMap; 51 52 public class IwlanEventListener { 53 54 private final FeatureFlags mFeatureFlags; 55 public static final int UNKNOWN_EVENT = -1; 56 57 /** On {@link IwlanCarrierConfigChangeListener#onCarrierConfigChanged} is called. */ 58 public static final int CARRIER_CONFIG_CHANGED_EVENT = 1; 59 60 /** Wifi turned off or disabled. */ 61 public static final int WIFI_DISABLE_EVENT = 2; 62 63 /** Airplane mode turned off or disabled. */ 64 public static final int APM_DISABLE_EVENT = 3; 65 /** Airplane mode turned on or enabled */ 66 public static final int APM_ENABLE_EVENT = 4; 67 68 /** Wifi AccessPoint changed. */ 69 public static final int WIFI_AP_CHANGED_EVENT = 5; 70 71 /** Wifi calling turned on or enabled */ 72 public static final int WIFI_CALLING_ENABLE_EVENT = 6; 73 74 /** Wifi calling turned off or disabled */ 75 public static final int WIFI_CALLING_DISABLE_EVENT = 7; 76 77 /** Cross sim calling enabled */ 78 public static final int CROSS_SIM_CALLING_ENABLE_EVENT = 8; 79 80 /** Cross sim calling disabled */ 81 public static final int CROSS_SIM_CALLING_DISABLE_EVENT = 9; 82 83 /** 84 * On {@link IwlanCarrierConfigChangeListener#onCarrierConfigChanged} is called with 85 * UNKNOWN_CARRIER_ID. 86 */ 87 public static final int CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT = 10; 88 89 /** On Cellinfo changed */ 90 public static final int CELLINFO_CHANGED_EVENT = 11; 91 92 /** On Call state changed */ 93 public static final int CALL_STATE_CHANGED_EVENT = 12; 94 95 /** On Preferred Network Type changed */ 96 public static final int PREFERRED_NETWORK_TYPE_CHANGED_EVENT = 13; 97 98 /* Events used and handled by IwlanDataService internally */ 99 public static final int DATA_SERVICE_INTERNAL_EVENT_BASE = 100; 100 101 /* Events used and handled by IwlanNetworkService internally */ 102 public static final int NETWORK_SERVICE_INTERNAL_EVENT_BASE = 200; 103 104 @IntDef({ 105 CARRIER_CONFIG_CHANGED_EVENT, 106 WIFI_DISABLE_EVENT, 107 APM_DISABLE_EVENT, 108 APM_ENABLE_EVENT, 109 WIFI_AP_CHANGED_EVENT, 110 WIFI_CALLING_ENABLE_EVENT, 111 WIFI_CALLING_DISABLE_EVENT, 112 CROSS_SIM_CALLING_ENABLE_EVENT, 113 CROSS_SIM_CALLING_DISABLE_EVENT, 114 CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT, 115 CELLINFO_CHANGED_EVENT, 116 CALL_STATE_CHANGED_EVENT, 117 PREFERRED_NETWORK_TYPE_CHANGED_EVENT, 118 }) 119 @interface IwlanEventType {} 120 121 private static final String LOG_TAG = IwlanEventListener.class.getSimpleName(); 122 123 private final String SUB_TAG; 124 125 private static Boolean sIsAirplaneModeOn; 126 127 private static String sWifiSSID = ""; 128 129 private static final Map<Integer, IwlanEventListener> mInstances = new ConcurrentHashMap<>(); 130 131 private final Context mContext; 132 private final int mSlotId; 133 private int mSubId; 134 private Uri mCrossSimCallingUri; 135 private Uri mWfcEnabledUri; 136 private UserSettingContentObserver mUserSettingContentObserver; 137 private RadioInfoTelephonyCallback mTelephonyCallback; 138 139 SparseArray<Set<Handler>> eventHandlers = new SparseArray<>(); 140 141 private class UserSettingContentObserver extends ContentObserver { UserSettingContentObserver(Handler h)142 UserSettingContentObserver(Handler h) { 143 super(h); 144 } 145 146 @Override onChange(boolean selfChange, Uri uri)147 public void onChange(boolean selfChange, Uri uri) { 148 Objects.requireNonNull(mCrossSimCallingUri, "CrossSimCallingUri must not be null"); 149 Objects.requireNonNull(mWfcEnabledUri, "WfcEnabledUri must not be null"); 150 if (mCrossSimCallingUri.equals(uri)) { 151 notifyCurrentSetting(uri); 152 } else if (mWfcEnabledUri.equals(uri)) { 153 notifyCurrentSetting(uri); 154 } 155 } 156 } 157 158 private class RadioInfoTelephonyCallback extends TelephonyCallback 159 implements TelephonyCallback.CellInfoListener, 160 TelephonyCallback.CallStateListener, 161 TelephonyCallback.AllowedNetworkTypesListener { 162 @Override onCellInfoChanged(List<CellInfo> arrayCi)163 public void onCellInfoChanged(List<CellInfo> arrayCi) { 164 Log.d(LOG_TAG, "Cellinfo changed"); 165 166 for (Map.Entry<Integer, IwlanEventListener> entry : mInstances.entrySet()) { 167 IwlanEventListener instance = entry.getValue(); 168 if (instance != null) { 169 instance.updateHandlers(arrayCi); 170 } 171 } 172 } 173 174 @Override onCallStateChanged(int state)175 public void onCallStateChanged(int state) { 176 Log.d( 177 LOG_TAG, 178 "Call state changed to " + callStateToString(state) + " for slot " + mSlotId); 179 180 IwlanEventListener instance = mInstances.get(mSlotId); 181 if (instance != null) { 182 instance.updateHandlers(CALL_STATE_CHANGED_EVENT, state); 183 } 184 } 185 186 @Override onAllowedNetworkTypesChanged( @elephonyManager.AllowedNetworkTypesReason int reason, @TelephonyManager.NetworkTypeBitMask long allowedNetworkType)187 public void onAllowedNetworkTypesChanged( 188 @TelephonyManager.AllowedNetworkTypesReason int reason, 189 @TelephonyManager.NetworkTypeBitMask long allowedNetworkType) { 190 if (reason != TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER) { 191 return; 192 } 193 194 IwlanEventListener instance = mInstances.get(mSlotId); 195 if (instance != null) { 196 instance.updateHandlers(PREFERRED_NETWORK_TYPE_CHANGED_EVENT, allowedNetworkType); 197 } 198 } 199 } 200 201 /** 202 * Returns IwlanEventListener instance 203 */ getInstance(@onNull Context context, int slotId)204 public static IwlanEventListener getInstance(@NonNull Context context, int slotId) { 205 return mInstances.computeIfAbsent( 206 slotId, k -> new IwlanEventListener(context, slotId, new FeatureFlagsImpl())); 207 } 208 209 @VisibleForTesting resetAllInstances()210 public static void resetAllInstances() { 211 mInstances.clear(); 212 } 213 214 /** 215 * Adds handler for the list of events. 216 * 217 * @param events lists of events for which the handler needs to be notified. 218 * @param handler handler to be called when the events happen 219 */ addEventListener(List<Integer> events, Handler handler)220 public synchronized void addEventListener(List<Integer> events, Handler handler) { 221 for (@IwlanEventType int event : events) { 222 if (eventHandlers.contains(event)) { 223 eventHandlers.get(event).add(handler); 224 } else { 225 Set<Handler> handlers = new HashSet<>(); 226 handlers.add(handler); 227 eventHandlers.append(event, handlers); 228 } 229 } 230 } 231 232 /** 233 * Removes handler for the list of events. 234 * 235 * @param events lists of events for which the handler needs to be removed. 236 * @param handler handler to be removed 237 */ removeEventListener(List<Integer> events, Handler handler)238 public synchronized void removeEventListener(List<Integer> events, Handler handler) { 239 for (int event : events) { 240 if (eventHandlers.contains(event)) { 241 Set<Handler> handlers = eventHandlers.get(event); 242 handlers.remove(handler); 243 if (handlers.isEmpty()) { 244 eventHandlers.delete(event); 245 } 246 } 247 } 248 if (eventHandlers.size() == 0) { 249 mInstances.remove(mSlotId, this); 250 } 251 } 252 253 /** 254 * Removes handler for all events it is registered 255 * 256 * @param handler handler to be removed 257 */ removeEventListener(Handler handler)258 public synchronized void removeEventListener(Handler handler) { 259 for (int i = 0; i < eventHandlers.size(); i++) { 260 Set<Handler> handlers = eventHandlers.valueAt(i); 261 handlers.remove(handler); 262 if (handlers.isEmpty()) { 263 eventHandlers.delete(eventHandlers.keyAt(i)); 264 i--; 265 } 266 } 267 if (eventHandlers.size() == 0) { 268 mInstances.remove(mSlotId, this); 269 } 270 } 271 272 /** 273 * Report a Broadcast received. Mainly used by IwlanBroadcastReceiver to report the following 274 * broadcasts: ACTION_AIRPLANE_MODE_CHANGED, WIFI_STATE_CHANGED_ACTION 275 * 276 * @param intent intent 277 */ onBroadcastReceived(Intent intent)278 public static synchronized void onBroadcastReceived(Intent intent) { 279 int event = UNKNOWN_EVENT; 280 switch (intent.getAction()) { 281 case Intent.ACTION_AIRPLANE_MODE_CHANGED: 282 Boolean isAirplaneModeOn = intent.getBooleanExtra("state", false); 283 if (sIsAirplaneModeOn != null && sIsAirplaneModeOn.equals(isAirplaneModeOn)) { 284 // no change in apm state 285 break; 286 } 287 sIsAirplaneModeOn = isAirplaneModeOn; 288 event = sIsAirplaneModeOn ? APM_ENABLE_EVENT : APM_DISABLE_EVENT; 289 for (Map.Entry<Integer, IwlanEventListener> entry : mInstances.entrySet()) { 290 IwlanEventListener instance = entry.getValue(); 291 instance.updateHandlers(event); 292 } 293 break; 294 case WifiManager.WIFI_STATE_CHANGED_ACTION: 295 int wifiState = 296 intent.getIntExtra( 297 WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN); 298 if (wifiState == WifiManager.WIFI_STATE_DISABLED) { 299 event = WIFI_DISABLE_EVENT; 300 for (Map.Entry<Integer, IwlanEventListener> entry : mInstances.entrySet()) { 301 IwlanEventListener instance = entry.getValue(); 302 instance.updateHandlers(event); 303 } 304 } 305 break; 306 } 307 } 308 309 /** 310 * Broadcast WIFI_AP_CHANGED_EVENT if Wifi SSID changed after Wifi connected. 311 * 312 * @param wifiInfo connected Wifi network's information. 313 */ onWifiConnected(WifiInfo wifiInfo)314 public static void onWifiConnected(WifiInfo wifiInfo) { 315 if (wifiInfo == null) { 316 Log.e(LOG_TAG, "wifiInfo is null"); 317 return; 318 } 319 String wifiSSID = wifiInfo.getSSID(); 320 if (wifiSSID.equals(WifiManager.UNKNOWN_SSID)) { 321 Log.e(LOG_TAG, "Could not get Wifi SSID"); 322 return; 323 } 324 325 // Check sWifiSSID is greater than 0 to avoid trigger event after device first camps on 326 // Wifi. 327 if (!sWifiSSID.isEmpty() && !sWifiSSID.equals(wifiSSID)) { 328 Log.d(LOG_TAG, "Wifi SSID changed"); 329 for (Map.Entry<Integer, IwlanEventListener> entry : mInstances.entrySet()) { 330 IwlanEventListener instance = entry.getValue(); 331 if (instance != null) { 332 instance.updateHandlers(WIFI_AP_CHANGED_EVENT); 333 } 334 } 335 } 336 sWifiSSID = wifiSSID; 337 } 338 339 /** 340 * Report Carrier Config changed. Mainly used by IwlanCarrierConfigChangeListener. 341 * 342 * @param context context 343 * @param slotId slot id which carrier config is changed 344 * @param subId sub id which carrier config is changed 345 * @param carrierId carrier id 346 */ onCarrierConfigChanged( Context context, int slotId, int subId, int carrierId)347 public static synchronized void onCarrierConfigChanged( 348 Context context, int slotId, int subId, int carrierId) { 349 getInstance(context, slotId).onCarrierConfigChanged(subId, carrierId); 350 } 351 352 /** 353 * Returns the Event id of the String. String that matches the name of the event 354 * 355 * @param event String form of the event. 356 */ getUnthrottlingEvent(String event)357 public static int getUnthrottlingEvent(String event) { 358 int ret = UNKNOWN_EVENT; 359 switch (event) { 360 case "CARRIER_CONFIG_CHANGED_EVENT": 361 ret = CARRIER_CONFIG_CHANGED_EVENT; 362 break; 363 case "WIFI_DISABLE_EVENT": 364 ret = WIFI_DISABLE_EVENT; 365 break; 366 case "APM_DISABLE_EVENT": 367 ret = APM_DISABLE_EVENT; 368 break; 369 case "APM_ENABLE_EVENT": 370 ret = APM_ENABLE_EVENT; 371 break; 372 case "WIFI_AP_CHANGED_EVENT": 373 ret = WIFI_AP_CHANGED_EVENT; 374 break; 375 case "WIFI_CALLING_ENABLE_EVENT": 376 ret = WIFI_CALLING_ENABLE_EVENT; 377 break; 378 case "WIFI_CALLING_DISABLE_EVENT": 379 ret = WIFI_CALLING_DISABLE_EVENT; 380 break; 381 case "CROSS_SIM_CALLING_ENABLE_EVENT": 382 ret = CROSS_SIM_CALLING_ENABLE_EVENT; 383 break; 384 case "CROSS_SIM_CALLING_DISABLE_EVENT": 385 ret = CROSS_SIM_CALLING_DISABLE_EVENT; 386 break; 387 case "CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT": 388 ret = CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT; 389 break; 390 case "CELLINFO_CHANGED_EVENT": 391 ret = CELLINFO_CHANGED_EVENT; 392 break; 393 case "PREFERRED_NETWORK_TYPE_CHANGED_EVENT": 394 ret = PREFERRED_NETWORK_TYPE_CHANGED_EVENT; 395 break; 396 } 397 return ret; 398 } 399 IwlanEventListener(Context context, int slotId, FeatureFlags featureFlags)400 IwlanEventListener(Context context, int slotId, FeatureFlags featureFlags) { 401 mContext = context; 402 mSlotId = slotId; 403 mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 404 SUB_TAG = IwlanEventListener.class.getSimpleName() + "[" + slotId + "]"; 405 sIsAirplaneModeOn = null; 406 mFeatureFlags = featureFlags; 407 } 408 onCarrierConfigChanged(int subId, int carrierId)409 private void onCarrierConfigChanged(int subId, int carrierId) { 410 Log.d(SUB_TAG, "onCarrierConfigChanged"); 411 if (subId != mSubId) { 412 unregisterContentObserver(); 413 mSubId = subId; 414 registerContentObserver(); 415 } 416 notifyCurrentSetting(mCrossSimCallingUri); 417 notifyCurrentSetting(mWfcEnabledUri); 418 419 int event; 420 if (carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) { 421 event = CARRIER_CONFIG_CHANGED_EVENT; 422 registerTelephonyCallback(); 423 } else { 424 event = CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT; 425 } 426 updateHandlers(event); 427 } 428 429 /** Unregister ContentObserver. */ unregisterContentObserver()430 void unregisterContentObserver() { 431 if (mUserSettingContentObserver != null) { 432 mContext.getContentResolver().unregisterContentObserver(mUserSettingContentObserver); 433 } 434 mCrossSimCallingUri = null; 435 mWfcEnabledUri = null; 436 } 437 438 /** Initiate ContentObserver if it is not created. And, register it with the current sub id. */ registerContentObserver()439 private void registerContentObserver() { 440 if (mUserSettingContentObserver == null) { 441 HandlerThread userSettingHandlerThread = 442 new HandlerThread(IwlanNetworkService.class.getSimpleName()); 443 userSettingHandlerThread.start(); 444 Looper looper = userSettingHandlerThread.getLooper(); 445 Handler handler = new Handler(looper); 446 mUserSettingContentObserver = new UserSettingContentObserver(handler); 447 } 448 449 if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 450 return; 451 } 452 453 ContentResolver resolver = mContext.getContentResolver(); 454 // Register for CrossSimCalling setting uri 455 mCrossSimCallingUri = 456 Uri.withAppendedPath( 457 SubscriptionManager.CROSS_SIM_ENABLED_CONTENT_URI, String.valueOf(mSubId)); 458 resolver.registerContentObserver(mCrossSimCallingUri, true, mUserSettingContentObserver); 459 460 // Register for WifiCalling setting uri 461 mWfcEnabledUri = 462 Uri.withAppendedPath( 463 SubscriptionManager.WFC_ENABLED_CONTENT_URI, String.valueOf(mSubId)); 464 resolver.registerContentObserver(mWfcEnabledUri, true, mUserSettingContentObserver); 465 } 466 467 @VisibleForTesting notifyCurrentSetting(Uri uri)468 void notifyCurrentSetting(Uri uri) { 469 if (uri == null) { 470 return; 471 } 472 String uriString = uri.getPath(); 473 int subIndex = Integer.parseInt(uriString.substring(uriString.lastIndexOf('/') + 1)); 474 int slotIndex = SubscriptionManager.getSlotIndex(subIndex); 475 476 if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { 477 Log.e(SUB_TAG, "Invalid slot index: " + slotIndex); 478 return; 479 } 480 481 if (uri.equals(mCrossSimCallingUri)) { 482 boolean isCstEnabled = IwlanHelper.isCrossSimCallingEnabled(mContext, slotIndex); 483 int event = 484 (isCstEnabled) 485 ? CROSS_SIM_CALLING_ENABLE_EVENT 486 : CROSS_SIM_CALLING_DISABLE_EVENT; 487 getInstance(mContext, slotIndex).updateHandlers(event); 488 } else if (uri.equals(mWfcEnabledUri)) { 489 ImsManager imsManager = mContext.getSystemService(ImsManager.class); 490 if (imsManager == null) { 491 Log.e(SUB_TAG, "Could not find ImsManager"); 492 return; 493 } 494 ImsMmTelManager imsMmTelManager = imsManager.getImsMmTelManager(subIndex); 495 if (imsMmTelManager == null) { 496 Log.e(SUB_TAG, "Could not find ImsMmTelManager"); 497 return; 498 } 499 boolean wfcEnabled = false; 500 try { 501 wfcEnabled = imsMmTelManager.isVoWiFiSettingEnabled(); 502 } catch (IllegalArgumentException e) { 503 Log.w(SUB_TAG, e.getMessage()); 504 } 505 int event = (wfcEnabled) ? WIFI_CALLING_ENABLE_EVENT : WIFI_CALLING_DISABLE_EVENT; 506 getInstance(mContext, slotIndex).updateHandlers(event); 507 } else { 508 Log.e(SUB_TAG, "Unknown Uri : " + uri); 509 } 510 } 511 512 @VisibleForTesting registerTelephonyCallback()513 void registerTelephonyCallback() { 514 Log.d(SUB_TAG, "registerTelephonyCallback"); 515 TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class); 516 telephonyManager = 517 Objects.requireNonNull(telephonyManager) 518 .createForSubscriptionId(IwlanHelper.getSubId(mContext, mSlotId)); 519 mTelephonyCallback = new RadioInfoTelephonyCallback(); 520 telephonyManager.registerTelephonyCallback(Runnable::run, mTelephonyCallback); 521 } 522 523 @VisibleForTesting setCrossSimCallingUri(Uri uri)524 void setCrossSimCallingUri(Uri uri) { 525 mCrossSimCallingUri = uri; 526 } 527 528 @VisibleForTesting setWfcEnabledUri(Uri uri)529 void setWfcEnabledUri(Uri uri) { 530 mWfcEnabledUri = uri; 531 } 532 533 @VisibleForTesting getTelephonyCallback()534 RadioInfoTelephonyCallback getTelephonyCallback() { 535 return mTelephonyCallback; 536 } 537 updateHandlers(int event)538 private synchronized void updateHandlers(int event) { 539 if (eventHandlers.contains(event)) { 540 Log.d(SUB_TAG, "Updating handlers for the event: " + event); 541 for (Handler handler : eventHandlers.get(event)) { 542 handler.obtainMessage(event, mSlotId, 0 /* unused */).sendToTarget(); 543 } 544 } 545 } 546 updateHandlers(List<CellInfo> arrayCi)547 private synchronized void updateHandlers(List<CellInfo> arrayCi) { 548 int event = IwlanEventListener.CELLINFO_CHANGED_EVENT; 549 if (eventHandlers.contains(event)) { 550 Log.d(SUB_TAG, "Updating handlers for the event: " + event); 551 for (Handler handler : eventHandlers.get(event)) { 552 handler.obtainMessage(event, mSlotId, 0 /* unused */, arrayCi).sendToTarget(); 553 } 554 } 555 } 556 updateHandlers(int event, int state)557 private synchronized void updateHandlers(int event, int state) { 558 if (eventHandlers.contains(event)) { 559 Log.d(SUB_TAG, "Updating handlers for the event: " + event); 560 for (Handler handler : eventHandlers.get(event)) { 561 handler.obtainMessage(event, mSlotId, state).sendToTarget(); 562 } 563 } 564 } 565 updateHandlers(int event, long allowedNetworkType)566 private synchronized void updateHandlers(int event, long allowedNetworkType) { 567 if (eventHandlers.contains(event)) { 568 Log.d(SUB_TAG, "Updating handlers for the event: " + event); 569 for (Handler handler : eventHandlers.get(event)) { 570 handler.obtainMessage(event, mSlotId, 0 /* unused */, allowedNetworkType) 571 .sendToTarget(); 572 } 573 } 574 } 575 callStateToString(int state)576 private String callStateToString(int state) { 577 switch (state) { 578 case TelephonyManager.CALL_STATE_IDLE: 579 return "CALL_STATE_IDLE"; 580 case TelephonyManager.CALL_STATE_RINGING: 581 return "CALL_STATE_RINGING"; 582 case TelephonyManager.CALL_STATE_OFFHOOK: 583 return "CALL_STATE_OFFHOOK"; 584 default: 585 return "Unknown Call State (" + state + ")"; 586 } 587 } 588 } 589