/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wifi; import android.app.AlertDialog; import android.app.Notification; import android.app.NotificationManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.net.wifi.WifiConfiguration; import android.os.Handler; import android.os.Process; import android.util.Log; import com.android.internal.R; /** * This class may be used to launch notifications when wifi connections fail. */ public class ConnectionFailureNotifier { private static final String TAG = "ConnectionFailureNotifier"; public static final int NO_RANDOMIZED_MAC_SUPPORT_NOTIFICATION_ID = 123; private Context mContext; private WifiInjector mWifiInjector; private Resources mResources; private FrameworkFacade mFrameworkFacade; private WifiConfigManager mWifiConfigManager; private WifiConnectivityManager mWifiConnectivityManager; private NotificationManager mNotificationManager; private Handler mHandler; private ConnectionFailureNotificationBuilder mConnectionFailureNotificationBuilder; public ConnectionFailureNotifier( Context context, WifiInjector wifiInjector, FrameworkFacade framework, WifiConfigManager wifiConfigManager, WifiConnectivityManager wifiConnectivityManager, Handler handler) { mContext = context; mWifiInjector = wifiInjector; mResources = context.getResources(); mFrameworkFacade = framework; mWifiConfigManager = wifiConfigManager; mWifiConnectivityManager = wifiConnectivityManager; mNotificationManager = mWifiInjector.getNotificationManager(); mHandler = handler; mConnectionFailureNotificationBuilder = mWifiInjector.getConnectionFailureNotificationBuilder(); IntentFilter filter = new IntentFilter(); filter.addAction(ConnectionFailureNotificationBuilder .ACTION_SHOW_SET_RANDOMIZATION_DETAILS); mContext.registerReceiver( new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(ConnectionFailureNotificationBuilder .ACTION_SHOW_SET_RANDOMIZATION_DETAILS)) { int networkId = intent.getIntExtra( ConnectionFailureNotificationBuilder .RANDOMIZATION_SETTINGS_NETWORK_ID, WifiConfiguration.INVALID_NETWORK_ID); String ssidAndSecurityType = intent.getStringExtra( ConnectionFailureNotificationBuilder .RANDOMIZATION_SETTINGS_NETWORK_SSID); showRandomizationSettingsDialog(networkId, ssidAndSecurityType); } } }, filter); } /** * Shows a notification which will bring up a dialog which offers the user an option to disable * MAC randomization on |networkdId|. * @param networkId */ public void showFailedToConnectDueToNoRandomizedMacSupportNotification(int networkId) { WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(networkId); if (config == null) { return; } Notification notification = mConnectionFailureNotificationBuilder .buildNoMacRandomizationSupportNotification(config); mNotificationManager.notify(NO_RANDOMIZED_MAC_SUPPORT_NOTIFICATION_ID, notification); } class DisableMacRandomizationListener implements DialogInterface.OnClickListener { private WifiConfiguration mConfig; DisableMacRandomizationListener(WifiConfiguration config) { mConfig = config; } @Override public void onClick(DialogInterface dialog, int which) { mHandler.post(() -> { mConfig.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE; mWifiConfigManager.addOrUpdateNetwork(mConfig, Process.SYSTEM_UID); WifiConfiguration updatedConfig = mWifiConfigManager.getConfiguredNetwork(mConfig.networkId); if (updatedConfig.macRandomizationSetting == WifiConfiguration.RANDOMIZATION_NONE) { String message = mResources.getString( R.string.wifi_disable_mac_randomization_dialog_success); mFrameworkFacade.showToast(mContext, message); mWifiConfigManager.enableNetwork(updatedConfig.networkId, true, Process.SYSTEM_UID); mWifiConnectivityManager.forceConnectivityScan( ClientModeImpl.WIFI_WORK_SOURCE); } else { // Shouldn't ever fail, but here for completeness String message = mResources.getString( R.string.wifi_disable_mac_randomization_dialog_failure); mFrameworkFacade.showToast(mContext, message); Log.e(TAG, "Failed to modify mac randomization setting"); } }); } } /** * Class to show a AlertDialog which notifies the user of a network not being privacy * compliant and then suggests an action. */ private void showRandomizationSettingsDialog(int networkId, String ssidAndSecurityType) { WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(networkId); // Make sure the networkId is still pointing to the correct WifiConfiguration since // there might be a large time gap between when the notification shows and when // it's tapped. if (config == null || ssidAndSecurityType == null || !ssidAndSecurityType.equals(config.getSsidAndSecurityTypeString())) { String message = mResources.getString( R.string.wifi_disable_mac_randomization_dialog_network_not_found); mFrameworkFacade.showToast(mContext, message); return; } AlertDialog dialog = mConnectionFailureNotificationBuilder .buildChangeMacRandomizationSettingDialog(config.SSID, new DisableMacRandomizationListener(config)); dialog.show(); } }