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.NotificationManager;
21 import android.app.PendingIntent;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.provider.Settings;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
28 import com.android.internal.notification.SystemNotificationChannels;
29 import com.android.server.wifi.util.NativeUtil;
30 
31 /**
32  * Responsible for notifying user for wrong password errors.
33  */
34 public class WrongPasswordNotifier {
35     // Number of milliseconds to wait before automatically dismiss the notification.
36     private static final long CANCEL_TIMEOUT_MILLISECONDS = 5 * 60 * 1000;
37 
38     // Unique ID associated with the notification.
39     @VisibleForTesting
40     public static final int NOTIFICATION_ID = SystemMessage.NOTE_WIFI_WRONG_PASSWORD;
41 
42     // Flag indicating if a wrong password error is detected for the current connection.
43     private boolean mWrongPasswordDetected;
44 
45     private final Context mContext;
46     private final NotificationManager mNotificationManager;
47     private final FrameworkFacade mFrameworkFacade;
48 
WrongPasswordNotifier(Context context, FrameworkFacade frameworkFacade)49     public WrongPasswordNotifier(Context context, FrameworkFacade frameworkFacade) {
50         mContext = context;
51         mFrameworkFacade = frameworkFacade;
52         mNotificationManager =
53                 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
54     }
55 
56     /**
57      * Invoked when a wrong password error for a Wi-Fi network is detected.
58      *
59      * @param ssid The SSID of the Wi-Fi network
60      */
onWrongPasswordError(String ssid)61     public void onWrongPasswordError(String ssid) {
62         showNotification(ssid);
63         mWrongPasswordDetected = true;
64     }
65 
66     /**
67      * Invoked when attempting a new Wi-Fi network connection.
68      */
onNewConnectionAttempt()69     public void onNewConnectionAttempt() {
70         if (mWrongPasswordDetected) {
71             dismissNotification();
72             mWrongPasswordDetected = false;
73         }
74     }
75 
76     /**
77      * Display wrong password notification for a given Wi-Fi network (specified by its SSID).
78      *
79      * @param ssid SSID of the Wi-FI network
80      */
showNotification(String ssid)81     private void showNotification(String ssid) {
82         Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS);
83         intent.putExtra("wifi_start_connect_ssid", NativeUtil.removeEnclosingQuotes(ssid));
84         Notification.Builder builder = mFrameworkFacade.makeNotificationBuilder(mContext,
85                 SystemNotificationChannels.NETWORK_ALERTS)
86                 .setAutoCancel(true)
87                 .setTimeoutAfter(CANCEL_TIMEOUT_MILLISECONDS)
88                 // TODO(zqiu): consider creating a new icon.
89                 .setSmallIcon(com.android.internal.R.drawable.stat_notify_wifi_in_range)
90                 .setContentTitle(mContext.getString(
91                         com.android.internal.R.string.wifi_available_title_failed_to_connect))
92                 .setContentText(ssid)
93                 .setContentIntent(mFrameworkFacade.getActivity(
94                         mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT))
95                 .setColor(mContext.getResources().getColor(
96                         com.android.internal.R.color.system_notification_accent_color));
97         mNotificationManager.notify(NOTIFICATION_ID, builder.build());
98     }
99 
100     /**
101      * Dismiss the notification that was generated by {@link #showNotification}. The notification
102      * might have already been dismissed, either by user or timeout. We'll attempt to dismiss it
103      * regardless if it is been dismissed or not, to reduce code complexity.
104      */
dismissNotification()105     private void dismissNotification() {
106         // Notification might have already been dismissed, either by user or timeout. It is
107         // still okay to cancel it if already dismissed.
108         mNotificationManager.cancel(null, NOTIFICATION_ID);
109     }
110 }
111