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 android.app.Notification;
20 import android.app.PendingIntent;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.res.Resources;
24 import android.net.wifi.ScanResult;
25 import android.util.Log;
26 
27 import com.android.internal.R;
28 import com.android.internal.notification.SystemNotificationChannels;
29 
30 /**
31  * Helper to create notifications for {@link OpenNetworkNotifier}.
32  */
33 public class ConnectToNetworkNotificationBuilder {
34 
35     /** Intent when user dismissed the "Connect to Network" notification. */
36     public static final String ACTION_USER_DISMISSED_NOTIFICATION =
37             "com.android.server.wifi.ConnectToNetworkNotification.USER_DISMISSED_NOTIFICATION";
38 
39     /** Intent when user tapped action button to connect to recommended network. */
40     public static final String ACTION_CONNECT_TO_NETWORK =
41             "com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK";
42 
43     /** Intent when user tapped action button to open Wi-Fi Settings. */
44     public static final String ACTION_PICK_WIFI_NETWORK =
45             "com.android.server.wifi.ConnectToNetworkNotification.PICK_WIFI_NETWORK";
46 
47     /** Intent when user tapped "Failed to connect" notification to open Wi-Fi Settings. */
48     public static final String ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE =
49             "com.android.server.wifi.ConnectToNetworkNotification.PICK_NETWORK_AFTER_FAILURE";
50 
51     /** Extra data added to the Intent to specify the registering network notifier. */
52     public static final String AVAILABLE_NETWORK_NOTIFIER_TAG =
53             "com.android.server.wifi.ConnectToNetworkNotification.AVAILABLE_NETWORK_NOTIFIER_TAG";
54 
55     private Context mContext;
56     private Resources mResources;
57     private FrameworkFacade mFrameworkFacade;
58 
ConnectToNetworkNotificationBuilder( Context context, FrameworkFacade framework)59     public ConnectToNetworkNotificationBuilder(
60             Context context,
61             FrameworkFacade framework) {
62         mContext = context;
63         mResources = context.getResources();
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             case CarrierNetworkNotifier.TAG:
85                 title = mContext.getText(R.string.wifi_available_carrier_network_title);
86                 break;
87             default:
88                 Log.wtf("ConnectToNetworkNotificationBuilder", "Unknown network notifier."
89                         + notifierTag);
90                 return null;
91         }
92         Notification.Action connectAction = new Notification.Action.Builder(null /* icon */,
93                 mResources.getText(R.string.wifi_available_action_connect),
94                 getPrivateBroadcast(ACTION_CONNECT_TO_NETWORK, notifierTag)).build();
95         Notification.Action allNetworksAction = new Notification.Action.Builder(null /* icon */,
96                 mResources.getText(R.string.wifi_available_action_all_networks),
97                 getPrivateBroadcast(ACTION_PICK_WIFI_NETWORK, notifierTag)).build();
98         return createNotificationBuilder(title, network.SSID, notifierTag)
99                 .setContentIntent(getPrivateBroadcast(ACTION_PICK_WIFI_NETWORK, notifierTag))
100                 .addAction(connectAction)
101                 .addAction(allNetworksAction)
102                 .build();
103     }
104 
105     /**
106      * Creates the notification that indicates the controller is attempting to connect to the
107      * recommended network.
108      *
109      * @param notifierTag Unique tag of the calling network notifier
110      * @param network The network to be recommended
111      */
createNetworkConnectingNotification(String notifierTag, ScanResult network)112     public Notification createNetworkConnectingNotification(String notifierTag,
113             ScanResult network) {
114         return createNotificationBuilder(
115                 mContext.getText(R.string.wifi_available_title_connecting), network.SSID,
116                         notifierTag)
117                 .setProgress(0 /* max */, 0 /* progress */, true /* indeterminate */)
118                 .build();
119     }
120 
121     /**
122      * Creates the notification that indicates the controller successfully connected to the
123      * recommended network.
124      *
125      * @param notifierTag Unique tag of the calling network notifier
126      * @param network The network to be recommended
127      */
createNetworkConnectedNotification(String notifierTag, ScanResult network)128     public Notification createNetworkConnectedNotification(String notifierTag, ScanResult network) {
129         return createNotificationBuilder(
130                 mContext.getText(R.string.wifi_available_title_connected), network.SSID,
131                         notifierTag)
132                 .build();
133     }
134 
135     /**
136      * Creates the notification that indicates the controller failed to connect to the recommended
137      * network. Tapping this notification opens the wifi picker.
138      *
139      * @param notifierTag Unique tag of the calling network notifier
140      */
createNetworkFailedNotification(String notifierTag)141     public Notification createNetworkFailedNotification(String notifierTag) {
142         return createNotificationBuilder(
143                 mContext.getText(R.string.wifi_available_title_failed_to_connect),
144                 mContext.getText(R.string.wifi_available_content_failed_to_connect), notifierTag)
145                 .setContentIntent(
146                         getPrivateBroadcast(ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE,
147                                 notifierTag))
148                 .setAutoCancel(true)
149                 .build();
150     }
151 
getNotifierRequestCode(String notifierTag)152     private int getNotifierRequestCode(String notifierTag) {
153         switch (notifierTag) {
154             case OpenNetworkNotifier.TAG:
155                 return 1;
156             case CarrierNetworkNotifier.TAG:
157                 return 2;
158         }
159         return 0;
160     }
161 
createNotificationBuilder( CharSequence title, CharSequence content, String extraData)162     private Notification.Builder createNotificationBuilder(
163             CharSequence title, CharSequence content, String extraData) {
164         return mFrameworkFacade.makeNotificationBuilder(mContext,
165                 SystemNotificationChannels.NETWORK_AVAILABLE)
166                 .setSmallIcon(R.drawable.stat_notify_wifi_in_range)
167                 .setTicker(title)
168                 .setContentTitle(title)
169                 .setContentText(content)
170                 .setDeleteIntent(getPrivateBroadcast(ACTION_USER_DISMISSED_NOTIFICATION, extraData))
171                 .setShowWhen(false)
172                 .setLocalOnly(true)
173                 .setColor(mResources.getColor(R.color.system_notification_accent_color,
174                         mContext.getTheme()));
175     }
176 
getPrivateBroadcast(String action, String extraData)177     private PendingIntent getPrivateBroadcast(String action, String extraData) {
178         Intent intent = new Intent(action).setPackage("android");
179         int requestCode = 0;  // Makes the different kinds of notifications distinguishable
180         if (extraData != null) {
181             intent.putExtra(AVAILABLE_NETWORK_NOTIFIER_TAG, extraData);
182             requestCode = getNotifierRequestCode(extraData);
183         }
184         return mFrameworkFacade.getBroadcast(mContext, requestCode, intent,
185                 PendingIntent.FLAG_UPDATE_CURRENT);
186     }
187 }
188