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.Context; 20 import android.content.Intent; 21 import android.database.ContentObserver; 22 import android.net.Uri; 23 import android.net.wifi.WifiInfo; 24 import android.net.wifi.WifiManager; 25 import android.os.Handler; 26 import android.os.HandlerThread; 27 import android.os.Looper; 28 import android.support.annotation.IntDef; 29 import android.support.annotation.NonNull; 30 import android.telephony.CarrierConfigManager; 31 import android.telephony.SubscriptionManager; 32 import android.telephony.TelephonyManager; 33 import android.telephony.ims.ImsManager; 34 import android.telephony.ims.ImsMmTelManager; 35 import android.util.Log; 36 import android.util.SparseArray; 37 38 import com.android.internal.annotations.VisibleForTesting; 39 40 import java.util.HashSet; 41 import java.util.List; 42 import java.util.Map; 43 import java.util.Set; 44 import java.util.concurrent.ConcurrentHashMap; 45 46 public class IwlanEventListener { 47 48 public static final int UNKNOWN_EVENT = -1; 49 50 /** On receiving {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} intent. */ 51 public static final int CARRIER_CONFIG_CHANGED_EVENT = 1; 52 53 /** Wifi turned off or disabled. */ 54 public static final int WIFI_DISABLE_EVENT = 2; 55 56 /** Airplane mode turned off or disabled. */ 57 public static final int APM_DISABLE_EVENT = 3; 58 /** Airplame mode turned on or enabled */ 59 public static final int APM_ENABLE_EVENT = 4; 60 61 /** Wifi AccessPoint changed. */ 62 public static final int WIFI_AP_CHANGED_EVENT = 5; 63 64 /** Wifi calling turned on or enabled */ 65 public static final int WIFI_CALLING_ENABLE_EVENT = 6; 66 67 /** Wifi calling turned off or disabled */ 68 public static final int WIFI_CALLING_DISABLE_EVENT = 7; 69 70 /** Cross sim calling enabled */ 71 public static final int CROSS_SIM_CALLING_ENABLE_EVENT = 8; 72 73 /** Cross sim calling disabled */ 74 public static final int CROSS_SIM_CALLING_DISABLE_EVENT = 9; 75 76 /** 77 * On receiving {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} intent with 78 * UNKNOWN_CARRIER_ID. 79 */ 80 public static final int CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT = 10; 81 82 @IntDef({ 83 CARRIER_CONFIG_CHANGED_EVENT, 84 WIFI_DISABLE_EVENT, 85 APM_DISABLE_EVENT, 86 APM_ENABLE_EVENT, 87 WIFI_AP_CHANGED_EVENT, 88 WIFI_CALLING_ENABLE_EVENT, 89 WIFI_CALLING_DISABLE_EVENT, 90 CROSS_SIM_CALLING_ENABLE_EVENT, 91 CROSS_SIM_CALLING_DISABLE_EVENT, 92 CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT 93 }) 94 @interface IwlanEventType {}; 95 96 private static String LOG_TAG = IwlanEventListener.class.getSimpleName(); 97 98 private final String SUB_TAG; 99 100 private static Boolean sIsAirplaneModeOn; 101 102 private static String sWifiSSID = new String(); 103 104 private static Map<Integer, IwlanEventListener> mInstances = new ConcurrentHashMap<>(); 105 106 private Context mContext; 107 private int mSlotId; 108 private Uri mCrossSimCallingUri; 109 private Uri mWfcEnabledUri; 110 private UserSettingContentObserver mUserSettingContentObserver; 111 private HandlerThread mUserSettingHandlerThread; 112 113 SparseArray<Set<Handler>> eventHandlers = new SparseArray<>(); 114 115 private class UserSettingContentObserver extends ContentObserver { UserSettingContentObserver(Handler h)116 UserSettingContentObserver(Handler h) { 117 super(h); 118 } 119 120 @Override onChange(boolean selfChange, Uri uri)121 public void onChange(boolean selfChange, Uri uri) { 122 if (mCrossSimCallingUri.equals(uri)) { 123 getCurrentUriSetting(uri); 124 } else if (mWfcEnabledUri.equals(uri)) { 125 getCurrentUriSetting(uri); 126 } 127 } 128 } 129 130 /** Returns IwlanEventListener instance */ getInstance(@onNull Context context, int slotId)131 public static IwlanEventListener getInstance(@NonNull Context context, int slotId) { 132 return mInstances.computeIfAbsent(slotId, k -> new IwlanEventListener(context, slotId)); 133 } 134 135 /** 136 * Adds handler for the list of events. 137 * 138 * @param events lists of events for which the handler needs to be notified. 139 * @param handler handler to be called when the events happen 140 */ addEventListener(List<Integer> events, Handler handler)141 public synchronized void addEventListener(List<Integer> events, Handler handler) { 142 for (@IwlanEventType int event : events) { 143 if (eventHandlers.contains(event)) { 144 eventHandlers.get(event).add(handler); 145 } else { 146 Set<Handler> handlers = new HashSet<>(); 147 handlers.add(handler); 148 eventHandlers.append(event, handlers); 149 } 150 } 151 } 152 153 /** 154 * Removes handler for the list of events. 155 * 156 * @param events lists of events for which the handler needs to be removed. 157 * @param handler handler to be removed 158 */ removeEventListener(List<Integer> events, Handler handler)159 public synchronized void removeEventListener(List<Integer> events, Handler handler) { 160 for (int event : events) { 161 if (eventHandlers.contains(event)) { 162 Set<Handler> handlers = eventHandlers.get(event); 163 handlers.remove(handler); 164 if (handlers.isEmpty()) { 165 eventHandlers.delete(event); 166 } 167 } 168 } 169 if (eventHandlers.size() == 0) { 170 mInstances.remove(mSlotId, this); 171 } 172 } 173 174 /** 175 * Removes handler for all events it is registered 176 * 177 * @param handler handler to be removed 178 */ removeEventListener(Handler handler)179 public synchronized void removeEventListener(Handler handler) { 180 for (int i = 0; i < eventHandlers.size(); i++) { 181 Set<Handler> handlers = eventHandlers.valueAt(i); 182 handlers.remove(handler); 183 if (handlers.isEmpty()) { 184 eventHandlers.delete(eventHandlers.keyAt(i)); 185 i--; 186 } 187 } 188 if (eventHandlers.size() == 0) { 189 mInstances.remove(mSlotId, this); 190 } 191 } 192 193 /** 194 * Report a Broadcast received. Mainly used by IwlanBroadcastReceiver to report the following 195 * broadcasts CARRIER_CONFIG_CHANGED 196 * 197 * @param Intent intent 198 */ onBroadcastReceived(Intent intent)199 public static synchronized void onBroadcastReceived(Intent intent) { 200 int event = UNKNOWN_EVENT; 201 switch (intent.getAction()) { 202 case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED: 203 int slotId = 204 intent.getIntExtra( 205 CarrierConfigManager.EXTRA_SLOT_INDEX, 206 SubscriptionManager.INVALID_SIM_SLOT_INDEX); 207 int carrierId = 208 intent.getIntExtra( 209 TelephonyManager.EXTRA_CARRIER_ID, 210 TelephonyManager.UNKNOWN_CARRIER_ID); 211 212 Context context = IwlanDataService.getContext(); 213 if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX && context != null) { 214 if (carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) { 215 event = CARRIER_CONFIG_CHANGED_EVENT; 216 getInstance(context, slotId).registerContentObserver(); 217 } else { 218 event = CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT; 219 } 220 getInstance(context, slotId).updateHandlers(event); 221 } 222 break; 223 case Intent.ACTION_AIRPLANE_MODE_CHANGED: 224 Boolean isAirplaneModeOn = new Boolean(intent.getBooleanExtra("state", false)); 225 if (sIsAirplaneModeOn != null && sIsAirplaneModeOn.equals(isAirplaneModeOn)) { 226 // no change in apm state 227 break; 228 } 229 sIsAirplaneModeOn = isAirplaneModeOn; 230 event = sIsAirplaneModeOn ? APM_ENABLE_EVENT : APM_DISABLE_EVENT; 231 for (Map.Entry<Integer, IwlanEventListener> entry : mInstances.entrySet()) { 232 IwlanEventListener instance = entry.getValue(); 233 instance.updateHandlers(event); 234 } 235 break; 236 case WifiManager.WIFI_STATE_CHANGED_ACTION: 237 int wifiState = 238 intent.getIntExtra( 239 WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN); 240 if (wifiState == WifiManager.WIFI_STATE_DISABLED) { 241 event = WIFI_DISABLE_EVENT; 242 for (Map.Entry<Integer, IwlanEventListener> entry : mInstances.entrySet()) { 243 IwlanEventListener instance = entry.getValue(); 244 instance.updateHandlers(event); 245 } 246 } 247 break; 248 } 249 } 250 251 /** 252 * Broadcast WIFI_AP_CHANGED_EVENT if Wifi SSID changed after Wifi connected. 253 * 254 * @param Context context 255 */ onWifiConnected(Context context)256 public static void onWifiConnected(Context context) { 257 WifiManager wifiManager = context.getSystemService(WifiManager.class); 258 if (wifiManager == null) { 259 Log.e(LOG_TAG, "Could not find wifiManager"); 260 return; 261 } 262 WifiInfo wifiInfo = wifiManager.getConnectionInfo(); 263 if (wifiInfo == null) { 264 Log.e(LOG_TAG, "wifiInfo is null"); 265 return; 266 } 267 String wifiSSID = wifiInfo.getSSID(); 268 if (wifiSSID.equals(WifiManager.UNKNOWN_SSID)) { 269 Log.e(LOG_TAG, "Could not get Wifi SSID"); 270 return; 271 } 272 273 // Check sWifiSSID is greater than 0 to avoid trigger event after device first camps on 274 // Wifi. 275 if (sWifiSSID.length() > 0 && !sWifiSSID.equals(wifiSSID)) { 276 Log.d(LOG_TAG, "Wifi SSID changed"); 277 int event = WIFI_AP_CHANGED_EVENT; 278 for (Map.Entry<Integer, IwlanEventListener> entry : mInstances.entrySet()) { 279 IwlanEventListener instance = entry.getValue(); 280 if (instance != null) { 281 instance.updateHandlers(event); 282 } 283 } 284 } 285 sWifiSSID = wifiSSID; 286 } 287 288 /** 289 * Returns the Event id of the String. String that matches the name of the event 290 * 291 * @param event String form of the event. 292 * @param int form of the event. 293 */ getUnthrottlingEvent(String event)294 public static int getUnthrottlingEvent(String event) { 295 int ret = UNKNOWN_EVENT; 296 switch (event) { 297 case "CARRIER_CONFIG_CHANGED_EVENT": 298 ret = CARRIER_CONFIG_CHANGED_EVENT; 299 break; 300 case "WIFI_DISABLE_EVENT": 301 ret = WIFI_DISABLE_EVENT; 302 break; 303 case "APM_DISABLE_EVENT": 304 ret = APM_DISABLE_EVENT; 305 break; 306 case "APM_ENABLE_EVENT": 307 ret = APM_ENABLE_EVENT; 308 break; 309 case "WIFI_AP_CHANGED_EVENT": 310 ret = WIFI_AP_CHANGED_EVENT; 311 break; 312 case "WIFI_CALLING_ENABLE_EVENT": 313 ret = WIFI_CALLING_ENABLE_EVENT; 314 break; 315 case "WIFI_CALLING_DISABLE_EVENT": 316 ret = WIFI_CALLING_DISABLE_EVENT; 317 break; 318 case "CROSS_SIM_CALLING_ENABLE_EVENT": 319 ret = CROSS_SIM_CALLING_ENABLE_EVENT; 320 break; 321 case "CROSS_SIM_CALLING_DISABLE_EVENT": 322 ret = CROSS_SIM_CALLING_DISABLE_EVENT; 323 break; 324 case "CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT": 325 ret = CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT; 326 break; 327 } 328 return ret; 329 } 330 IwlanEventListener(Context context, int slotId)331 private IwlanEventListener(Context context, int slotId) { 332 mContext = context; 333 mSlotId = slotId; 334 SUB_TAG = IwlanEventListener.class.getSimpleName() + "[" + slotId + "]"; 335 sIsAirplaneModeOn = null; 336 } 337 registerContentObserver()338 private void registerContentObserver() { 339 // Register for content observer 340 if (mUserSettingContentObserver == null) { 341 mUserSettingHandlerThread = 342 new HandlerThread(IwlanNetworkService.class.getSimpleName()); 343 mUserSettingHandlerThread.start(); 344 Looper mlooper = mUserSettingHandlerThread.getLooper(); 345 Handler mhandler = new Handler(mlooper); 346 mUserSettingContentObserver = new UserSettingContentObserver(mhandler); 347 348 // Register for CrossSimCalling setting uri 349 mCrossSimCallingUri = 350 Uri.withAppendedPath( 351 SubscriptionManager.CROSS_SIM_ENABLED_CONTENT_URI, 352 String.valueOf(IwlanHelper.getSubId(mContext, mSlotId))); 353 mContext.getContentResolver() 354 .registerContentObserver( 355 mCrossSimCallingUri, true, mUserSettingContentObserver); 356 357 // Register for WifiCalling setting uri 358 mWfcEnabledUri = 359 Uri.withAppendedPath( 360 SubscriptionManager.WFC_ENABLED_CONTENT_URI, 361 String.valueOf(IwlanHelper.getSubId(mContext, mSlotId))); 362 mContext.getContentResolver() 363 .registerContentObserver(mWfcEnabledUri, true, mUserSettingContentObserver); 364 } 365 // Update current Cross Sim Calling setting 366 getCurrentUriSetting(mCrossSimCallingUri); 367 368 // Update current Wifi Calling setting 369 getCurrentUriSetting(mWfcEnabledUri); 370 } 371 372 @VisibleForTesting getCurrentUriSetting(Uri uri)373 void getCurrentUriSetting(Uri uri) { 374 String uriString = uri.getPath(); 375 int subIndex = Integer.parseInt(uriString.substring(uriString.lastIndexOf('/') + 1)); 376 int slotIndex = SubscriptionManager.getSlotIndex(subIndex); 377 378 if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { 379 Log.e(SUB_TAG, "Invalid slot index: " + slotIndex); 380 return; 381 } 382 383 if (uri.equals(mCrossSimCallingUri)) { 384 boolean isCstEnabled = IwlanHelper.isCrossSimCallingEnabled(mContext, slotIndex); 385 int event = 386 (isCstEnabled) 387 ? CROSS_SIM_CALLING_ENABLE_EVENT 388 : CROSS_SIM_CALLING_DISABLE_EVENT; 389 getInstance(mContext, slotIndex).updateHandlers(event); 390 } else if (uri.equals(mWfcEnabledUri)) { 391 ImsManager imsManager = mContext.getSystemService(ImsManager.class); 392 if (imsManager == null) { 393 Log.e(SUB_TAG, "Could not find ImsManager"); 394 return; 395 } 396 ImsMmTelManager imsMmTelManager = imsManager.getImsMmTelManager(subIndex); 397 if (imsMmTelManager == null) { 398 Log.e(SUB_TAG, "Could not find ImsMmTelManager"); 399 return; 400 } 401 boolean wfcEnabled = imsMmTelManager.isVoWiFiSettingEnabled(); 402 int event = (wfcEnabled) ? WIFI_CALLING_ENABLE_EVENT : WIFI_CALLING_DISABLE_EVENT; 403 getInstance(mContext, slotIndex).updateHandlers(event); 404 } else { 405 Log.e(SUB_TAG, "Unknown Uri : " + uri); 406 } 407 } 408 409 @VisibleForTesting setCrossSimCallingUri(Uri uri)410 void setCrossSimCallingUri(Uri uri) { 411 mCrossSimCallingUri = uri; 412 } 413 414 @VisibleForTesting setWfcEnabledUri(Uri uri)415 void setWfcEnabledUri(Uri uri) { 416 mWfcEnabledUri = uri; 417 } 418 updateHandlers(int event)419 private synchronized void updateHandlers(int event) { 420 if (eventHandlers.contains(event)) { 421 Log.d(SUB_TAG, "Updating handlers for the event: " + event); 422 for (Handler handler : eventHandlers.get(event)) { 423 handler.obtainMessage(event).sendToTarget(); 424 } 425 } 426 } 427 } 428