1 /*
2  * Copyright (C) 2019 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.android.server.wifi;
18 
19 import android.app.AlertDialog;
20 import android.app.Notification;
21 import android.app.NotificationManager;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.net.wifi.WifiConfiguration;
28 import android.os.Handler;
29 import android.os.Process;
30 import android.util.Log;
31 
32 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
33 import com.android.wifi.resources.R;
34 
35 /**
36  * This class may be used to launch notifications when wifi connections fail.
37  */
38 public class ConnectionFailureNotifier {
39     private static final String TAG = "ConnectionFailureNotifier";
40 
41     private Context mContext;
42     private WifiInjector mWifiInjector;
43     private FrameworkFacade mFrameworkFacade;
44     private WifiConfigManager mWifiConfigManager;
45     private WifiConnectivityManager mWifiConnectivityManager;
46     private NotificationManager mNotificationManager;
47     private Handler mHandler;
48     private ConnectionFailureNotificationBuilder mConnectionFailureNotificationBuilder;
49 
ConnectionFailureNotifier( Context context, WifiInjector wifiInjector, FrameworkFacade framework, WifiConfigManager wifiConfigManager, WifiConnectivityManager wifiConnectivityManager, Handler handler)50     public ConnectionFailureNotifier(
51             Context context, WifiInjector wifiInjector, FrameworkFacade framework,
52             WifiConfigManager wifiConfigManager, WifiConnectivityManager wifiConnectivityManager,
53             Handler handler) {
54         mContext = context;
55         mWifiInjector = wifiInjector;
56         mFrameworkFacade = framework;
57         mWifiConfigManager = wifiConfigManager;
58         mWifiConnectivityManager = wifiConnectivityManager;
59         mNotificationManager = mWifiInjector.getNotificationManager();
60         mHandler = handler;
61         mConnectionFailureNotificationBuilder =
62                 mWifiInjector.getConnectionFailureNotificationBuilder();
63 
64         IntentFilter filter = new IntentFilter();
65         filter.addAction(ConnectionFailureNotificationBuilder
66                 .ACTION_SHOW_SET_RANDOMIZATION_DETAILS);
67         mContext.registerReceiver(
68                 new BroadcastReceiver() {
69                     @Override
70                     public void onReceive(Context context, Intent intent) {
71                         String action = intent.getAction();
72                         if (action.equals(ConnectionFailureNotificationBuilder
73                                 .ACTION_SHOW_SET_RANDOMIZATION_DETAILS)) {
74                             int networkId = intent.getIntExtra(
75                                     ConnectionFailureNotificationBuilder
76                                             .RANDOMIZATION_SETTINGS_NETWORK_ID,
77                                     WifiConfiguration.INVALID_NETWORK_ID);
78                             String ssidAndSecurityType = intent.getStringExtra(
79                                     ConnectionFailureNotificationBuilder
80                                             .RANDOMIZATION_SETTINGS_NETWORK_SSID);
81                             showRandomizationSettingsDialog(networkId, ssidAndSecurityType);
82                         }
83                     }
84                 }, filter);
85     }
86 
87     /**
88      * Shows a notification which will bring up a dialog which offers the user an option to disable
89      * MAC randomization on |networkdId|.
90      * @param networkId
91      */
showFailedToConnectDueToNoRandomizedMacSupportNotification(int networkId)92     public void showFailedToConnectDueToNoRandomizedMacSupportNotification(int networkId) {
93         WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(networkId);
94         if (config == null) {
95             return;
96         }
97         Notification notification = mConnectionFailureNotificationBuilder
98                 .buildNoMacRandomizationSupportNotification(config);
99         mNotificationManager.notify(SystemMessage.NOTE_NETWORK_NO_MAC_RANDOMIZATION_SUPPORT,
100                 notification);
101     }
102 
103     class DisableMacRandomizationListener implements DialogInterface.OnClickListener {
104         private WifiConfiguration mConfig;
105 
DisableMacRandomizationListener(WifiConfiguration config)106         DisableMacRandomizationListener(WifiConfiguration config) {
107             mConfig = config;
108         }
109 
110         @Override
onClick(DialogInterface dialog, int which)111         public void onClick(DialogInterface dialog, int which) {
112             mHandler.post(() -> {
113                 mConfig.macRandomizationSetting =
114                         WifiConfiguration.RANDOMIZATION_NONE;
115                 mWifiConfigManager.addOrUpdateNetwork(mConfig, Process.SYSTEM_UID);
116                 WifiConfiguration updatedConfig =
117                         mWifiConfigManager.getConfiguredNetwork(mConfig.networkId);
118                 if (updatedConfig.macRandomizationSetting
119                         == WifiConfiguration.RANDOMIZATION_NONE) {
120                     String message = mContext.getResources().getString(
121                             R.string.wifi_disable_mac_randomization_dialog_success);
122                     mFrameworkFacade.showToast(mContext, message);
123                     mWifiConfigManager.enableNetwork(updatedConfig.networkId, true,
124                             Process.SYSTEM_UID, null);
125                     mWifiConnectivityManager.forceConnectivityScan(
126                             ClientModeImpl.WIFI_WORK_SOURCE);
127                 } else {
128                     // Shouldn't ever fail, but here for completeness
129                     String message = mContext.getResources().getString(
130                             R.string.wifi_disable_mac_randomization_dialog_failure);
131                     mFrameworkFacade.showToast(mContext, message);
132                     Log.e(TAG, "Failed to modify mac randomization setting");
133                 }
134             });
135         }
136     }
137 
138     /**
139      * Class to show a AlertDialog which notifies the user of a network not being privacy
140      * compliant and then suggests an action.
141      */
showRandomizationSettingsDialog(int networkId, String ssidAndSecurityType)142     private void showRandomizationSettingsDialog(int networkId, String ssidAndSecurityType) {
143         WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(networkId);
144         // Make sure the networkId is still pointing to the correct WifiConfiguration since
145         // there might be a large time gap between when the notification shows and when
146         // it's tapped.
147         if (config == null || ssidAndSecurityType == null
148                 || !ssidAndSecurityType.equals(config.getSsidAndSecurityTypeString())) {
149             String message = mContext.getResources().getString(
150                     R.string.wifi_disable_mac_randomization_dialog_network_not_found);
151             mFrameworkFacade.showToast(mContext, message);
152             return;
153         }
154 
155         AlertDialog dialog = mConnectionFailureNotificationBuilder
156                 .buildChangeMacRandomizationSettingDialog(config.SSID,
157                         new DisableMacRandomizationListener(config));
158         dialog.show();
159     }
160 }
161