• 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.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