summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe LaPenna <jlapenna@google.com>2017-03-24 17:48:30 -0700
committerJoe LaPenna <jlapenna@google.com>2017-03-30 10:07:52 -0700
commit69639e9bb98d976123459e4dcc09e50abc81c8f1 (patch)
tree41b378cfbd250827874d04c25e9d51fdc2f7be57
parent019e6518fe5e95880703ca43b7a5f2e81437319f (diff)
downloadNetworkRecommendation-69639e9bb98d976123459e4dcc09e50abc81c8f1.tar.gz
Update netrec.
Test: mma NetworkRecommendation RunNetworkRecommendationRoboTests Bug: 34944625 Change-Id: Ie20ab4ec5f46e944bd55558e1567df66094e6b64
-rw-r--r--AndroidManifest.xml5
-rw-r--r--res/values/config.xml4
-rw-r--r--res/values/strings.xml19
-rw-r--r--robotests/src/com/android/networkrecommendation/notify/WifiNotificationControllerTest.java54
-rw-r--r--robotests/src/com/android/networkrecommendation/notify/WifiNotificationHelperTest.java71
-rw-r--r--robotests/src/com/android/networkrecommendation/shadows/BitmapGetPixelsShadow.java15
-rw-r--r--robotests/src/com/android/networkrecommendation/shadows/ShadowNotificationChannelUtil.java42
-rw-r--r--robotests/src/com/android/networkrecommendation/util/SsidUtilTest.java6
-rw-r--r--robotests/src/com/android/networkrecommendation/wakeup/WifiWakeupControllerTest.java86
-rw-r--r--robotests/src/com/android/networkrecommendation/wakeup/WifiWakeupHelperTest.java49
-rw-r--r--src/com/android/networkrecommendation/NetworkRecommendationApp.java17
-rw-r--r--src/com/android/networkrecommendation/NetworkRecommendationService.java6
-rw-r--r--src/com/android/networkrecommendation/config/PreferenceFile.java299
-rw-r--r--src/com/android/networkrecommendation/config/Preferences.java75
-rw-r--r--src/com/android/networkrecommendation/notify/WifiNotificationController.java42
-rw-r--r--src/com/android/networkrecommendation/notify/WifiNotificationHelper.java197
-rw-r--r--src/com/android/networkrecommendation/scoring/util/HashUtil.java93
-rw-r--r--src/com/android/networkrecommendation/scoring/util/NetworkUtil.java164
-rw-r--r--src/com/android/networkrecommendation/scoring/util/Util.java33
-rw-r--r--src/com/android/networkrecommendation/util/ImageUtil.java62
-rw-r--r--src/com/android/networkrecommendation/util/NotificationChannelUtil.java69
-rw-r--r--src/com/android/networkrecommendation/util/RoboCompatUtil.java5
-rw-r--r--src/com/android/networkrecommendation/util/SsidUtil.java12
-rw-r--r--src/com/android/networkrecommendation/wakeup/WifiWakeupController.java72
-rw-r--r--src/com/android/networkrecommendation/wakeup/WifiWakeupHelper.java55
-rw-r--r--tests/src/com/android/networkrecommendation/NetworkRecommendationServiceTest.java3
26 files changed, 1099 insertions, 456 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 0b21a24..3c61f98 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -27,7 +27,8 @@
<uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
- <application android:allowBackup="false"
+ <application android:name=".NetworkRecommendationApp"
+ android:allowBackup="false"
android:directBootAware="true">
<!-- Only the platform can bind to this service -->
@@ -35,6 +36,8 @@
android:permission="android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE">
<meta-data android:name="android.net.scoring.recommendation_service_label"
android:value="@string/network_recommendation_service_label"/>
+ <meta-data android:name="android.net.wifi.notification_channel_id_network_available"
+ android:value="com.android.networkrecommendation.Notifications.WifiMessageGroup.NetworkAvailableChannel" />
<intent-filter>
<action android:name="android.net.action.RECOMMEND_NETWORKS" />
</intent-filter>
diff --git a/res/values/config.xml b/res/values/config.xml
index 3762e90..4167ebd 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -18,9 +18,13 @@
<integer translatable="false" name="config_netrec_5GHz_preference_boost_factor">40</integer>
<integer translatable="false" name="config_netrec_RSSI_SCORE_OFFSET">85</integer>
<integer translatable="false" name="config_netrec_RSSI_SCORE_SLOPE">4</integer>
+ <integer translatable="false" name="config_netrec_SAME_BSSID_AWARD">24</integer>
+ <integer translatable="false" name="config_netrec_LAST_SELECTION_AWARD">480</integer>
<integer translatable="false" name="config_netrec_PASSPOINT_SECURITY_AWARD">40</integer>
<integer translatable="false" name="config_netrec_SECURITY_AWARD">80</integer>
<integer translatable="false" name="config_netrec_wifi_score_low_rssi_threshold_5GHz">-70</integer>
<integer translatable="false" name="config_netrec_wifi_score_low_rssi_threshold_24GHz">-73</integer>
<integer translatable="false" name="config_netrec_wifi_score_good_rssi_threshold_24GHz">-60</integer>
+ <integer translatable="false" name="config_netrec_score_good_rssi_threshold">-60</integer>
+ <integer translatable="false" name="config_netrec_current_network_boost">16</integer>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4916767..e208b4c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -18,18 +18,6 @@
<!-- The service label for network recommendation service. [CHAR LIMIT=40] -->
<string name="network_recommendation_service_label">System default</string>
- <!-- A notification is shown when there is a high quality open wireless network nearby. This is the notification's title. -->
- <string name="wifi_available">Connect to Wi\u2011Fi Network</string>
-
- <!-- A notification is shown when there is a high quality open wireless network nearby. These are the different notification actions. -->
- <string name="wifi_available_options">Options</string>
- <string name="wifi_available_connect">Connect</string>
- <string name="wifi_available_connecting">Connecting</string>
- <string name="wifi_available_connected">Connected</string>
- <string name="wifi_available_failed">FAILED TO CONNECT</string>
-
- <string name="android_system_label">Android System</string>
-
<!-- Notification title when there is a high quality open wireless network nearby.-->
<string name="wifi_available_title">Connect to open Wi\u2011Fi network</string>
<!-- Notification title when the system is connecting to a high quality open network. -->
@@ -52,4 +40,11 @@
<!-- Text used to indicate that a connection attempt is ongoing [CHAR LIMIT=20] -->
<string name="common_connecting">Connecting&#8230;</string>
+
+ <!-- Name of the notification channel group of our Wi-Fi messages -->
+ <string name="notification_channel_group_name">Wi\u2011Fi messages</string>
+ <!-- Name of the notification channel for a notification shown when there is a high quality open wireless network nearby. -->
+ <string name="notification_channel_wakeup_name">Wi\u2011Fi turned on</string>
+ <!-- Name of the notification channel for a notification shown when Wi-Fi Wakeup enables Wi-Fi.. -->
+ <string name="notification_channel_network_available">Network available</string>
</resources>
diff --git a/robotests/src/com/android/networkrecommendation/notify/WifiNotificationControllerTest.java b/robotests/src/com/android/networkrecommendation/notify/WifiNotificationControllerTest.java
index 943ffc7..3f4828f 100644
--- a/robotests/src/com/android/networkrecommendation/notify/WifiNotificationControllerTest.java
+++ b/robotests/src/com/android/networkrecommendation/notify/WifiNotificationControllerTest.java
@@ -30,7 +30,6 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Intent;
-import android.graphics.Bitmap;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkInfo.State;
@@ -129,11 +128,6 @@ public class WifiNotificationControllerTest {
return config;
}
- private void createFakeBitmap() {
- when(mWifiNotificationHelper.createNotificationBadgeBitmap(any(), any()))
- .thenReturn(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888));
- }
-
/**
* When the NetworkRecommendationService associated with this WifiNotificationController is
* unbound, this WifiWakeupController should no longer function.
@@ -157,7 +151,6 @@ public class WifiNotificationControllerTest {
when(mNetworkInfo.getDetailedState()).thenReturn(DetailedState.DISCONNECTED);
mBroadcastIntentTestHelper.sendNetworkStateChanged(mNetworkInfo);
setOpenAccessPoints();
- createFakeBitmap();
when(mNetworkRecommendationProvider.requestRecommendation(any(RecommendationRequest.class)))
.thenReturn(RecommendationResult.createConnectRecommendation(createFakeConfig()));
@@ -182,8 +175,7 @@ public class WifiNotificationControllerTest {
// The third scan result notification will trigger the notification.
mBroadcastIntentTestHelper.sendScanResultsAvailable();
- verify(mWifiNotificationHelper)
- .createMainNotification(any(WifiConfiguration.class), any(Bitmap.class));
+ verify(mWifiNotificationHelper).createMainNotification(any(WifiConfiguration.class));
verify(mNotificationManager).notify(anyString(), anyInt(), any(Notification.class));
verify(mNotificationManager, never()).cancel(anyString(), anyInt());
}
@@ -197,7 +189,6 @@ public class WifiNotificationControllerTest {
when(mNetworkInfo.getDetailedState()).thenReturn(DetailedState.DISCONNECTED);
mBroadcastIntentTestHelper.sendNetworkStateChanged(mNetworkInfo);
setOpenAccessPoints();
- createFakeBitmap();
// Recommendation result with no WifiConfiguration returned.
when(mNetworkRecommendationProvider.requestRecommendation(any(RecommendationRequest.class)))
@@ -223,7 +214,6 @@ public class WifiNotificationControllerTest {
when(mNetworkInfo.getDetailedState()).thenReturn(DetailedState.DISCONNECTED);
mBroadcastIntentTestHelper.sendNetworkStateChanged(mNetworkInfo);
setOpenAccessPoints();
- createFakeBitmap();
when(mNetworkRecommendationProvider.requestRecommendation(any(RecommendationRequest.class)))
.thenReturn(RecommendationResult.createConnectRecommendation(createFakeConfig()));
@@ -231,8 +221,7 @@ public class WifiNotificationControllerTest {
mBroadcastIntentTestHelper.sendScanResultsAvailable();
mBroadcastIntentTestHelper.sendScanResultsAvailable();
mBroadcastIntentTestHelper.sendScanResultsAvailable();
- verify(mWifiNotificationHelper)
- .createMainNotification(any(WifiConfiguration.class), any(Bitmap.class));
+ verify(mWifiNotificationHelper).createMainNotification(any(WifiConfiguration.class));
verify(mNotificationManager).notify(anyString(), anyInt(), any(Notification.class));
// Send connect intent, should attempt to connect to Wi-Fi
@@ -240,8 +229,7 @@ public class WifiNotificationControllerTest {
new Intent(WifiNotificationController.ACTION_CONNECT_TO_RECOMMENDED_NETWORK);
ShadowApplication.getInstance().sendBroadcast(intent);
verify(mRoboCompatUtil).connectToWifi(any(WifiManager.class), any(WifiConfiguration.class));
- verify(mWifiNotificationHelper)
- .createConnectingNotification(any(WifiConfiguration.class), any(Bitmap.class));
+ verify(mWifiNotificationHelper).createConnectingNotification(any(WifiConfiguration.class));
// Show connecting notification.
verify(mNotificationManager, times(2))
@@ -250,8 +238,7 @@ public class WifiNotificationControllerTest {
// Verify show connected notification.
when(mNetworkInfo.getDetailedState()).thenReturn(DetailedState.CONNECTED);
mBroadcastIntentTestHelper.sendNetworkStateChanged(mNetworkInfo);
- verify(mWifiNotificationHelper)
- .createConnectedNotification(any(WifiConfiguration.class), any(Bitmap.class));
+ verify(mWifiNotificationHelper).createConnectedNotification(any(WifiConfiguration.class));
verify(mNotificationManager, times(3))
.notify(anyString(), anyInt(), any(Notification.class));
@@ -269,7 +256,6 @@ public class WifiNotificationControllerTest {
when(mNetworkInfo.getDetailedState()).thenReturn(DetailedState.DISCONNECTED);
mBroadcastIntentTestHelper.sendNetworkStateChanged(mNetworkInfo);
setOpenAccessPoints();
- createFakeBitmap();
when(mNetworkRecommendationProvider.requestRecommendation(any(RecommendationRequest.class)))
.thenReturn(RecommendationResult.createConnectRecommendation(createFakeConfig()));
@@ -277,8 +263,7 @@ public class WifiNotificationControllerTest {
mBroadcastIntentTestHelper.sendScanResultsAvailable();
mBroadcastIntentTestHelper.sendScanResultsAvailable();
mBroadcastIntentTestHelper.sendScanResultsAvailable();
- verify(mWifiNotificationHelper)
- .createMainNotification(any(WifiConfiguration.class), any(Bitmap.class));
+ verify(mWifiNotificationHelper).createMainNotification(any(WifiConfiguration.class));
verify(mNotificationManager).notify(anyString(), anyInt(), any(Notification.class));
// Send connect intent, should attempt to connect to Wi-Fi
@@ -286,8 +271,7 @@ public class WifiNotificationControllerTest {
new Intent(WifiNotificationController.ACTION_CONNECT_TO_RECOMMENDED_NETWORK);
ShadowApplication.getInstance().sendBroadcast(intent);
verify(mRoboCompatUtil).connectToWifi(any(WifiManager.class), any(WifiConfiguration.class));
- verify(mWifiNotificationHelper)
- .createConnectingNotification(any(WifiConfiguration.class), any(Bitmap.class));
+ verify(mWifiNotificationHelper).createConnectingNotification(any(WifiConfiguration.class));
// Show connecting notification.
verify(mNotificationManager, times(2))
@@ -295,8 +279,7 @@ public class WifiNotificationControllerTest {
// Show failed to connect notification.
ShadowLooper.runMainLooperToNextTask();
- verify(mWifiNotificationHelper)
- .createFailedToConnectNotification(any(WifiConfiguration.class));
+ verify(mWifiNotificationHelper).createFailedToConnectNotification();
// Dismissed the cancel notification.
ShadowLooper.runMainLooperToNextTask();
@@ -312,7 +295,6 @@ public class WifiNotificationControllerTest {
when(mNetworkInfo.getDetailedState()).thenReturn(DetailedState.DISCONNECTED);
mBroadcastIntentTestHelper.sendNetworkStateChanged(mNetworkInfo);
setOpenAccessPoints();
- createFakeBitmap();
when(mNetworkRecommendationProvider.requestRecommendation(any(RecommendationRequest.class)))
.thenReturn(RecommendationResult.createConnectRecommendation(createFakeConfig()));
@@ -322,8 +304,7 @@ public class WifiNotificationControllerTest {
mBroadcastIntentTestHelper.sendScanResultsAvailable();
// Show main notification
- verify(mWifiNotificationHelper)
- .createMainNotification(any(WifiConfiguration.class), any(Bitmap.class));
+ verify(mWifiNotificationHelper).createMainNotification(any(WifiConfiguration.class));
verify(mNotificationManager).notify(anyString(), anyInt(), any(Notification.class));
// Send dismiss intent
@@ -340,7 +321,6 @@ public class WifiNotificationControllerTest {
when(mNetworkInfo.getDetailedState()).thenReturn(DetailedState.DISCONNECTED);
mBroadcastIntentTestHelper.sendNetworkStateChanged(mNetworkInfo);
setOpenAccessPoints();
- createFakeBitmap();
when(mNetworkRecommendationProvider.requestRecommendation(any(RecommendationRequest.class)))
.thenReturn(RecommendationResult.createConnectRecommendation(createFakeConfig()));
@@ -350,8 +330,7 @@ public class WifiNotificationControllerTest {
mBroadcastIntentTestHelper.sendScanResultsAvailable();
// Show main notification
- verify(mWifiNotificationHelper)
- .createMainNotification(any(WifiConfiguration.class), any(Bitmap.class));
+ verify(mWifiNotificationHelper).createMainNotification(any(WifiConfiguration.class));
verify(mNotificationManager).notify(anyString(), anyInt(), any(Notification.class));
// Send click settings intent
@@ -369,7 +348,6 @@ public class WifiNotificationControllerTest {
when(mNetworkInfo.getDetailedState()).thenReturn(DetailedState.DISCONNECTED);
mBroadcastIntentTestHelper.sendNetworkStateChanged(mNetworkInfo);
setOpenAccessPoints();
- createFakeBitmap();
when(mNetworkRecommendationProvider.requestRecommendation(any(RecommendationRequest.class)))
.thenReturn(RecommendationResult.createConnectRecommendation(createFakeConfig()));
@@ -379,8 +357,7 @@ public class WifiNotificationControllerTest {
mBroadcastIntentTestHelper.sendScanResultsAvailable();
// Show main notification
- verify(mWifiNotificationHelper)
- .createMainNotification(any(WifiConfiguration.class), any(Bitmap.class));
+ verify(mWifiNotificationHelper).createMainNotification(any(WifiConfiguration.class));
verify(mNotificationManager).notify(anyString(), anyInt(), any(Notification.class));
when(mNetworkInfo.getDetailedState()).thenReturn(DetailedState.CAPTIVE_PORTAL_CHECK);
@@ -426,7 +403,6 @@ public class WifiNotificationControllerTest {
when(mNetworkInfo.getDetailedState()).thenReturn(DetailedState.DISCONNECTED);
mBroadcastIntentTestHelper.sendNetworkStateChanged(mNetworkInfo);
setOpenAccessPoints();
- createFakeBitmap();
when(mNetworkRecommendationProvider.requestRecommendation(any(RecommendationRequest.class)))
.thenReturn(RecommendationResult.createConnectRecommendation(createFakeConfig()));
@@ -437,8 +413,7 @@ public class WifiNotificationControllerTest {
verify(mNetworkRecommendationProvider, times(3)).requestRecommendation(any());
// Show main notification
- verify(mWifiNotificationHelper)
- .createMainNotification(any(WifiConfiguration.class), any(Bitmap.class));
+ verify(mWifiNotificationHelper).createMainNotification(any(WifiConfiguration.class));
verify(mNotificationManager).notify(anyString(), anyInt(), any(Notification.class));
// Send connect intent, should attempt to connect to Wi-Fi
@@ -446,8 +421,7 @@ public class WifiNotificationControllerTest {
new Intent(WifiNotificationController.ACTION_CONNECT_TO_RECOMMENDED_NETWORK);
ShadowApplication.getInstance().sendBroadcast(intent);
verify(mRoboCompatUtil).connectToWifi(any(WifiManager.class), any(WifiConfiguration.class));
- verify(mWifiNotificationHelper)
- .createConnectingNotification(any(WifiConfiguration.class), any(Bitmap.class));
+ verify(mWifiNotificationHelper).createConnectingNotification(any(WifiConfiguration.class));
verify(mNotificationManager, times(2))
.notify(anyString(), anyInt(), any(Notification.class));
@@ -465,7 +439,6 @@ public class WifiNotificationControllerTest {
when(mNetworkInfo.getDetailedState()).thenReturn(DetailedState.DISCONNECTED);
mBroadcastIntentTestHelper.sendNetworkStateChanged(mNetworkInfo);
setOpenAccessPoints();
- createFakeBitmap();
when(mNetworkRecommendationProvider.requestRecommendation(any(RecommendationRequest.class)))
.thenReturn(RecommendationResult.createConnectRecommendation(createFakeConfig()));
@@ -476,8 +449,7 @@ public class WifiNotificationControllerTest {
verify(mNetworkRecommendationProvider, times(3)).requestRecommendation(any());
// Show main notification
- verify(mWifiNotificationHelper)
- .createMainNotification(any(WifiConfiguration.class), any(Bitmap.class));
+ verify(mWifiNotificationHelper).createMainNotification(any(WifiConfiguration.class));
verify(mNotificationManager).notify(anyString(), anyInt(), any(Notification.class));
// Update main notification.
diff --git a/robotests/src/com/android/networkrecommendation/notify/WifiNotificationHelperTest.java b/robotests/src/com/android/networkrecommendation/notify/WifiNotificationHelperTest.java
index 35856aa..4a37e6c 100644
--- a/robotests/src/com/android/networkrecommendation/notify/WifiNotificationHelperTest.java
+++ b/robotests/src/com/android/networkrecommendation/notify/WifiNotificationHelperTest.java
@@ -15,42 +15,30 @@
*/
package com.android.networkrecommendation.notify;
-import static com.android.networkrecommendation.PlatformTestObjectFactory.createOpenNetworkScanResult;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.when;
import android.app.Notification;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.net.NetworkBadging;
-import android.net.ScoredNetwork;
-import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import com.android.networkrecommendation.SynchronousNetworkRecommendationProvider;
import com.android.networkrecommendation.TestData;
import com.android.networkrecommendation.shadows.BitmapGetPixelsShadow;
+import com.android.networkrecommendation.shadows.ShadowNotificationChannelUtil;
+import com.android.networkrecommendation.config.Flag;
import com.android.networkrecommendation.util.RoboCompatUtil;
-import com.google.common.collect.Lists;
-import java.util.ArrayList;
-import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowSettings;
/** Unit tests for {@link WifiNotificationHelper} */
@RunWith(RobolectricTestRunner.class)
@Config(manifest = "packages/services/NetworkRecommendation/AndroidManifest.xml", sdk = 23,
-shadows={BitmapGetPixelsShadow.class})
+shadows={BitmapGetPixelsShadow.class, ShadowNotificationChannelUtil.class})
public class WifiNotificationHelperTest {
private Context mContext;
@@ -65,11 +53,11 @@ public class WifiNotificationHelperTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ Flag.initForTest();
RoboCompatUtil.setInstanceForTesting(mRoboCompatUtil);
mContext = RuntimeEnvironment.application;
- mWifiNotificationHelper =
- new WifiNotificationHelper(mContext, mSynchronousNetworkRecommendationProvider);
+ mWifiNotificationHelper = new WifiNotificationHelper(mContext);
}
private static WifiConfiguration createFakeConfig() {
@@ -80,71 +68,30 @@ public class WifiNotificationHelperTest {
return config;
}
- private static Bitmap createFakeIcon() {
- return Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
- }
-
private static void assertValidNotification(Notification notification) {
assertNotNull(notification);
assertNotNull(notification.getSmallIcon());
- assertNotNull(notification.getLargeIcon());
}
@Test
public void createMainNotification() {
- assertValidNotification(
- mWifiNotificationHelper.createMainNotification(
- createFakeConfig(), createFakeIcon()));
+ assertValidNotification(mWifiNotificationHelper.createMainNotification(createFakeConfig()));
}
@Test
public void createConnectingNotification() {
assertValidNotification(
- mWifiNotificationHelper.createConnectingNotification(
- createFakeConfig(), createFakeIcon()));
+ mWifiNotificationHelper.createConnectingNotification(createFakeConfig()));
}
@Test
public void createConnectedNotification() {
assertValidNotification(
- mWifiNotificationHelper.createConnectedNotification(
- createFakeConfig(), createFakeIcon()));
+ mWifiNotificationHelper.createConnectedNotification(createFakeConfig()));
}
@Test
public void createFailedToConnectNotification() {
- assertValidNotification(
- mWifiNotificationHelper.createFailedToConnectNotification(createFakeConfig()));
- }
-
- @Test
- public void createNotificationBadgeBitmap() {
- WifiConfiguration wifiConfig = createFakeConfig();
- List<ScanResult> scanResultList =
- Lists.newArrayList(createOpenNetworkScanResult(wifiConfig.SSID, wifiConfig.BSSID));
- when(mSynchronousNetworkRecommendationProvider.getCachedScoredNetwork(any()))
- .thenReturn(Mockito.mock(ScoredNetwork.class));
- when(mRoboCompatUtil.calculateBadge(any(), anyInt())).thenReturn(NetworkBadging.BADGING_4K);
- when(mRoboCompatUtil.getWifiIcon(anyInt(), anyInt(), any()))
- .thenReturn(mContext.getDrawable(android.R.drawable.stat_sys_warning));
-
- assertNotNull(
- mWifiNotificationHelper.createNotificationBadgeBitmap(wifiConfig, scanResultList));
-
- ShadowSettings.ShadowGlobal.putInt(
- mContext.getContentResolver(),
- WifiNotificationHelper.NETWORK_SCORING_UI_ENABLED,
- 1);
- assertNotNull(
- mWifiNotificationHelper.createNotificationBadgeBitmap(wifiConfig, scanResultList));
- }
-
- @Test
- public void createNotificationBadgeBitmap_noMatchingScanResults() {
- WifiConfiguration wifiConfig = createFakeConfig();
- List<ScanResult> scanResultList = new ArrayList<>();
-
- assertNull(
- mWifiNotificationHelper.createNotificationBadgeBitmap(wifiConfig, scanResultList));
+ assertValidNotification(mWifiNotificationHelper.createFailedToConnectNotification());
}
}
diff --git a/robotests/src/com/android/networkrecommendation/shadows/BitmapGetPixelsShadow.java b/robotests/src/com/android/networkrecommendation/shadows/BitmapGetPixelsShadow.java
index 8912305..c1a8c23 100644
--- a/robotests/src/com/android/networkrecommendation/shadows/BitmapGetPixelsShadow.java
+++ b/robotests/src/com/android/networkrecommendation/shadows/BitmapGetPixelsShadow.java
@@ -1,3 +1,18 @@
+/*
+ * 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.shadows;
import android.annotation.ColorInt;
diff --git a/robotests/src/com/android/networkrecommendation/shadows/ShadowNotificationChannelUtil.java b/robotests/src/com/android/networkrecommendation/shadows/ShadowNotificationChannelUtil.java
new file mode 100644
index 0000000..c8e6d26
--- /dev/null
+++ b/robotests/src/com/android/networkrecommendation/shadows/ShadowNotificationChannelUtil.java
@@ -0,0 +1,42 @@
+/*
+ * 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.shadows;
+
+import android.app.Notification.Builder;
+import android.app.NotificationManager;
+import android.content.Context;
+import com.android.networkrecommendation.util.NotificationChannelUtil;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+/**
+ * A temporary shadow which is only useful until NotificationChannel and NotificationChannelGroup
+ * classes is available to Robolectric tests. TODO(b/35959851): remove this class.
+ */
+@Implements(NotificationChannelUtil.class)
+public class ShadowNotificationChannelUtil {
+
+ @Implementation
+ public static void configureNotificationChannels(
+ NotificationManager notificationManager, Context context) {
+ // Do nothing
+ }
+
+ @Implementation
+ public static Builder setChannel(Builder notificationBuilder, String channelId) {
+ return notificationBuilder;
+ }
+}
diff --git a/robotests/src/com/android/networkrecommendation/util/SsidUtilTest.java b/robotests/src/com/android/networkrecommendation/util/SsidUtilTest.java
index e3cdff8..1c1bd07 100644
--- a/robotests/src/com/android/networkrecommendation/util/SsidUtilTest.java
+++ b/robotests/src/com/android/networkrecommendation/util/SsidUtilTest.java
@@ -15,7 +15,7 @@
*/
package com.android.networkrecommendation.util;
-import static com.android.networkrecommendation.TestData.NETWORK_KEY1;
+import static com.android.networkrecommendation.TestData.BSSID_1;
import static com.android.networkrecommendation.TestData.SSID_1;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
@@ -71,12 +71,12 @@ public class SsidUtilTest {
@Test
public void testRedactedId() {
G.Netrec.enableSensitiveLogging.override(false);
- assertThat(SsidUtil.getRedactedId(NETWORK_KEY1)).doesNotContain(SSID_1);
+ assertThat(SsidUtil.getRedactedId(SSID_1, BSSID_1)).doesNotContain(SSID_1);
}
@Test
public void testRedactedId_sensitiveEnabled() {
G.Netrec.enableSensitiveLogging.override(true);
- assertEquals("\"ssid1\"/01:01:01:01:01:01", SsidUtil.getRedactedId(NETWORK_KEY1));
+ assertEquals("\"ssid1\"/01:01:01:01:01:01", SsidUtil.getRedactedId(SSID_1, BSSID_1));
}
}
diff --git a/robotests/src/com/android/networkrecommendation/wakeup/WifiWakeupControllerTest.java b/robotests/src/com/android/networkrecommendation/wakeup/WifiWakeupControllerTest.java
index ac30e8e..01e7db1 100644
--- a/robotests/src/com/android/networkrecommendation/wakeup/WifiWakeupControllerTest.java
+++ b/robotests/src/com/android/networkrecommendation/wakeup/WifiWakeupControllerTest.java
@@ -15,6 +15,7 @@
*/
package com.android.networkrecommendation.wakeup;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyList;
@@ -36,8 +37,12 @@ import android.os.PowerManager;
import android.provider.Settings;
import com.android.networkrecommendation.BroadcastIntentTestHelper;
import com.android.networkrecommendation.config.Flag;
+import com.android.networkrecommendation.config.PreferenceFile;
+import com.android.networkrecommendation.config.Preferences;
import com.android.networkrecommendation.config.WideAreaNetworks;
+import com.android.networkrecommendation.scoring.util.HashUtil;
import com.android.networkrecommendation.util.RoboCompatUtil;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -94,6 +99,7 @@ public class WifiWakeupControllerTest {
MockitoAnnotations.initMocks(this);
Flag.initForTest();
RoboCompatUtil.setInstanceForTesting(mRoboCompatUtil);
+ PreferenceFile.init(RuntimeEnvironment.application);
mSavedWifiConfiguration = new WifiConfiguration();
mSavedWifiConfiguration.SSID = "\"" + SAVED_SCAN_RESULT.SSID + "\"";
@@ -117,6 +123,7 @@ public class WifiWakeupControllerTest {
Settings.Global.putInt(mContentResolver, Settings.Global.AIRPLANE_MODE_ON, 0);
when(mWifiManager.getWifiApState()).thenReturn(WifiManager.WIFI_AP_STATE_DISABLED);
ShadowLooper.resetThreadLoopers();
+ Preferences.savedSsidsOnDisable.remove();
mWifiWakeupController =
new WifiWakeupController(
@@ -146,6 +153,44 @@ public class WifiWakeupControllerTest {
}
/**
+ * When {@link Settings.Global.WIFI_WAKEUP_ENABLED} is disabled, scan results should not be
+ * processed.
+ */
+ @Test
+ public void wifiWakeupControllerStarted_settingDisabled() {
+ Settings.Global.putInt(mContentResolver, Settings.Global.WIFI_WAKEUP_ENABLED, 0);
+ when(mWifiManager.getConfiguredNetworks())
+ .thenReturn(Lists.newArrayList(mSavedWifiConfiguration, mSavedWifiConfiguration2));
+ when(mWifiManager.getScanResults())
+ .thenReturn(
+ Lists.newArrayList(SAVED_SCAN_RESULT),
+ Lists.newArrayList(SAVED_SCAN_RESULT2));
+ when(mWifiWakeupNetworkSelector.selectNetwork(anyMap(), anyList()))
+ .thenReturn(mSavedWifiConfiguration2);
+ when(mWifiManager.getWifiState())
+ .thenReturn(WifiManager.WIFI_STATE_ENABLED, WifiManager.WIFI_STATE_DISABLED);
+
+ mWifiWakeupController.mContentObserver.onChange(true);
+ mBroadcastIntentTestHelper.sendWifiStateChanged();
+ mBroadcastIntentTestHelper.sendConfiguredNetworksChanged();
+ mBroadcastIntentTestHelper.sendScanResultsAvailable();
+ mBroadcastIntentTestHelper.sendWifiStateChanged();
+ mBroadcastIntentTestHelper.sendScanResultsAvailable();
+ mBroadcastIntentTestHelper.sendScanResultsAvailable();
+ mBroadcastIntentTestHelper.sendScanResultsAvailable();
+
+ verify(mWifiManager, never()).setWifiEnabled(true);
+
+ Settings.Global.putInt(mContentResolver, Settings.Global.WIFI_WAKEUP_ENABLED, 1);
+ mWifiWakeupController.mContentObserver.onChange(true);
+
+ mBroadcastIntentTestHelper.sendScanResultsAvailable();
+
+ verify(mWifiManager).setWifiEnabled(true);
+ verify(mWifiWakeupHelper).startWifiSession(mSavedWifiConfiguration2);
+ }
+
+ /**
* When Wi-Fi is disabled and a saved network is in the scan list, and then this network is not
* in the scan list 3x, and then it is, Wi-Fi should be enabled.
*/
@@ -263,6 +308,47 @@ public class WifiWakeupControllerTest {
}
/**
+ * When Wi-Fi is disabled near a saved network, and WifiWakeupController stops and starts, Wi-Fi
+ * should not be enabled.
+ */
+ @Test
+ public void userDisabledWifiNearSavedNetwork_controllerStopped_controllerStarted() {
+ when(mWifiManager.getConfiguredNetworks())
+ .thenReturn(Lists.newArrayList(mSavedWifiConfiguration));
+ when(mWifiManager.getScanResults()).thenReturn(Lists.newArrayList(SAVED_SCAN_RESULT));
+ when(mWifiWakeupNetworkSelector.selectNetwork(anyMap(), anyList()))
+ .thenReturn(mSavedWifiConfiguration);
+ when(mWifiManager.getWifiState())
+ .thenReturn(WifiManager.WIFI_STATE_ENABLED, WifiManager.WIFI_STATE_DISABLED);
+
+ mBroadcastIntentTestHelper.sendWifiStateChanged();
+ mBroadcastIntentTestHelper.sendConfiguredNetworksChanged();
+ mBroadcastIntentTestHelper.sendScanResultsAvailable();
+ mBroadcastIntentTestHelper.sendWifiStateChanged();
+ mWifiWakeupController.stop();
+
+ assertEquals(
+ ImmutableSet.of(HashUtil.getSsidHash(SAVED_SCAN_RESULT.SSID)),
+ Preferences.savedSsidsOnDisable.get());
+
+ mWifiWakeupController =
+ new WifiWakeupController(
+ RuntimeEnvironment.application,
+ mContentResolver,
+ new Handler(ShadowLooper.getMainLooper()),
+ mWifiManager,
+ mPowerManager,
+ mWifiWakeupNetworkSelector,
+ mWifiWakeupHelper);
+ mWifiWakeupController.start();
+ mBroadcastIntentTestHelper.sendScanResultsAvailable();
+ mBroadcastIntentTestHelper.sendScanResultsAvailable();
+ mBroadcastIntentTestHelper.sendScanResultsAvailable();
+
+ verify(mWifiManager, never()).setWifiEnabled(true);
+ }
+
+ /**
* When Wi-Fi is disabled and a saved network is in the scan list, but {@link
* WifiWakeupNetworkSelector}, does not choose this network, Wi-Fi should not be enabled.
*/
diff --git a/robotests/src/com/android/networkrecommendation/wakeup/WifiWakeupHelperTest.java b/robotests/src/com/android/networkrecommendation/wakeup/WifiWakeupHelperTest.java
index a74e5fc..3840771 100644
--- a/robotests/src/com/android/networkrecommendation/wakeup/WifiWakeupHelperTest.java
+++ b/robotests/src/com/android/networkrecommendation/wakeup/WifiWakeupHelperTest.java
@@ -15,6 +15,8 @@
*/
package com.android.networkrecommendation.wakeup;
+import static com.android.networkrecommendation.TestData.SSID_1;
+import static com.android.networkrecommendation.TestData.UNQUOTED_SSID_1;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -30,14 +32,18 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Looper;
+import android.provider.Settings;
+import android.util.ArraySet;
import com.android.networkrecommendation.config.Flag;
-import com.google.common.collect.ImmutableSet;
+import com.android.networkrecommendation.config.PreferenceFile;
+import com.android.networkrecommendation.config.Preferences;
+import com.android.networkrecommendation.scoring.util.HashUtil;
+import com.android.networkrecommendation.shadows.ShadowNotificationChannelUtil;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
@@ -52,17 +58,15 @@ import org.robolectric.shadows.ShadowLooper;
/** Unit tests for {@link WifiWakeupHelper} */
@RunWith(RobolectricTestRunner.class)
-@Config(manifest = "packages/services/NetworkRecommendation/AndroidManifest.xml", sdk = 23)
+@Config(manifest = "packages/services/NetworkRecommendation/AndroidManifest.xml", sdk = 23,
+shadows={ShadowNotificationChannelUtil.class})
public class WifiWakeupHelperTest {
- private static final String SSID = "ssid";
-
private Context mContext;
private WifiConfiguration mWifiConfiguration;
@Mock private NotificationManager mNotificationManager;
@Mock private WifiManager mWifiManager;
@Mock private WifiInfo mWifiInfo;
- private SharedPreferences mSharedPreferences;
private WifiWakeupHelper mWifiWakeupHelper;
@@ -70,11 +74,12 @@ public class WifiWakeupHelperTest {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Flag.initForTest();
- mWifiConfiguration = new WifiConfiguration();
- mWifiConfiguration.SSID = "\"" + SSID + "\"";
-
mContext = RuntimeEnvironment.application;
- mSharedPreferences = mContext.getSharedPreferences("wifi_wakeup", Context.MODE_PRIVATE);
+ PreferenceFile.init(mContext);
+ Preferences.ssidsForWakeupShown.remove();
+
+ mWifiConfiguration = new WifiConfiguration();
+ mWifiConfiguration.SSID = SSID_1;
when(mWifiManager.getConnectionInfo()).thenReturn(mWifiInfo);
@@ -84,8 +89,7 @@ public class WifiWakeupHelperTest {
mContext.getResources(),
new Handler(Looper.getMainLooper()),
mNotificationManager,
- mWifiManager,
- mSharedPreferences);
+ mWifiManager);
}
@Test
@@ -97,10 +101,9 @@ public class WifiWakeupHelperTest {
verify(mNotificationManager, times(1))
.notify(anyString(), anyInt(), any(Notification.class));
- Set<String> ssidSet =
- mSharedPreferences.getStringSet(WifiWakeupHelper.KEY_SHOWN_SSIDS, null);
+ Set<String> ssidSet = Preferences.ssidsForWakeupShown.get();
assertEquals(1, ssidSet.size());
- assertTrue(ssidSet.contains(mWifiConfiguration.SSID));
+ assertTrue(ssidSet.contains(HashUtil.getSsidHash(UNQUOTED_SSID_1)));
}
@Test
@@ -115,7 +118,7 @@ public class WifiWakeupHelperTest {
public void notificationCanceledWhenWifiDisabled() {
mWifiWakeupHelper.startWifiSession(mWifiConfiguration);
- when(mWifiInfo.getSSID()).thenReturn(SSID);
+ when(mWifiInfo.getSSID()).thenReturn(UNQUOTED_SSID_1);
when(mWifiManager.isWifiEnabled()).thenReturn(true, false);
mContext.sendBroadcast(new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION));
@@ -130,7 +133,7 @@ public class WifiWakeupHelperTest {
public void notificationCanceledWhenSsidChanged() throws Exception {
mWifiWakeupHelper.startWifiSession(mWifiConfiguration);
- when(mWifiInfo.getSSID()).thenReturn(SSID, "blah");
+ when(mWifiInfo.getSSID()).thenReturn(UNQUOTED_SSID_1, "blah");
when(mWifiManager.isWifiEnabled()).thenReturn(true);
mContext.sendBroadcast(new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION));
@@ -144,12 +147,10 @@ public class WifiWakeupHelperTest {
@Test
public void sessionLoggedWithoutNotification() {
- mSharedPreferences
- .edit()
- .putStringSet(
- WifiWakeupHelper.KEY_SHOWN_SSIDS, ImmutableSet.of(mWifiConfiguration.SSID))
- .commit();
- when(mWifiInfo.getSSID()).thenReturn(SSID, "blah");
+ Set<String> ssidsShown = new ArraySet<>();
+ ssidsShown.add(HashUtil.getSsidHash(mWifiConfiguration.SSID));
+ Preferences.ssidsForWakeupShown.put(ssidsShown);
+ when(mWifiInfo.getSSID()).thenReturn(UNQUOTED_SSID_1, "blah");
when(mWifiManager.isWifiEnabled()).thenReturn(true);
mWifiWakeupHelper.startWifiSession(mWifiConfiguration);
@@ -169,7 +170,7 @@ public class WifiWakeupHelperTest {
Intent intent = Shadows.shadowOf(RuntimeEnvironment.application).getNextStartedActivity();
- assertThat(intent.getAction()).isEqualTo("android.settings.CONFIGURE_WIFI_SETTINGS");
+ assertThat(intent.getAction()).isEqualTo(Settings.ACTION_WIFI_SETTINGS);
}
@Test
diff --git a/src/com/android/networkrecommendation/NetworkRecommendationApp.java b/src/com/android/networkrecommendation/NetworkRecommendationApp.java
new file mode 100644
index 0000000..c63c875
--- /dev/null
+++ b/src/com/android/networkrecommendation/NetworkRecommendationApp.java
@@ -0,0 +1,17 @@
+package com.android.networkrecommendation;
+
+import android.app.Application;
+
+import com.android.networkrecommendation.config.PreferenceFile;
+
+/**
+ * Initialize app-wide state.
+ */
+public class NetworkRecommendationApp extends Application {
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ PreferenceFile.init(this);
+ }
+}
diff --git a/src/com/android/networkrecommendation/NetworkRecommendationService.java b/src/com/android/networkrecommendation/NetworkRecommendationService.java
index bf86c6c..2207dda 100644
--- a/src/com/android/networkrecommendation/NetworkRecommendationService.java
+++ b/src/com/android/networkrecommendation/NetworkRecommendationService.java
@@ -31,6 +31,7 @@ import android.os.PowerManager;
import com.android.networkrecommendation.notify.WifiNotificationController;
import com.android.networkrecommendation.notify.WifiNotificationHelper;
+import com.android.networkrecommendation.util.NotificationChannelUtil;
import com.android.networkrecommendation.wakeup.WifiWakeupController;
import com.android.networkrecommendation.wakeup.WifiWakeupHelper;
import com.android.networkrecommendation.wakeup.WifiWakeupNetworkSelector;
@@ -64,14 +65,15 @@ public class NetworkRecommendationService extends Service {
mControllerHandlerThread.start();
mControllerHandler = new Handler(mControllerHandlerThread.getLooper());
NotificationManager notificationManager = getSystemService(NotificationManager.class);
+ NotificationChannelUtil.configureNotificationChannels(notificationManager, this);
+
WifiManager wifiManager = getSystemService(WifiManager.class);
PowerManager powerManager = getSystemService(PowerManager.class);
Resources resources = getResources();
ContentResolver contentResolver = getContentResolver();
mWifiNotificationController = new WifiNotificationController(
this, contentResolver, mControllerHandler, mProvider,
- wifiManager, notificationManager,
- new WifiNotificationHelper(this, mProvider));
+ wifiManager, notificationManager, new WifiNotificationHelper(this));
WifiWakeupNetworkSelector wifiWakeupNetworkSelector =
new WifiWakeupNetworkSelector(resources, mProvider);
WifiWakeupHelper wifiWakeupHelper = new WifiWakeupHelper(this, resources, mControllerHandler,
diff --git a/src/com/android/networkrecommendation/config/PreferenceFile.java b/src/com/android/networkrecommendation/config/PreferenceFile.java
new file mode 100644
index 0000000..9066a6a
--- /dev/null
+++ b/src/com/android/networkrecommendation/config/PreferenceFile.java
@@ -0,0 +1,299 @@
+/*
+ * 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.config;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.os.Build;
+
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utility class for retrieving and storing key/value pairs in a SharedPreferences file.
+ *
+ * Typical usage:
+ *
+ * In your application's onCreate();
+ * PreferenceFile.init(this);
+ *
+ * In common preferences declaration area:
+ * private static final PreferenceFile sFile = new PreferenceFile("my_prefs");
+ * public static final SharedPreference<String> pageUrl = sFile.value("page_url", "http://blah");
+ *
+ * At usage time:
+ * String pageUrl = Preferences.pageUrl.get();
+ * Preferences.pageUrl.put("http://www.newurl.com/");
+ */
+public class PreferenceFile {
+ private static final String TAG = "PreferenceFile";
+
+ private static Context sContext;
+
+ public static void init(Context context) {
+ sContext = context;
+ }
+
+ private final String mName;
+ private final int mMode;
+
+ @SuppressWarnings("deprecation")
+ public PreferenceFile(String name) {
+ this(name, Context.MODE_PRIVATE);
+ }
+
+ /**
+ * @deprecated any mode other than MODE_PRIVATE is a bad idea. If you need multi-process
+ * support, see if {@link MultiProcessPreferenceFile} is suitable.
+ */
+ @Deprecated
+ public PreferenceFile(String name, int mode) {
+ mName = name;
+ mMode = mode;
+ }
+
+ /**
+ * Returns a text dump of all preferences in this file; for debugging.
+ */
+ public String dump() {
+ SharedPreferences sp = open();
+ Map<String, ?> allPrefs = sp.getAll();
+ String format = "%" + longestString(allPrefs.keySet()) + "s = %s\n";
+ StringBuilder s = new StringBuilder();
+ for (String key : allPrefs.keySet()) {
+ s.append(String.format(Locale.US, format, key, allPrefs.get(key)));
+ }
+ return s.toString();
+ }
+
+ /** Return a SharedPreferences for this file. */
+ public SharedPreferences open() {
+ return sContext.getSharedPreferences(mName, mMode);
+ }
+
+ public void remove(SharedPreference<?>... preferences) {
+ SharedPreferences.Editor editor = open().edit();
+ for (SharedPreference<?> preference : preferences) {
+ editor.remove(preference.getKey());
+ }
+ commit(editor);
+ }
+
+ /** Synchronously clear all SharedPreferences in this file. */
+ public void clear() {
+ open().edit().clear().commit();
+ }
+
+
+ /**
+ * If on API >= 9, use the asynchronous
+ * {@link Editor#apply()} method. Otherwise, use the
+ * synchronous {@link Editor#commit()} method. <br />
+ * <br />
+ * If commit() is used, the result will be returned. If apply() is used, it
+ * will always return true.
+ *
+ * @param editor The editor to save
+ * @return the result of commit() on API &lt; 9 and true on API >= 9.
+ */
+ @SuppressLint("NewApi")
+ public static boolean commit(Editor editor) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
+ return editor.commit();
+ }
+ editor.apply();
+ return true;
+ }
+
+ /** Define a new Long value shared pref key. */
+ public SharedPreference<Long> longValue(final String key, final Long defaultValue) {
+ return new SharedPreference<Long>(this, key) {
+ @Override
+ protected Long read(SharedPreferences sp) {
+ if (sp.contains(key)) {
+ return sp.getLong(key, 0L);
+ }
+ return defaultValue;
+ }
+
+ @Override
+ protected void write(Editor editor, Long value) {
+ if (value == null) {
+ throw new IllegalArgumentException("null cannot be written for Long");
+ }
+ editor.putLong(key, value);
+ }
+ };
+ }
+
+ /** Define a new String value shared pref key. */
+ public SharedPreference<String> stringValue(final String key, final String defaultValue) {
+ return new SharedPreference<String>(this, key) {
+ @Override
+ protected String read(SharedPreferences sp) {
+ if (sp.contains(key)) {
+ return sp.getString(key, null);
+ }
+ return defaultValue;
+ }
+
+ @Override
+ protected void write(Editor editor, String value) {
+ if (value == null) {
+ throw new IllegalArgumentException("null cannot be written for String");
+ }
+ editor.putString(key, value);
+ }
+ };
+ }
+
+ /** Define a new Boolean value shared pref key. */
+ public SharedPreference<Boolean> booleanValue(final String key, final Boolean defaultValue) {
+ return new SharedPreference<Boolean>(this, key) {
+ @Override
+ protected Boolean read(SharedPreferences sp) {
+ if (sp.contains(key)) {
+ return sp.getBoolean(key, false);
+ }
+ return defaultValue;
+ }
+
+ @Override
+ protected void write(Editor editor, Boolean value) {
+ if (value == null) {
+ throw new IllegalArgumentException("null cannot be written for Boolean");
+ }
+ editor.putBoolean(key, value);
+ }
+ };
+ }
+
+ /** Define a new Integer value shared pref key. */
+ public SharedPreference<Integer> intValue(final String key, final Integer defaultValue) {
+ return new SharedPreference<Integer>(this, key) {
+ @Override
+ protected Integer read(SharedPreferences sp) {
+ if (sp.contains(key)) {
+ return sp.getInt(key, 0);
+ }
+ return defaultValue;
+ }
+
+ @Override
+ protected void write(Editor editor, Integer value) {
+ if (value == null) {
+ throw new IllegalArgumentException("null cannot be written for Integer");
+ }
+ editor.putInt(key, value);
+ }
+ };
+ }
+
+ /** Define a new Set<String> value shared pref key. */
+ public SharedPreference<Set<String>> stringSetValue(final String key,
+ final Set<String> defaultValue) {
+ return new SharedPreference<Set<String>>(this, key) {
+ @Override
+ protected Set<String> read(SharedPreferences sp) {
+ if (sp.contains(key)) {
+ return sp.getStringSet(key, null);
+ }
+ return defaultValue;
+ }
+
+ @Override
+ protected void write(Editor editor, Set<String> value) {
+ if (value == null) {
+ throw new IllegalArgumentException("null cannot be written for Set<String>");
+ }
+ editor.putStringSet(key, value);
+ }
+ };
+ }
+
+ /**
+ * A class representing a key/value pair in a given {@link PreferenceFile}.
+ */
+ public static abstract class SharedPreference<T> {
+ PreferenceFile mFile;
+ final String mKey;
+
+ protected SharedPreference(PreferenceFile file, String key) {
+ mFile = file;
+ mKey = key;
+ }
+
+ /** Read the value stored for this pref, or the default value if none is stored. */
+ public final T get() {
+ return read(mFile.open());
+ }
+
+ /** Get the representation in string of the value for this pref. */
+ public String getValueString() {
+ T value = get();
+ if (value == null) {
+ return null;
+ }
+ return value.toString();
+ }
+
+ /** Return this pref's key. */
+ public final String getKey() {
+ return mKey;
+ }
+
+ /** Return true if this key is defined in its file. */
+ public final boolean exists() {
+ return mFile.open().contains(mKey);
+ }
+
+ /** Write a new value for this pref to its file. */
+ public final void put(T value) {
+ SharedPreferences sp = mFile.open();
+ Editor editor = sp.edit();
+ write(editor, value);
+ commit(editor);
+ }
+
+ /** Removes this pref from its file. */
+ public final void remove() {
+ commit(mFile.open().edit().remove(mKey));
+ }
+
+ /** Override the PreferenceFile used by this preference (for testing). */
+ public final void override(PreferenceFile file) {
+ mFile = file;
+ }
+
+ protected abstract T read(SharedPreferences sp);
+ protected abstract void write(Editor editor, T value);
+ }
+
+ /**
+ * Returns the length of the longest string in the provided Collection.
+ */
+ private static int longestString(Collection<String> strings) {
+ int longest = 0;
+ for (String s : strings) {
+ longest = Math.max(longest, s.length());
+ }
+ return longest;
+ }
+}
diff --git a/src/com/android/networkrecommendation/config/Preferences.java b/src/com/android/networkrecommendation/config/Preferences.java
new file mode 100644
index 0000000..a9e6fb0
--- /dev/null
+++ b/src/com/android/networkrecommendation/config/Preferences.java
@@ -0,0 +1,75 @@
+/*
+ * 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.config;
+
+import com.android.networkrecommendation.config.PreferenceFile.SharedPreference;
+import java.util.Collections;
+import java.util.Set;
+
+/** The NetRec preferences file. */
+public final class Preferences {
+ private Preferences() {}
+
+ private static final PreferenceFile sPrefs =
+ new PreferenceFile("com.android.networkrecommendation");
+
+ /**
+ * {@link ScoreNetworksChimeraBroadcastReceiver} sets this to true when the scorer is enabled.
+ * {@link com.android.networkrecommendation.scoring.service.FutureRefreshRequestor} checks for
+ * this value and triggers a quick score refresh if this is set.
+ */
+ public static final SharedPreference<Boolean> justEnabled =
+ sPrefs.booleanValue("justEnabled", false);
+
+ /**
+ * The next time, in ms since system boot, that a rapid (i.e. outside the usual refresh window)
+ * will be allowed to make a network request.
+ */
+ public static final SharedPreference<Long> nextRapidRefreshAllowed =
+ sPrefs.longValue("nextRapidRefreshAllowedMillis", 0L);
+
+ /**
+ * The set of saved ssid hashes in previous scan result list when the user disabled Wi-Fi. Saved
+ * to preferences when {@link com.android.networkrecommendation.wakeup.WifiWakeupController}
+ * stops.
+ */
+ public static final SharedPreference<Set<String>> savedSsidsOnDisable =
+ sPrefs.stringSetValue("savedSsidsOnDisable", Collections.emptySet());
+
+ /**
+ * The set of saved ssid hashes that were previously shown as Wi-Fi Enabled notifications
+ * through {@link com.android.networkrecommendation.wakeup.WifiWakeupController}.
+ */
+ public static final SharedPreference<Set<String>> ssidsForWakeupShown =
+ sPrefs.stringSetValue("ssidsForWakeupShown", Collections.emptySet());
+
+ /** Key for {@link com.android.networkrecommendation.storage.Encrypter} on pre-MNC devices. */
+ public static final SharedPreference<String> encrypterKey =
+ sPrefs.stringValue("encrypterKey", null);
+
+ /**
+ * How long we should wait before requesting another network. Used by {@link
+ * PersistentNetworkRequest} to support GCS/WFA.
+ */
+ public static final SharedPreference<Integer> nextNetworkRequestDelayMs =
+ sPrefs.intValue("nextNetworkRequestDelayMs", 0);
+
+ /**
+ * Hash of the SSID that last satisfied the network request in {@link PersistentNetworkRequest}.
+ */
+ public static final SharedPreference<String> lastSsidHash =
+ sPrefs.stringValue("lastSsidHash", "");
+}
diff --git a/src/com/android/networkrecommendation/notify/WifiNotificationController.java b/src/com/android/networkrecommendation/notify/WifiNotificationController.java
index aaba9c9..a6a9e70 100644
--- a/src/com/android/networkrecommendation/notify/WifiNotificationController.java
+++ b/src/com/android/networkrecommendation/notify/WifiNotificationController.java
@@ -25,7 +25,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
-import android.graphics.Bitmap;
import android.net.NetworkInfo;
import android.net.NetworkScoreManager;
import android.net.RecommendationRequest;
@@ -54,7 +53,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
/** Takes care of handling the "open wi-fi network available" notification */
public class WifiNotificationController {
/** The unique ID of the Notification given to the NotificationManager. */
- private static final int NOTIFICATION_ID = R.string.wifi_available;
+ private static final int NOTIFICATION_ID = R.string.wifi_available_title;
/** When a notification is shown, we wait this amount before possibly showing it again. */
private final long mNotificationRepeatDelayMs;
@@ -138,9 +137,6 @@ public class WifiNotificationController {
/** Network recommended by {@link NetworkScoreManager#requestRecommendation}. */
private WifiConfiguration mRecommendedNetwork;
- /** Badge icon of the recommended network. */
- private Bitmap mNotificationBadgeBitmap;
-
/** Whether {@link WifiNotificationController} has been started. */
private final AtomicBoolean mStarted;
@@ -212,7 +208,7 @@ public class WifiNotificationController {
return;
}
mContext.unregisterReceiver(mBroadcastReceiver);
- mNotificationEnabledSettingObserver.register();
+ mNotificationEnabledSettingObserver.unregister();
}
private final BroadcastReceiver mBroadcastReceiver =
@@ -257,7 +253,7 @@ public class WifiNotificationController {
}
} else if (intent.getAction()
.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
- checkAndSetNotification(mNetworkInfo, mWifiManager.getScanResults());
+ checkAndSetNotification(mNetworkInfo);
} else if (intent.getAction()
.equals(ACTION_CONNECT_TO_RECOMMENDED_NETWORK)) {
connectToRecommendedNetwork();
@@ -274,15 +270,13 @@ public class WifiNotificationController {
}
};
- private void checkAndSetNotification(NetworkInfo networkInfo, List<ScanResult> scanResults) {
+ private void checkAndSetNotification(NetworkInfo networkInfo) {
// TODO: unregister broadcast so we do not have to check here
// If we shouldn't place a notification on available networks, then
// don't bother doing any of the following
if (!mNotificationEnabled
|| mWifiState != WifiManager.WIFI_STATE_ENABLED
- || mNotificationState > State.SHOWING_CONNECT_ACTIONS
- || scanResults == null
- || scanResults.isEmpty()) {
+ || mNotificationState > State.SHOWING_CONNECT_ACTIONS) {
return;
}
@@ -293,15 +287,11 @@ public class WifiNotificationController {
if (state == NetworkInfo.State.DISCONNECTED || state == NetworkInfo.State.UNKNOWN) {
maybeLogOpenNetworksAvailable();
- RecommendationResult result = getOpenNetworkRecommendation(scanResults);
+ RecommendationResult result = getOpenNetworkRecommendation();
if (result != null && result.getWifiConfiguration() != null) {
mRecommendedNetwork = result.getWifiConfiguration();
- mNotificationBadgeBitmap =
- mWifiNotificationHelper.createNotificationBadgeBitmap(
- mRecommendedNetwork, scanResults);
- if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING
- && mNotificationBadgeBitmap != null) {
+ if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) {
/*
* We have scanned continuously at least
* NUM_SCANS_BEFORE_NOTIFICATION times. The user
@@ -334,7 +324,8 @@ public class WifiNotificationController {
* @return returns the best qualified open networks, if any.
*/
@Nullable
- private RecommendationResult getOpenNetworkRecommendation(List<ScanResult> scanResults) {
+ private RecommendationResult getOpenNetworkRecommendation() {
+ List<ScanResult> scanResults = mWifiManager.getScanResults();
if (scanResults == null || scanResults.isEmpty()) {
return null;
}
@@ -353,6 +344,7 @@ public class WifiNotificationController {
}
}
+ Blog.d(TAG, "Sending RecommendationRequest. [num_open_networks=%d]", openNetworks.size());
RecommendationRequest request =
new RecommendationRequest.Builder()
.setScanResults(openNetworks.toArray(new ScanResult[openNetworks.size()]))
@@ -387,8 +379,7 @@ public class WifiNotificationController {
return;
}
Notification notification =
- mWifiNotificationHelper.createMainNotification(
- mRecommendedNetwork, mNotificationBadgeBitmap);
+ mWifiNotificationHelper.createMainNotification(mRecommendedNetwork);
mNotificationRepeatTime = System.currentTimeMillis() + mNotificationRepeatDelayMs;
postNotification(notification);
if (mNotificationState != State.SHOWING_CONNECT_ACTIONS) {
@@ -419,8 +410,7 @@ public class WifiNotificationController {
// Update notification to connecting status.
Notification notification =
- mWifiNotificationHelper.createConnectingNotification(
- mRecommendedNetwork, mNotificationBadgeBitmap);
+ mWifiNotificationHelper.createConnectingNotification(mRecommendedNetwork);
postNotification(notification);
mNotificationState = State.SHOWING_CONNECTING;
mHandler.postDelayed(
@@ -442,8 +432,7 @@ public class WifiNotificationController {
}
Notification notification =
- mWifiNotificationHelper.createConnectedNotification(
- mRecommendedNetwork, mNotificationBadgeBitmap);
+ mWifiNotificationHelper.createConnectedNotification(mRecommendedNetwork);
postNotification(notification);
mNotificationState = State.SHOWING_CONNECTED;
mHandler.postDelayed(
@@ -460,8 +449,7 @@ public class WifiNotificationController {
* {@link #TIME_TO_SHOW_CONNECTING_MILLIS} duration.
*/
private void showFailedToConnectNotification() {
- Notification notification =
- mWifiNotificationHelper.createFailedToConnectNotification(mRecommendedNetwork);
+ Notification notification = mWifiNotificationHelper.createFailedToConnectNotification();
postNotification(notification);
mNotificationState = State.SHOWING_FAILURE;
mHandler.postDelayed(
@@ -477,7 +465,6 @@ public class WifiNotificationController {
private void handleNotificationDeleted() {
mNotificationState = State.HIDDEN;
mRecommendedNetwork = null;
- mNotificationBadgeBitmap = null;
}
private void postNotification(Notification notification) {
@@ -502,7 +489,6 @@ public class WifiNotificationController {
mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
mNotificationState = State.HIDDEN;
mRecommendedNetwork = null;
- mNotificationBadgeBitmap = null;
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/src/com/android/networkrecommendation/notify/WifiNotificationHelper.java b/src/com/android/networkrecommendation/notify/WifiNotificationHelper.java
index 2fbeeab..c265e8f 100644
--- a/src/com/android/networkrecommendation/notify/WifiNotificationHelper.java
+++ b/src/com/android/networkrecommendation/notify/WifiNotificationHelper.java
@@ -16,54 +16,24 @@
package com.android.networkrecommendation.notify;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
-import static com.android.networkrecommendation.Constants.TAG;
+import static com.android.networkrecommendation.util.NotificationChannelUtil.CHANNEL_ID_NETWORK_AVAILABLE;
import android.app.Notification;
import android.app.Notification.Action;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.net.NetworkBadging;
-import android.net.NetworkKey;
-import android.net.ScoredNetwork;
-import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiManager;
import android.os.Bundle;
-import android.provider.Settings;
-import android.support.annotation.NonNull;
-import android.support.annotation.VisibleForTesting;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.style.ForegroundColorSpan;
import com.android.networkrecommendation.R;
-import com.android.networkrecommendation.SynchronousNetworkRecommendationProvider;
-import com.android.networkrecommendation.util.Blog;
-import com.android.networkrecommendation.util.ImageUtil;
-import com.android.networkrecommendation.util.RoboCompatUtil;
-import com.android.networkrecommendation.util.ScanResultUtil;
-import com.android.networkrecommendation.util.WifiConfigurationUtil;
-import java.util.List;
-import javax.annotation.Nullable;
+import com.android.networkrecommendation.util.NotificationChannelUtil;
/** Helper class that creates notifications for {@link WifiNotificationController}. */
public class WifiNotificationHelper {
-
- /** This is in reference to the hidden Settings.Global.NETWORK_SCORING_UI_ENABLED */
- @VisibleForTesting
- static final String NETWORK_SCORING_UI_ENABLED = "network_scoring_ui_enabled";
-
private final Context mContext;
- private final SynchronousNetworkRecommendationProvider mCachedScoredNetworkProvider;
- public WifiNotificationHelper(
- Context context, SynchronousNetworkRecommendationProvider cachedScoredNetworkProvider) {
+ public WifiNotificationHelper(Context context) {
mContext = context;
- mCachedScoredNetworkProvider = cachedScoredNetworkProvider;
}
/**
@@ -71,18 +41,18 @@ public class WifiNotificationHelper {
* picker activity, and "Connect" prompts {@link WifiNotificationController} to connect to the
* recommended network.
*/
- public Notification createMainNotification(WifiConfiguration config, Bitmap badge) {
- PendingIntent optionsIntent =
+ public Notification createMainNotification(WifiConfiguration config) {
+ PendingIntent allNetworksIntent =
PendingIntent.getBroadcast(
mContext,
0,
new Intent(WifiNotificationController.ACTION_PICK_WIFI_NETWORK),
FLAG_UPDATE_CURRENT);
- Action optionsAction =
+ Action allNetworksAction =
new Action.Builder(
null /* icon */,
- mContext.getText(R.string.wifi_available_options),
- optionsIntent)
+ mContext.getText(R.string.wifi_available_action_all_networks),
+ allNetworksIntent)
.build();
PendingIntent connectIntent =
PendingIntent.getBroadcast(
@@ -94,12 +64,12 @@ public class WifiNotificationHelper {
Action connectAction =
new Action.Builder(
null /* icon */,
- mContext.getText(R.string.wifi_available_connect),
+ mContext.getText(R.string.wifi_available_action_connect),
connectIntent)
.build();
- return createNotificationBuilder(config, badge)
+ return createNotificationBuilder(R.string.wifi_available_title, config.SSID)
.addAction(connectAction)
- .addAction(optionsAction)
+ .addAction(allNetworksAction)
.build();
}
@@ -107,15 +77,8 @@ public class WifiNotificationHelper {
* Creates the notification that indicates the controller is attempting to connect to the
* recommended network.
*/
- public Notification createConnectingNotification(WifiConfiguration config, Bitmap badge) {
- Action connecting =
- new Action.Builder(
- null /* icon */,
- mContext.getText(R.string.common_connecting),
- null /* pendingIntent */)
- .build();
- return createNotificationBuilder(config, badge)
- .addAction(connecting)
+ public Notification createConnectingNotification(WifiConfiguration config) {
+ return createNotificationBuilder(R.string.wifi_available_title_connecting, config.SSID)
.setProgress(0 /* max */, 0 /* progress */, true /* indeterminate */)
.build();
}
@@ -124,126 +87,58 @@ public class WifiNotificationHelper {
* Creates the notification that indicates the controller successfully connected to the
* recommended network.
*/
- public Notification createConnectedNotification(WifiConfiguration config, Bitmap badge) {
- Action connected =
- new Action.Builder(
- null /* icon */,
- mContext.getText(R.string.wifi_available_connected),
- null /* pendingIntent */)
- .build();
- return createNotificationBuilder(config, badge).addAction(connected).build();
+ public Notification createConnectedNotification(WifiConfiguration config) {
+ return createNotificationBuilder(R.string.wifi_available_title_connected, config.SSID)
+ .setAutoCancel(true)
+ .build();
}
/**
* Creates the notification that indicates the controller failed to connect to the recommended
* network.
*/
- public Notification createFailedToConnectNotification(WifiConfiguration config) {
- Spannable failedText =
- new SpannableString(mContext.getText(R.string.wifi_available_failed));
- Resources resources = mContext.getResources();
- Drawable iconDrawable = mContext.getDrawable(R.drawable.ic_signal_wifi_no_network);
- iconDrawable.setTint(mContext.getColor(R.color.color_tint));
- Bitmap icon =
- ImageUtil.buildScaledBitmap(
- iconDrawable,
- resources.getDimensionPixelSize(
- android.R.dimen.notification_large_icon_width),
- resources.getDimensionPixelSize(
- android.R.dimen.notification_large_icon_height));
- failedText.setSpan(
- new ForegroundColorSpan(Color.RED),
- 0,
- failedText.length(),
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- return createNotificationBuilder(config, icon).setContentText(failedText).build();
+ public Notification createFailedToConnectNotification() {
+ PendingIntent allNetworksIntent =
+ PendingIntent.getBroadcast(
+ mContext,
+ 0,
+ new Intent(WifiNotificationController.ACTION_PICK_WIFI_NETWORK),
+ FLAG_UPDATE_CURRENT);
+ return createNotificationBuilder(
+ R.string.wifi_available_title_failed,
+ mContext.getString(R.string.wifi_available_content_failed))
+ .setContentIntent(allNetworksIntent)
+ .setAutoCancel(true)
+ .build();
}
- private Notification.Builder createNotificationBuilder(WifiConfiguration config, Bitmap badge) {
- CharSequence title = mContext.getText(R.string.wifi_available);
+ private Notification.Builder createNotificationBuilder(int titleRid, String content) {
+ CharSequence title = mContext.getText(titleRid);
PendingIntent deleteIntent =
PendingIntent.getBroadcast(
mContext,
0,
new Intent(WifiNotificationController.ACTION_NOTIFICATION_DELETED),
FLAG_UPDATE_CURRENT);
- return new Notification.Builder(mContext)
- .setDeleteIntent(deleteIntent)
- .setSmallIcon(R.drawable.ic_signal_wifi_statusbar_not_connected)
- .setLargeIcon(badge)
- .setAutoCancel(true)
- .setTicker(title)
- .setContentTitle(title)
- .setColor(mContext.getColor(R.color.color_tint))
- .setContentText(WifiConfigurationUtil.getPrintableSsid(config))
- .addExtras(getSystemLabelExtras());
+ int smallIcon = R.drawable.ic_signal_wifi_statusbar_not_connected;
+ Notification.Builder builder =
+ new Notification.Builder(mContext)
+ .setDeleteIntent(deleteIntent)
+ .setSmallIcon(smallIcon)
+ .setTicker(title)
+ .setContentTitle(title)
+ .setColor(mContext.getColor(R.color.color_tint))
+ .setContentText(content)
+ .setLocalOnly(true)
+ .addExtras(getOverrideLabelExtras());
+ return NotificationChannelUtil.setChannel(builder, CHANNEL_ID_NETWORK_AVAILABLE);
}
- private Bundle getSystemLabelExtras() {
+ private Bundle getOverrideLabelExtras() {
Bundle extras = new Bundle();
extras.putString(
Notification.EXTRA_SUBSTITUTE_APP_NAME,
- mContext.getString(R.string.android_system_label));
+ mContext.getString(R.string.notification_channel_group_name));
return extras;
}
-
- /**
- * Creates a Wi-Fi badge for the notification using matching {@link ScanResult}'s RSSI and
- * badging from {@link CachedScoredNetworkProvider}.
- */
- @Nullable
- public Bitmap createNotificationBadgeBitmap(
- @NonNull WifiConfiguration config, @NonNull List<ScanResult> scanResults) {
- ScanResult matchingScanResult = findMatchingScanResult(scanResults, config);
- if (matchingScanResult == null) {
- return null;
- }
- int rssi = matchingScanResult.level;
-
- NetworkKey networkKey;
- try {
- networkKey = ScanResultUtil.createNetworkKey(matchingScanResult);
- } catch (IllegalArgumentException e) {
- Blog.e(TAG, e, "Error creating NetworkKey.");
- return null;
- }
-
- ScoredNetwork scoredNetwork =
- mCachedScoredNetworkProvider.getCachedScoredNetwork(networkKey);
- if (scoredNetwork != null) {
- return getBadgedWifiBitmap(
- RoboCompatUtil.getInstance().calculateBadge(scoredNetwork, rssi), rssi);
- }
- return null;
- }
-
- private Bitmap getBadgedWifiBitmap(int badgeEnum, int rssi) {
- if (badgeEnum == NetworkBadging.BADGING_NONE) {
- return null;
- }
- if (Settings.Global.getInt(mContext.getContentResolver(), NETWORK_SCORING_UI_ENABLED, 0)
- == 0) {
- badgeEnum = NetworkBadging.BADGING_NONE;
- }
- int signalLevel = WifiManager.calculateSignalLevel(rssi, 5);
- Drawable drawable =
- RoboCompatUtil.getInstance()
- .getWifiIcon(signalLevel, badgeEnum, mContext.getTheme());
- drawable.setTint(mContext.getColor(R.color.color_tint));
- Resources resources = mContext.getResources();
- return ImageUtil.buildScaledBitmap(
- drawable,
- resources.getDimensionPixelSize(android.R.dimen.notification_large_icon_width),
- resources.getDimensionPixelSize(android.R.dimen.notification_large_icon_height));
- }
-
- private static ScanResult findMatchingScanResult(
- List<ScanResult> scanResults, WifiConfiguration wifiConfiguration) {
- for (ScanResult scanResult : scanResults) {
- if (ScanResultUtil.doesScanResultMatchWithNetwork(scanResult, wifiConfiguration)) {
- return scanResult;
- }
- }
- return null;
- }
}
diff --git a/src/com/android/networkrecommendation/scoring/util/HashUtil.java b/src/com/android/networkrecommendation/scoring/util/HashUtil.java
new file mode 100644
index 0000000..19fbd6a
--- /dev/null
+++ b/src/com/android/networkrecommendation/scoring/util/HashUtil.java
@@ -0,0 +1,93 @@
+/*
+ * 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.scoring.util;
+
+import android.util.Base64;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/** Hashcode and encoding utils. */
+public final class HashUtil {
+ private HashUtil() {}
+
+ /**
+ * Returns a base64-encoded secure hash (using the SHA-256 algorithm) of the provided input.
+ *
+ * @param input the bytes for which the secure hash should be computed.
+ * @return the hash
+ */
+ public static String secureHash(String input) {
+ return encodeBase64(getHash(input, "SHA-256"));
+ }
+
+ public static String encodeBase64(byte[] input) {
+ return Base64.encodeToString(input, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
+ }
+
+ /** Retrieves the message digest instance for a given hash algorithm. */
+ public static MessageDigest getMessageDigest(String hashAlgorithm) {
+ try {
+ return MessageDigest.getInstance(hashAlgorithm);
+ } catch (NoSuchAlgorithmException e) {
+ return null;
+ }
+ }
+
+ /**
+ * @return hash of input using hashAlgorithm, or 0-length byte array if input is null, or null
+ * if hashAlgorithm can't be loaded
+ */
+ public static byte[] getHash(String input, String hashAlgorithm) {
+ if (input != null) {
+ MessageDigest digest = getMessageDigest(hashAlgorithm);
+ if (digest == null) {
+ return null;
+ }
+ return digest.digest(input.getBytes());
+ }
+ return new byte[0];
+ }
+
+ /**
+ * Gets an SSID-specific hash which also ensures the SSID is in cannonical form (stripped of
+ * quotes).
+ */
+ public static String getSsidHash(String ssid) {
+ return secureHash(NetworkUtil.canonicalizeSsid(ssid));
+ }
+
+ /** Gets a single hash of over the combined SSID and BSSID. */
+ public static String getSsidBssidHash(String ssid, String bssid) {
+ String canonicalSsid = NetworkUtil.canonicalizeSsid(ssid);
+ return secureHash(canonicalSsid + bssid);
+ }
+
+ /** Return the first 8 bytes of the SHA-256 hash of the given ssid as a long value. */
+ public static long hashAsLong(String ssid) {
+ byte[] h = getHash(ssid, "SHA-256");
+ if (h == null || h.length < 8) {
+ return 0;
+ }
+ return (h[0] & 0xFFL) << 56
+ | (h[1] & 0xFFL) << 48
+ | (h[2] & 0xFFL) << 40
+ | (h[3] & 0xFFL) << 32
+ | (h[4] & 0xFFL) << 24
+ | (h[5] & 0xFFL) << 16
+ | (h[6] & 0xFFL) << 8
+ | (h[7] & 0xFFL);
+ }
+}
diff --git a/src/com/android/networkrecommendation/scoring/util/NetworkUtil.java b/src/com/android/networkrecommendation/scoring/util/NetworkUtil.java
new file mode 100644
index 0000000..55112a3
--- /dev/null
+++ b/src/com/android/networkrecommendation/scoring/util/NetworkUtil.java
@@ -0,0 +1,164 @@
+/*
+ * 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.scoring.util;
+
+import static android.net.wifi.WifiConfiguration.KeyMgmt.IEEE8021X;
+import static android.net.wifi.WifiConfiguration.KeyMgmt.WPA_EAP;
+import static android.net.wifi.WifiConfiguration.KeyMgmt.WPA_PSK;
+
+import android.content.Context;
+import android.net.NetworkKey;
+import android.net.WifiKey;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import com.android.networkrecommendation.Constants;
+import com.android.networkrecommendation.config.G;
+import com.android.networkrecommendation.util.Blog;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Network Utils. */
+public final class NetworkUtil {
+
+ private NetworkUtil() {
+ // do not instantiate
+ }
+
+ /**
+ * Canonicalize the given SSID returned by WifiInfo#getSSID().
+ *
+ * <p>This method should only be called once on a given SSID! If an SSID contains outer quotes,
+ * we will strip them twice and change the SSID to a different one.
+ *
+ * <p>The SSID should be returned surrounded by double quotation marks if it is valid UTF-8.
+ * This behavior was only implemented correctly after
+ * https://googleplex-android-review.googlesource.com/#/c/224602/ which went into JB-MR1.
+ *
+ * <p>This method does not account for non-UTF-8 SSIDs, which are returned as a string of hex
+ * digits from getSSID().
+ *
+ * <p>For more details, see: http://stackoverflow.com/questions/13563032
+ */
+ public static String canonicalizeSsid(String ssid) {
+ if (ssid == null) {
+ return null;
+ }
+ return removeQuotesIfNeeded(ssid);
+ }
+
+ /** Remove the leading quote and trailing quote. */
+ private static String removeQuotesIfNeeded(String text) {
+ if (text.length() > 1 && text.startsWith("\"") && text.endsWith("\"")) {
+ return text.substring(1, text.length() - 1);
+ }
+ return text;
+ }
+
+ /**
+ * @return a map from NetworkKey to true if that network is open, and false otherwise, for all
+ * visible networks in the last set of Wi-Fi scan results.
+ */
+ public static Map<NetworkKey, Boolean> getOpenWifiNetworkKeys(Context context) {
+ WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ List<ScanResult> scanResults = null;
+ if (Util.isScorerActive(context)) {
+ try {
+ scanResults = wifiMgr.getScanResults();
+ } catch (SecurityException e) {
+ Blog.w(Constants.TAG, e, "No permission to get scan results");
+ scanResults = null;
+ }
+ }
+ if (scanResults == null) {
+ return Collections.emptyMap();
+ }
+ Map<NetworkKey, Boolean> openKeys = new HashMap<>();
+ for (int i = 0; i < scanResults.size(); i++) {
+ ScanResult scanResult = scanResults.get(i);
+ try {
+ openKeys.put(
+ new NetworkKey(
+ new WifiKey("\"" + scanResult.SSID + "\"", scanResult.BSSID)),
+ isOpenNetwork(scanResult));
+ } catch (IllegalArgumentException iae) {
+ // WifiKey rejects some SSIDs that ScanResults considers valid, e.g. those
+ // containing a carriage return (as of L MR1). It's okay to just exclude those
+ // SSIDs from this list, because the platform uses the same WifiKey implementation, and so
+ // it would never be asking about such SSIDs in the first place.
+ Blog.v(
+ Constants.TAG,
+ "Couldn't make a wifi key from "
+ + Blog.pii(scanResult.SSID, G.Netrec.enableSensitiveLogging.get())
+ + "/"
+ + Blog.pii(scanResult.BSSID, G.Netrec.enableSensitiveLogging.get())
+ + ", skipping");
+ }
+ }
+ return openKeys;
+ }
+
+ private static boolean isOpenNetwork(ScanResult result) {
+ return !TextUtils.isEmpty(result.SSID)
+ && !TextUtils.isEmpty(result.BSSID)
+ && !result.capabilities.contains("WEP")
+ && !result.capabilities.contains("PSK")
+ && !result.capabilities.contains("EAP");
+ }
+
+ /** Returns true if the given config is for an "open" network. */
+ public static boolean isOpenNetwork(@NonNull WifiConfiguration config) {
+ if (config.allowedKeyManagement.get(WPA_PSK) // covers WPA_PSK and WPA2_PSK
+ || config.allowedKeyManagement.get(WPA_EAP)
+ || config.allowedKeyManagement.get(IEEE8021X)
+ || (config.wepKeys != null && config.wepKeys[0] != null)) {
+ return false;
+ }
+ return true;
+ }
+
+ @NonNull
+ public static String getCurrentWifiSsid(Context context) {
+ WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ WifiInfo wifiInfo = wifiManager.getConnectionInfo();
+ return wifiInfo == null ? "" : wifiInfo.getSSID();
+ }
+
+ /** Returns the config for the given SSID, or null if one cannot be found. */
+ @Nullable
+ public static WifiConfiguration getConfig(Context context, String ssid) {
+ WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks();
+ if (configs == null) {
+ return null;
+ }
+
+ WifiConfiguration config;
+ for (int i = 0; i < configs.size(); i++) {
+ config = configs.get(i);
+ if (TextUtils.equals(ssid, config.SSID)) {
+ return config;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/networkrecommendation/scoring/util/Util.java b/src/com/android/networkrecommendation/scoring/util/Util.java
new file mode 100644
index 0000000..3390531
--- /dev/null
+++ b/src/com/android/networkrecommendation/scoring/util/Util.java
@@ -0,0 +1,33 @@
+/*
+ * 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.scoring.util;
+
+import android.content.Context;
+import android.net.NetworkScoreManager;
+
+/** Utility methods for the scorer. */
+public final class Util {
+
+ /** @return true if GmsCore is the active network scorer. */
+ public static boolean isScorerActive(Context context) {
+ NetworkScoreManager scoreManager =
+ (NetworkScoreManager) context.getSystemService(Context.NETWORK_SCORE_SERVICE);
+ final String activeScorer = scoreManager.getActiveScorerPackage();
+ final String packageName = context.getPackageName();
+
+ return packageName.equals(activeScorer);
+ }
+}
diff --git a/src/com/android/networkrecommendation/util/ImageUtil.java b/src/com/android/networkrecommendation/util/ImageUtil.java
deleted file mode 100644
index 8bf3de0..0000000
--- a/src/com/android/networkrecommendation/util/ImageUtil.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.util;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-
-/** Helper for image manipulation */
-public class ImageUtil {
-
- /**
- * Convert a drawable to a bitmap, scaled to fit within maxWidth and maxHeight.
- */
- public static Bitmap buildScaledBitmap(Drawable drawable, int maxWidth,
- int maxHeight) {
- if (drawable == null) {
- return null;
- }
- int originalWidth = drawable.getIntrinsicWidth();
- int originalHeight = drawable.getIntrinsicHeight();
-
- if ((originalWidth <= maxWidth) && (originalHeight <= maxHeight)
- && (drawable instanceof BitmapDrawable)) {
- return ((BitmapDrawable) drawable).getBitmap();
- }
- if (originalHeight <= 0 || originalWidth <= 0) {
- return null;
- }
-
- // create a new bitmap, scaling down to fit the max dimensions of
- // a large notification icon if necessary
- float ratio = Math.min((float) maxWidth / (float) originalWidth,
- (float) maxHeight / (float) originalHeight);
- ratio = Math.min(1.0f, ratio);
- int scaledWidth = (int) (ratio * originalWidth);
- int scaledHeight = (int) (ratio * originalHeight);
- Bitmap result = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
-
- // and paint our app bitmap on it
- Canvas canvas = new Canvas(result);
- drawable.setBounds(0, 0, scaledWidth, scaledHeight);
- drawable.draw(canvas);
-
- return result;
- }
-}
diff --git a/src/com/android/networkrecommendation/util/NotificationChannelUtil.java b/src/com/android/networkrecommendation/util/NotificationChannelUtil.java
new file mode 100644
index 0000000..8be71bd
--- /dev/null
+++ b/src/com/android/networkrecommendation/util/NotificationChannelUtil.java
@@ -0,0 +1,69 @@
+/*
+ * 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.util;
+
+import android.app.Notification.Builder;
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
+import android.content.Context;
+import com.android.networkrecommendation.R;
+
+/**
+ * Util class for managing {@link android.app.NotificationChannel}s for our notifications.
+ * TODO(netrec): b/36486429 Add tests for this class once relevant class constructors are supported
+ * for Robolectric.
+ */
+public class NotificationChannelUtil {
+
+ private static final String CHANNEL_GROUP_ID =
+ "com.android.networkrecommendation.Notifications.WifiMessageGroup";
+ public static final String CHANNEL_ID_NETWORK_AVAILABLE =
+ "com.android.networkrecommendation.Notifications.WifiMessageGroup.NetworkAvailableChannel";
+ public static final String CHANNEL_ID_WAKEUP =
+ "com.android.networkrecommendation.Notifications.WifiMessageGroup.WakeupChannel";
+
+ /** Configures the {@link android.app.NotificationChannel}s for our module. */
+ public static void configureNotificationChannels(
+ NotificationManager notificationManager, Context context) {
+ NotificationChannelGroup notificationChannelGroup =
+ new NotificationChannelGroup(
+ CHANNEL_GROUP_ID,
+ context.getString(R.string.notification_channel_group_name));
+ notificationManager.createNotificationChannelGroup(notificationChannelGroup);
+
+ NotificationChannel networkAvailableChannel =
+ new NotificationChannel(
+ CHANNEL_ID_NETWORK_AVAILABLE,
+ context.getString(R.string.notification_channel_network_available),
+ NotificationManager.IMPORTANCE_LOW);
+ networkAvailableChannel.setGroup(CHANNEL_GROUP_ID);
+ notificationManager.createNotificationChannel(networkAvailableChannel);
+
+ NotificationChannel wakeupChannel =
+ new NotificationChannel(
+ CHANNEL_ID_WAKEUP,
+ context.getString(R.string.notification_channel_wakeup_name),
+ NotificationManager.IMPORTANCE_LOW);
+ wakeupChannel.setGroup(CHANNEL_GROUP_ID);
+ notificationManager.createNotificationChannel(wakeupChannel);
+ }
+
+ /** Wraps Notification.Builder.setChannel. */
+ public static Builder setChannel(Builder notificationBuilder, String channelId) {
+ return notificationBuilder.setChannel(channelId);
+ }
+}
diff --git a/src/com/android/networkrecommendation/util/RoboCompatUtil.java b/src/com/android/networkrecommendation/util/RoboCompatUtil.java
index 06b48fe..24c6d03 100644
--- a/src/com/android/networkrecommendation/util/RoboCompatUtil.java
+++ b/src/com/android/networkrecommendation/util/RoboCompatUtil.java
@@ -74,11 +74,6 @@ public class RoboCompatUtil {
return wifiConfiguration.isPasspoint();
}
- /** Wraps ScoredNetwork.calculateBadge. */
- public int calculateBadge(ScoredNetwork scoredNetwork, int rssi) {
- return scoredNetwork.calculateBadge(rssi);
- }
-
/** Wraps NetworkBadging.getWifiIcon. */
public Drawable getWifiIcon(int signalLevel, int badging, Theme theme) {
return NetworkBadging.getWifiIcon(signalLevel, badging, theme);
diff --git a/src/com/android/networkrecommendation/util/SsidUtil.java b/src/com/android/networkrecommendation/util/SsidUtil.java
index 5f7e5e8..52ed7de 100644
--- a/src/com/android/networkrecommendation/util/SsidUtil.java
+++ b/src/com/android/networkrecommendation/util/SsidUtil.java
@@ -17,7 +17,6 @@ package com.android.networkrecommendation.util;
import static com.android.networkrecommendation.Constants.TAG;
-import android.net.NetworkKey;
import android.net.WifiKey;
import android.support.annotation.Nullable;
import com.android.networkrecommendation.config.G;
@@ -78,15 +77,12 @@ public final class SsidUtil {
}
/**
- * Returns a string version of the NetworkKey SSID/BSSID pair for logging which is typically
- * redacted.
+ * Returns a string version of the SSID/BSSID pair for logging which is typically redacted.
*
- * <p>The IDs will only be returned verbatim if the enableSentitiveLogging flag is set.
+ * <p>The IDs will only be returned verbatim if the enableSensitiveLogging flag is set.
*/
- public static String getRedactedId(NetworkKey networkKey) {
- return Blog.pii(
- String.format("%s/%s", networkKey.wifiKey.ssid, networkKey.wifiKey.bssid),
- G.Netrec.enableSensitiveLogging.get());
+ public static String getRedactedId(String ssid, String bssid) {
+ return Blog.pii(String.format("%s/%s", ssid, bssid), G.Netrec.enableSensitiveLogging.get());
}
// Can't instantiate.
diff --git a/src/com/android/networkrecommendation/wakeup/WifiWakeupController.java b/src/com/android/networkrecommendation/wakeup/WifiWakeupController.java
index 100e652..a9aa61f 100644
--- a/src/com/android/networkrecommendation/wakeup/WifiWakeupController.java
+++ b/src/com/android/networkrecommendation/wakeup/WifiWakeupController.java
@@ -34,7 +34,9 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.networkrecommendation.config.G;
+import com.android.networkrecommendation.config.Preferences;
import com.android.networkrecommendation.config.WideAreaNetworks;
+import com.android.networkrecommendation.scoring.util.HashUtil;
import com.android.networkrecommendation.util.Blog;
import com.android.networkrecommendation.util.RoboCompatUtil;
import com.android.networkrecommendation.util.WifiConfigurationUtil;
@@ -121,23 +123,26 @@ public class WifiWakeupController {
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (!mWifiWakeupEnabled) {
- return;
- }
-
- if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(intent.getAction())) {
- handleWifiApStateChanged();
- } else if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
- handleWifiStateChanged();
- } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(
- intent.getAction())) {
- handleScanResultsAvailable();
- } else if (WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(
- intent.getAction())) {
- handleConfiguredNetworksChanged();
- } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(
- intent.getAction())) {
- handlePowerSaverModeChanged();
+ try {
+ if (WifiManager.WIFI_AP_STATE_CHANGED_ACTION.equals(intent.getAction())) {
+ handleWifiApStateChanged();
+ } else if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(
+ intent.getAction())) {
+ handleWifiStateChanged(false);
+ } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(
+ intent.getAction())) {
+ handleScanResultsAvailable();
+ } else if (WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(
+ intent.getAction())) {
+ handleConfiguredNetworksChanged();
+ } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(
+ intent.getAction())) {
+ handlePowerSaverModeChanged();
+ }
+ } 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.");
}
}
};
@@ -166,10 +171,10 @@ public class WifiWakeupController {
true,
mContentObserver);
mContentObserver.onChange(true);
- handleWifiStateChanged();
handlePowerSaverModeChanged();
handleWifiApStateChanged();
handleConfiguredNetworksChanged();
+ handleWifiStateChanged(true);
handleScanResultsAvailable();
}
@@ -240,7 +245,7 @@ public class WifiWakeupController {
mSavedSsidsInLastScan.retainAll(mSavedSsids);
}
- private void handleWifiStateChanged() {
+ private void handleWifiStateChanged(boolean calledOnStart) {
mWifiState = mWifiManager.getWifiState();
Blog.v(TAG, "handleWifiStateChanged: %d", mWifiState);
@@ -250,8 +255,13 @@ public class WifiWakeupController {
if (!mAutopilotEnabledWifi) {}
break;
case WifiManager.WIFI_STATE_DISABLED:
- for (String ssid : mSavedSsidsInLastScan) {
- mSavedSsidsOnDisable.put(ssid, NUM_SCANS_TO_CONFIRM_AP_LOSS);
+ if (calledOnStart) {
+ readDisabledSsidsFromSharedPreferences();
+ } else {
+ for (String ssid : mSavedSsidsInLastScan) {
+ mSavedSsidsOnDisable.put(ssid, NUM_SCANS_TO_CONFIRM_AP_LOSS);
+ }
+ writeDisabledSsidsToSharedPreferences();
}
Blog.d(TAG, "Disabled ssid set: %s", mSavedSsidsOnDisable);
@@ -261,7 +271,27 @@ public class WifiWakeupController {
}
}
+ private void readDisabledSsidsFromSharedPreferences() {
+ Set<String> ssidsOnDisable = Preferences.savedSsidsOnDisable.get();
+ for (String ssid : mSavedSsids) {
+ if (ssidsOnDisable.contains(HashUtil.getSsidHash(ssid))) {
+ mSavedSsidsOnDisable.put(ssid, NUM_SCANS_TO_CONFIRM_AP_LOSS);
+ }
+ }
+ }
+
+ private void writeDisabledSsidsToSharedPreferences() {
+ Set<String> ssids = new ArraySet<>();
+ for (String ssid : mSavedSsidsOnDisable.keySet()) {
+ ssids.add(HashUtil.getSsidHash(ssid));
+ }
+ Preferences.savedSsidsOnDisable.put(ssids);
+ }
+
private void handleScanResultsAvailable() {
+ if (!mWifiWakeupEnabled) {
+ return;
+ }
List<ScanResult> scanResults = mWifiManager.getScanResults();
if (scanResults == null) {
return;
diff --git a/src/com/android/networkrecommendation/wakeup/WifiWakeupHelper.java b/src/com/android/networkrecommendation/wakeup/WifiWakeupHelper.java
index 6b1c48d..4e56aa2 100644
--- a/src/com/android/networkrecommendation/wakeup/WifiWakeupHelper.java
+++ b/src/com/android/networkrecommendation/wakeup/WifiWakeupHelper.java
@@ -16,6 +16,7 @@
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;
@@ -24,20 +25,23 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.SharedPreferences;
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;
@@ -49,8 +53,6 @@ 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 KEY_SHOWN_SSIDS = "key_shown_ssids";
-
@VisibleForTesting
static final String ACTION_WIFI_SETTINGS =
"com.android.networkrecommendation.wakeup.ACTION_WIFI_SETTINGS";
@@ -73,7 +75,6 @@ public class WifiWakeupHelper {
private final NotificationManager mNotificationManager;
private final Handler mHandler;
private final WifiManager mWifiManager;
- private final SharedPreferences mSharedPreferences;
/** Whether the wakeup notification is currently displayed. */
private boolean mNotificationShown;
@@ -88,9 +89,8 @@ public class WifiWakeupHelper {
public void onReceive(Context context, Intent intent) {
try {
if (ACTION_WIFI_SETTINGS.equals(intent.getAction())) {
- // TODO(netrec): Change to @SystemApi Settings.CONFIGURE_WIFI_SETTINGS
mContext.startActivity(
- new Intent("android.settings.CONFIGURE_WIFI_SETTINGS")
+ new Intent(Settings.ACTION_WIFI_SETTINGS)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
} else if (ACTION_DISMISS_WIFI_ENABLED_NOTIFICATION.equals(
intent.getAction())) {
@@ -113,30 +113,11 @@ public class WifiWakeupHelper {
Handler handler,
NotificationManager notificationManager,
WifiManager wifiManager) {
- this(
- context,
- resources,
- handler,
- notificationManager,
- wifiManager,
- context.getSharedPreferences("wifi_wakeup", Context.MODE_PRIVATE));
- // BUG(26641175): Code coverage does not like line wraps at 'this($'
- }
-
- @VisibleForTesting
- WifiWakeupHelper(
- Context context,
- Resources resources,
- Handler handler,
- NotificationManager notificationManager,
- WifiManager wifiManager,
- SharedPreferences sharedPreferences) {
mContext = context;
mResources = resources;
mNotificationManager = notificationManager;
mHandler = handler;
mWifiManager = wifiManager;
- mSharedPreferences = sharedPreferences;
mWifiSessionStarted = false;
mNotificationShown = false;
mConnectedSsid = null;
@@ -160,18 +141,19 @@ public class WifiWakeupHelper {
},
NETWORK_CONNECTED_TIMEOUT_MILLIS);
- Set<String> ssidSet = mSharedPreferences.getStringSet(KEY_SHOWN_SSIDS, null);
- if (ssidSet == null) {
- ssidSet = new ArraySet<>();
- } else if (ssidSet.contains(wifiConfiguration.SSID)) {
+ Set<String> hashedSsidSet = Preferences.ssidsForWakeupShown.get();
+ String hashedSsid = HashUtil.getSsidHash(wifiConfiguration.SSID);
+ if (hashedSsidSet.isEmpty()) {
+ hashedSsidSet = new ArraySet<>();
+ } else if (hashedSsidSet.contains(hashedSsid)) {
Blog.d(
TAG,
"Already showed Wi-Fi Enabled notification for ssid: %s",
Blog.pii(wifiConfiguration.SSID, G.Netrec.enableSensitiveLogging.get()));
return;
}
- ssidSet.add(wifiConfiguration.SSID);
- mSharedPreferences.edit().putStringSet(KEY_SHOWN_SSIDS, ssidSet).apply();
+ hashedSsidSet.add(hashedSsid);
+ Preferences.ssidsForWakeupShown.put(hashedSsidSet);
String title = mResources.getString(R.string.wifi_wakeup_enabled_notification_title);
String summary =
@@ -192,8 +174,8 @@ public class WifiWakeupHelper {
Bundle extras = new Bundle();
extras.putString(
Notification.EXTRA_SUBSTITUTE_APP_NAME,
- mResources.getString(R.string.android_system_label));
- Notification notification =
+ mResources.getString(R.string.notification_channel_group_name));
+ Notification.Builder notificationBuilder =
new Notification.Builder(mContext)
.setContentTitle(title)
.setSmallIcon(R.drawable.ic_signal_wifi_statusbar_not_connected)
@@ -205,9 +187,10 @@ public class WifiWakeupHelper {
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setCategory(Notification.CATEGORY_STATUS)
.setContentIntent(savedNetworkSettingsPendingIntent)
- .addExtras(extras)
- .build();
- mNotificationManager.notify(TAG, NOTIFICATION_ID, notification);
+ .setLocalOnly(true)
+ .addExtras(extras);
+ NotificationChannelUtil.setChannel(notificationBuilder, CHANNEL_ID_WAKEUP);
+ mNotificationManager.notify(TAG, NOTIFICATION_ID, notificationBuilder.build());
mNotificationShown = true;
}
diff --git a/tests/src/com/android/networkrecommendation/NetworkRecommendationServiceTest.java b/tests/src/com/android/networkrecommendation/NetworkRecommendationServiceTest.java
index 47656be..644cb93 100644
--- a/tests/src/com/android/networkrecommendation/NetworkRecommendationServiceTest.java
+++ b/tests/src/com/android/networkrecommendation/NetworkRecommendationServiceTest.java
@@ -45,6 +45,8 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import com.android.networkrecommendation.config.PreferenceFile;
+
@RunWith(AndroidJUnit4.class)
public class NetworkRecommendationServiceTest {
@@ -56,6 +58,7 @@ public class NetworkRecommendationServiceTest {
public final ServiceTestRule serviceRule = new ServiceTestRule();
private INetworkRecommendationProvider bind() throws TimeoutException {
+ PreferenceFile.init(InstrumentationRegistry.getTargetContext());
Intent bindIntent = new Intent(InstrumentationRegistry.getTargetContext(),
NetworkRecommendationService.class);
bindIntent.setAction(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS);