blob: 8b4da551d2cf65425f32c28bc695e6bf509cbf8a [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.networkrecommendation.wakeup;
import static com.android.networkrecommendation.Constants.TAG;
import static com.android.networkrecommendation.util.NotificationChannelUtil.CHANNEL_ID_WAKEUP;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArraySet;
import com.android.networkrecommendation.R;
import com.android.networkrecommendation.config.G;
import com.android.networkrecommendation.config.Preferences;
import com.android.networkrecommendation.scoring.util.HashUtil;
import com.android.networkrecommendation.util.Blog;
import com.android.networkrecommendation.util.NotificationChannelUtil;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Helper class for logging Wi-Fi Wakeup sessions and showing showing notifications for {@link
* WifiWakeupController}.
*/
public class WifiWakeupHelper {
/** Unique ID used for the Wi-Fi Enabled notification. */
private static final int NOTIFICATION_ID = R.string.wifi_wakeup_enabled_notification_title;
@VisibleForTesting
static final String ACTION_WIFI_SETTINGS =
"com.android.networkrecommendation.wakeup.ACTION_WIFI_SETTINGS";
@VisibleForTesting
static final String ACTION_DISMISS_WIFI_ENABLED_NOTIFICATION =
"com.android.networkrecommendation.wakeup.ACTION_DISMISS_WIFI_ENABLED_NOTIFICATION";
private static final long NETWORK_CONNECTED_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(30);
private static final IntentFilter INTENT_FILTER = new IntentFilter();
static {
INTENT_FILTER.addAction(ACTION_DISMISS_WIFI_ENABLED_NOTIFICATION);
INTENT_FILTER.addAction(ACTION_WIFI_SETTINGS);
INTENT_FILTER.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
}
private final Context mContext;
private final Resources mResources;
private final NotificationManager mNotificationManager;
private final Handler mHandler;
private final WifiManager mWifiManager;
/** Whether the wakeup notification is currently displayed. */
private boolean mNotificationShown;
/** True when the device is still connected to the first connected ssid since wakeup. */
private boolean mWifiSessionStarted;
/** The first connected ssid after wakeup enabled wifi. */
private String mConnectedSsid;
private final BroadcastReceiver mBroadcastReceiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
try {
if (ACTION_WIFI_SETTINGS.equals(intent.getAction())) {
mContext.startActivity(
new Intent(Settings.ACTION_WIFI_SETTINGS)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
} else if (ACTION_DISMISS_WIFI_ENABLED_NOTIFICATION.equals(
intent.getAction())) {
cancelNotificationIfNeeded();
} else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(
intent.getAction())) {
networkStateChanged();
}
} catch (RuntimeException re) {
// TODO(b/35044022) Remove try/catch after a couple of releases when we are confident
// this is not going to throw.
Blog.e(TAG, re, "RuntimeException in broadcast receiver.");
}
}
};
public WifiWakeupHelper(
Context context,
Resources resources,
Handler handler,
NotificationManager notificationManager,
WifiManager wifiManager) {
mContext = context;
mResources = resources;
mNotificationManager = notificationManager;
mHandler = handler;
mWifiManager = wifiManager;
mWifiSessionStarted = false;
mNotificationShown = false;
mConnectedSsid = null;
}
/**
* Start tracking a wifi wakeup session. Optionally show a notification that Wi-Fi has been
* enabled by Wi-Fi Wakeup if one has not been displayed for this {@link WifiConfiguration}.
*
* @param wifiConfiguration the {@link WifiConfiguration} that triggered Wi-Fi to wakeup
*/
public void startWifiSession(@NonNull WifiConfiguration wifiConfiguration) {
mContext.registerReceiver(
mBroadcastReceiver, INTENT_FILTER, null /* broadcastPermission*/, mHandler);
mWifiSessionStarted = true;
mHandler.postDelayed(
() -> {
if (mWifiSessionStarted && mConnectedSsid == null) {
endWifiSession();
}
},
NETWORK_CONNECTED_TIMEOUT_MILLIS);
Set<String> hashedSsidSet = Preferences.ssidsForWakeupShown.get();
String hashedSsid = HashUtil.getSsidHash(wifiConfiguration.SSID);
if (hashedSsidSet.isEmpty()) {
hashedSsidSet = new ArraySet<>();
} else if (hashedSsidSet.contains(hashedSsid)) {
Blog.i(
TAG,
"Already showed Wi-Fi Enabled notification for ssid: %s",
Blog.pii(wifiConfiguration.SSID, G.Netrec.enableSensitiveLogging.get()));
return;
}
hashedSsidSet.add(hashedSsid);
Preferences.ssidsForWakeupShown.put(hashedSsidSet);
String title = mResources.getString(R.string.wifi_wakeup_enabled_notification_title);
String summary =
mResources.getString(
R.string.wifi_wakeup_enabled_notification_context, wifiConfiguration.SSID);
PendingIntent savedNetworkSettingsPendingIntent =
PendingIntent.getBroadcast(
mContext,
0,
new Intent(ACTION_WIFI_SETTINGS),
PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent deletePendingIntent =
PendingIntent.getBroadcast(
mContext,
0,
new Intent(ACTION_DISMISS_WIFI_ENABLED_NOTIFICATION),
PendingIntent.FLAG_UPDATE_CURRENT);
Bundle extras = new Bundle();
extras.putString(
Notification.EXTRA_SUBSTITUTE_APP_NAME,
mResources.getString(R.string.notification_channel_group_name));
int smallIcon = R.drawable.ic_signal_wifi_statusbar_not_connected;
Notification.Builder notificationBuilder =
new Notification.Builder(mContext)
.setContentTitle(title)
.setSmallIcon(smallIcon)
.setColor(mContext.getColor(R.color.color_tint))
.setStyle(new Notification.BigTextStyle().bigText(summary))
.setAutoCancel(true)
.setShowWhen(false)
.setDeleteIntent(deletePendingIntent)
.setPriority(Notification.PRIORITY_LOW)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setCategory(Notification.CATEGORY_STATUS)
.setContentIntent(savedNetworkSettingsPendingIntent)
.setLocalOnly(true)
.addExtras(extras);
NotificationChannelUtil.setChannel(notificationBuilder, CHANNEL_ID_WAKEUP);
mNotificationManager.notify(TAG, NOTIFICATION_ID, notificationBuilder.build());
mNotificationShown = true;
}
private void networkStateChanged() {
if (!mWifiManager.isWifiEnabled()) {
endWifiSession();
return;
}
WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
String ssid = wifiInfo == null ? null : wifiInfo.getSSID();
if (mConnectedSsid == null) {
if (!TextUtils.isEmpty(ssid)) {
mConnectedSsid = ssid;
}
} else if (!TextUtils.equals(ssid, mConnectedSsid)) {
endWifiSession();
}
}
private void endWifiSession() {
if (mWifiSessionStarted) {
mWifiSessionStarted = false;
cancelNotificationIfNeeded();
mConnectedSsid = null;
mContext.unregisterReceiver(mBroadcastReceiver);
}
}
private void cancelNotificationIfNeeded() {
if (mNotificationShown) {
mNotificationShown = false;
mNotificationManager.cancel(TAG, NOTIFICATION_ID);
}
}
}