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