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