1 /* 2 * Copyright (C) 2017 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 static android.app.Notification.VISIBILITY_SECRET; 20 21 import android.app.Notification; 22 import android.app.PendingIntent; 23 import android.content.Intent; 24 import android.graphics.drawable.Icon; 25 import android.net.wifi.ScanResult; 26 import android.net.wifi.WifiContext; 27 import android.util.Log; 28 29 import com.android.modules.utils.build.SdkLevel; 30 import com.android.wifi.resources.R; 31 32 /** 33 * Helper to create notifications for {@link OpenNetworkNotifier}. 34 */ 35 public class ConnectToNetworkNotificationBuilder { 36 37 /** Intent when user dismissed the "Connect to Network" notification. */ 38 public static final String ACTION_USER_DISMISSED_NOTIFICATION = 39 "com.android.server.wifi.ConnectToNetworkNotification.USER_DISMISSED_NOTIFICATION"; 40 41 /** Intent when user tapped action button to connect to recommended network. */ 42 public static final String ACTION_CONNECT_TO_NETWORK = 43 "com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK"; 44 45 /** Intent when user tapped action button to open Wi-Fi Settings. */ 46 public static final String ACTION_PICK_WIFI_NETWORK = 47 "com.android.server.wifi.ConnectToNetworkNotification.PICK_WIFI_NETWORK"; 48 49 /** Intent when user tapped "Failed to connect" notification to open Wi-Fi Settings. */ 50 public static final String ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE = 51 "com.android.server.wifi.ConnectToNetworkNotification.PICK_NETWORK_AFTER_FAILURE"; 52 53 /** Extra data added to the Intent to specify the registering network notifier. */ 54 public static final String AVAILABLE_NETWORK_NOTIFIER_TAG = 55 "com.android.server.wifi.ConnectToNetworkNotification.AVAILABLE_NETWORK_NOTIFIER_TAG"; 56 57 private final WifiContext mContext; 58 private final FrameworkFacade mFrameworkFacade; 59 ConnectToNetworkNotificationBuilder( WifiContext context, FrameworkFacade framework)60 public ConnectToNetworkNotificationBuilder( 61 WifiContext context, 62 FrameworkFacade framework) { 63 mContext = context; 64 mFrameworkFacade = framework; 65 } 66 67 /** 68 * Creates the connect to network notification that alerts users of a recommended connectable 69 * network. 70 * 71 * There are two actions - "Options" link to the Wi-Fi picker activity, and "Connect" prompts 72 * the connection to the recommended network. 73 * 74 * @param notifierTag Unique tag of calling network notifier 75 * @param network The network to be recommended 76 */ createConnectToAvailableNetworkNotification(String notifierTag, ScanResult network)77 public Notification createConnectToAvailableNetworkNotification(String notifierTag, 78 ScanResult network) { 79 CharSequence title; 80 switch (notifierTag) { 81 case OpenNetworkNotifier.TAG: 82 title = mContext.getText(R.string.wifi_available_title); 83 break; 84 default: 85 Log.wtf("ConnectToNetworkNotificationBuilder", "Unknown network notifier." 86 + notifierTag); 87 return null; 88 } 89 Notification.Action.Builder connectActionBuilder = 90 new Notification.Action.Builder(null /* icon */, 91 mContext.getResources().getText(R.string.wifi_available_action_connect), 92 getPrivateBroadcast(ACTION_CONNECT_TO_NETWORK, notifierTag)); 93 // >= Android 12: Want the user to unlock before triggering connection. 94 if (SdkLevel.isAtLeastS()) { 95 connectActionBuilder.setAuthenticationRequired(true); 96 } 97 Notification.Action connectAction = connectActionBuilder.build(); 98 Notification.Action allNetworksAction = new Notification.Action.Builder(null /* icon */, 99 mContext.getResources().getText(R.string.wifi_available_action_all_networks), 100 getPrivateBroadcast(ACTION_PICK_WIFI_NETWORK, notifierTag)).build(); 101 Notification.Builder notificationBuilder = 102 createNotificationBuilder(title, network.SSID, notifierTag) 103 .setContentIntent(getPrivateBroadcast(ACTION_PICK_WIFI_NETWORK, notifierTag)) 104 .addAction(connectAction) 105 .addAction(allNetworksAction); 106 // < Android 12: Hide the notification in lock screen since (setAuthenticationRequired) is 107 // not available. 108 if (!SdkLevel.isAtLeastS()) { 109 notificationBuilder.setVisibility(VISIBILITY_SECRET); 110 } 111 return notificationBuilder.build(); 112 } 113 114 /** 115 * Creates the notification that indicates the controller is attempting to connect to the 116 * recommended network. 117 * 118 * @param notifierTag Unique tag of the calling network notifier 119 * @param network The network to be recommended 120 */ createNetworkConnectingNotification(String notifierTag, ScanResult network)121 public Notification createNetworkConnectingNotification(String notifierTag, 122 ScanResult network) { 123 return createNotificationBuilder( 124 mContext.getText(R.string.wifi_available_title_connecting), network.SSID, 125 notifierTag) 126 .setProgress(0 /* max */, 0 /* progress */, true /* indeterminate */) 127 .build(); 128 } 129 130 /** 131 * Creates the notification that indicates the controller successfully connected to the 132 * recommended network. 133 * 134 * @param notifierTag Unique tag of the calling network notifier 135 * @param network The network to be recommended 136 */ createNetworkConnectedNotification(String notifierTag, ScanResult network)137 public Notification createNetworkConnectedNotification(String notifierTag, ScanResult network) { 138 return createNotificationBuilder( 139 mContext.getText(R.string.wifi_available_title_connected), network.SSID, 140 notifierTag) 141 .build(); 142 } 143 144 /** 145 * Creates the notification that indicates the controller failed to connect to the recommended 146 * network. Tapping this notification opens the wifi picker. 147 * 148 * @param notifierTag Unique tag of the calling network notifier 149 */ createNetworkFailedNotification(String notifierTag)150 public Notification createNetworkFailedNotification(String notifierTag) { 151 return createNotificationBuilder( 152 mContext.getText(R.string.wifi_available_title_failed_to_connect), 153 mContext.getText(R.string.wifi_available_content_failed_to_connect), notifierTag) 154 .setContentIntent( 155 getPrivateBroadcast(ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE, 156 notifierTag)) 157 .setAutoCancel(true) 158 .build(); 159 } 160 getNotifierRequestCode(String notifierTag)161 private int getNotifierRequestCode(String notifierTag) { 162 switch (notifierTag) { 163 case OpenNetworkNotifier.TAG: 164 return 1; 165 } 166 return 0; 167 } 168 createNotificationBuilder( CharSequence title, CharSequence content, String extraData)169 private Notification.Builder createNotificationBuilder( 170 CharSequence title, CharSequence content, String extraData) { 171 return mFrameworkFacade.makeNotificationBuilder(mContext, 172 WifiService.NOTIFICATION_NETWORK_AVAILABLE) 173 .setSmallIcon(Icon.createWithResource(mContext.getWifiOverlayApkPkgName(), 174 com.android.wifi.resources.R.drawable.stat_notify_wifi_in_range)) 175 .setTicker(title) 176 .setContentTitle(title) 177 .setContentText(content) 178 .setDeleteIntent(getPrivateBroadcast(ACTION_USER_DISMISSED_NOTIFICATION, extraData)) 179 .setShowWhen(false) 180 .setLocalOnly(true) 181 .setColor(mContext.getResources().getColor( 182 android.R.color.system_notification_accent_color, 183 mContext.getTheme())); 184 } 185 getPrivateBroadcast(String action, String extraData)186 private PendingIntent getPrivateBroadcast(String action, String extraData) { 187 Intent intent = new Intent(action).setPackage(mContext.getServiceWifiPackageName()); 188 int requestCode = 0; // Makes the different kinds of notifications distinguishable 189 if (extraData != null) { 190 intent.putExtra(AVAILABLE_NETWORK_NOTIFIER_TAG, extraData); 191 requestCode = getNotifierRequestCode(extraData); 192 } 193 return mFrameworkFacade.getBroadcast(mContext, requestCode, intent, 194 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); 195 } 196 } 197