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