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.Notification; 20 import android.app.PendingIntent; 21 import android.content.Intent; 22 import android.graphics.drawable.Icon; 23 import android.net.wifi.WifiConfiguration; 24 import android.net.wifi.WifiContext; 25 import android.net.wifi.WifiStringResourceWrapper; 26 import android.provider.Settings; 27 import android.service.notification.StatusBarNotification; 28 import android.telephony.TelephonyManager; 29 import android.text.TextUtils; 30 31 import com.android.internal.annotations.VisibleForTesting; 32 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; 33 34 /** 35 * This class may be used to launch notifications when EAP failure occurs. 36 */ 37 public class EapFailureNotifier { 38 private static final String TAG = "EapFailureNotifier"; 39 @VisibleForTesting 40 static final String ERROR_MESSAGE_OVERLAY_PREFIX = "wifi_eap_error_message_code_"; 41 @VisibleForTesting 42 static final String ERROR_MESSAGE_OVERLAY_UNKNOWN_ERROR_CODE = 43 "wifi_eap_error_message_unknown_error_code"; 44 45 private static final long CANCEL_TIMEOUT_MILLISECONDS = 5 * 60 * 1000; 46 private final WifiContext mContext; 47 private final WifiNotificationManager mNotificationManager; 48 private final FrameworkFacade mFrameworkFacade; 49 private final WifiCarrierInfoManager mWifiCarrierInfoManager; 50 51 // Unique ID associated with the notification. 52 public static final int NOTIFICATION_ID = SystemMessage.NOTE_WIFI_EAP_FAILURE; 53 private String mCurrentShownSsid; 54 EapFailureNotifier(WifiContext context, FrameworkFacade frameworkFacade, WifiCarrierInfoManager wifiCarrierInfoManager, WifiNotificationManager wifiNotificationManager)55 public EapFailureNotifier(WifiContext context, FrameworkFacade frameworkFacade, 56 WifiCarrierInfoManager wifiCarrierInfoManager, 57 WifiNotificationManager wifiNotificationManager) { 58 mContext = context; 59 mFrameworkFacade = frameworkFacade; 60 mWifiCarrierInfoManager = wifiCarrierInfoManager; 61 mNotificationManager = wifiNotificationManager; 62 } 63 64 /** 65 * Invoked when EAP failure occurs. 66 * 67 * @param errorCode error code which delivers from supplicant 68 * @param showNotification whether to display the notification 69 * @return true if the receiving error code is found in wifi resource 70 */ onEapFailure(int errorCode, WifiConfiguration config, boolean showNotification)71 public boolean onEapFailure(int errorCode, WifiConfiguration config, boolean showNotification) { 72 if (errorCode < 0) { 73 // EapErrorCode is defined as an unsigned uint32_t in ISupplicantStaIfaceCallback, so 74 // only consider non-negative error codes for carrier-specific error messages. 75 return false; 76 } 77 WifiStringResourceWrapper sr = mContext.getStringResourceWrapper( 78 mWifiCarrierInfoManager.getBestMatchSubscriptionId(config), 79 config.carrierId == TelephonyManager.UNKNOWN_CARRIER_ID 80 ? mWifiCarrierInfoManager.getDefaultDataSimCarrierId() : config.carrierId); 81 String errorMessage = sr.getString(ERROR_MESSAGE_OVERLAY_PREFIX + errorCode, config.SSID); 82 if (errorMessage == null) { 83 // Use the generic error message if the code does not match any known code. 84 errorMessage = sr.getString(ERROR_MESSAGE_OVERLAY_UNKNOWN_ERROR_CODE, config.SSID); 85 } 86 if (TextUtils.isEmpty(errorMessage)) return false; 87 StatusBarNotification[] activeNotifications = mNotificationManager.getActiveNotifications(); 88 for (StatusBarNotification activeNotification : activeNotifications) { 89 if ((activeNotification.getId() == NOTIFICATION_ID) 90 && TextUtils.equals(config.SSID, mCurrentShownSsid)) { 91 return true; 92 } 93 } 94 95 if (showNotification) { 96 showNotification(errorMessage, config.SSID); 97 } 98 return true; 99 } 100 101 /** 102 * Display eap error notification which defined by carrier. 103 * 104 * @param ssid Error Message which defined by carrier 105 */ showNotification(String errorMessage, String ssid)106 private void showNotification(String errorMessage, String ssid) { 107 String settingsPackage = mFrameworkFacade.getSettingsPackageName(mContext); 108 if (settingsPackage == null) return; 109 Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS) 110 .setPackage(settingsPackage); 111 Notification.Builder builder = mFrameworkFacade.makeNotificationBuilder(mContext, 112 WifiService.NOTIFICATION_NETWORK_ALERTS) 113 .setAutoCancel(true) 114 .setTimeoutAfter(CANCEL_TIMEOUT_MILLISECONDS) 115 .setSmallIcon(Icon.createWithResource(mContext.getWifiOverlayApkPkgName(), 116 com.android.wifi.resources.R.drawable.stat_notify_wifi_in_range)) 117 .setContentTitle(mContext.getString( 118 com.android.wifi.resources.R.string.wifi_available_title_failed_to_connect)) 119 .setContentText(errorMessage) 120 .setStyle(new Notification.BigTextStyle().bigText(errorMessage)) 121 .setContentIntent(mFrameworkFacade.getActivity( 122 mContext, 0, intent, 123 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)) 124 .setColor(mContext.getResources().getColor( 125 android.R.color.system_notification_accent_color)); 126 mNotificationManager.notify(NOTIFICATION_ID, 127 builder.build()); 128 mCurrentShownSsid = ssid; 129 } 130 131 /** 132 * Allow tests to modify mCurrentShownSsid 133 */ 134 @VisibleForTesting setCurrentShownSsid(String currentShownSsid)135 void setCurrentShownSsid(String currentShownSsid) { 136 mCurrentShownSsid = currentShownSsid; 137 } 138 } 139