• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.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