summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WifiTrackerLib/src/com/android/wifitrackerlib/ScanResultUpdater.java100
-rw-r--r--libs/WifiTrackerLib/tests/Android.bp28
-rw-r--r--libs/WifiTrackerLib/tests/AndroidManifest.xml36
-rw-r--r--libs/WifiTrackerLib/tests/src/com/android/wifitrackerlib/ScanResultUpdaterTest.java159
4 files changed, 323 insertions, 0 deletions
diff --git a/libs/WifiTrackerLib/src/com/android/wifitrackerlib/ScanResultUpdater.java b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/ScanResultUpdater.java
new file mode 100644
index 000000000..6df4f266c
--- /dev/null
+++ b/libs/WifiTrackerLib/src/com/android/wifitrackerlib/ScanResultUpdater.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 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.wifitrackerlib;
+
+import android.net.wifi.ScanResult;
+import android.os.SystemClock;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Utility class to keep a running list of scan results merged by BSSID.
+ *
+ * Thread-safe.
+ */
+public class ScanResultUpdater {
+ private HashMap<String, ScanResult> mScanResultsByBssid = new HashMap<>();
+ private long mMaxScanAgeMillis;
+ private Object mLock = new Object();
+
+ /**
+ * Creates a ScanResultUpdater with no max scan age.
+ */
+ public ScanResultUpdater() {
+ this(Long.MAX_VALUE);
+ }
+
+ /**
+ * Creates a ScanResultUpdater with a max scan age in milliseconds. Scans older than this limit
+ * will be pruned upon update/retrieval to keep the size of the scan list down.
+ */
+ public ScanResultUpdater(long maxScanAgeMillis) {
+ mMaxScanAgeMillis = maxScanAgeMillis;
+ }
+
+ /**
+ * Updates scan result list and replaces older scans of the same BSSID.
+ */
+ public void update(List<ScanResult> newResults) {
+ synchronized (mLock) {
+ evictOldScans();
+
+ for (ScanResult result : newResults) {
+ ScanResult prevResult = mScanResultsByBssid.get(result.BSSID);
+ if (prevResult == null || (prevResult.timestamp < result.timestamp)) {
+ mScanResultsByBssid.put(result.BSSID, result);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns all seen scan results merged by BSSID.
+ */
+ public List<ScanResult> getScanResults() {
+ return getScanResults(mMaxScanAgeMillis);
+ }
+
+ /**
+ * Returns all seen scan results merged by BSSID and newer than maxScanAgeMillis.
+ * maxScanAgeMillis must be less than or equal to the mMaxScanAgeMillis field if it was set.
+ */
+ public List<ScanResult> getScanResults(long maxScanAgeMillis) throws IllegalArgumentException {
+ if (maxScanAgeMillis > mMaxScanAgeMillis) {
+ throw new IllegalArgumentException(
+ "maxScanAgeMillis argument cannot be greater than mMaxScanAgeMillis!");
+ }
+ synchronized (mLock) {
+ List<ScanResult> ageFilteredResults = new ArrayList<>();
+ for (ScanResult result : mScanResultsByBssid.values()) {
+ if (SystemClock.elapsedRealtime() - result.timestamp <= maxScanAgeMillis) {
+ ageFilteredResults.add(result);
+ }
+ }
+ return ageFilteredResults;
+ }
+ }
+
+ private void evictOldScans() {
+ synchronized (mLock) {
+ mScanResultsByBssid.entrySet().removeIf((entry) ->
+ SystemClock.elapsedRealtime() - entry.getValue().timestamp > mMaxScanAgeMillis);
+ }
+ }
+}
diff --git a/libs/WifiTrackerLib/tests/Android.bp b/libs/WifiTrackerLib/tests/Android.bp
new file mode 100644
index 000000000..e8f854893
--- /dev/null
+++ b/libs/WifiTrackerLib/tests/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2019 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.
+
+android_test {
+ name: "WifiTrackerLibTests",
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "android-support-test",
+ "androidx.test.rules",
+ "WifiTrackerLib",
+ ],
+
+ platform_apis: true,
+
+ test_suites: ["device-tests"],
+}
diff --git a/libs/WifiTrackerLib/tests/AndroidManifest.xml b/libs/WifiTrackerLib/tests/AndroidManifest.xml
new file mode 100644
index 000000000..2642960e7
--- /dev/null
+++ b/libs/WifiTrackerLib/tests/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wifitrackerlib.test" >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:label="WifiTrackerTestsDummyLabel"
+ android:name="WifiTrackerTestsDummyName">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wifitrackerlib.test"
+ android:label="WifiTrackerLib Tests">
+ </instrumentation>
+
+</manifest> \ No newline at end of file
diff --git a/libs/WifiTrackerLib/tests/src/com/android/wifitrackerlib/ScanResultUpdaterTest.java b/libs/WifiTrackerLib/tests/src/com/android/wifitrackerlib/ScanResultUpdaterTest.java
new file mode 100644
index 000000000..39d6bf3f8
--- /dev/null
+++ b/libs/WifiTrackerLib/tests/src/com/android/wifitrackerlib/ScanResultUpdaterTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2019 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.wifitrackerlib;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.fail;
+
+import android.net.wifi.ScanResult;
+import android.os.SystemClock;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class ScanResultUpdaterTest {
+ private static final String BSSID_1 = "11:11:11:11:11:11";
+ private static final String BSSID_2 = "22:22:22:22:22:22";
+ private static final String BSSID_3 = "33:33:33:33:33:33";
+
+ private static ScanResult buildScanResult(String bssid, long timestampMs) {
+ return new ScanResult(
+ null,
+ bssid,
+ 0, // hessid
+ 0, //anqpDomainId
+ null, // osuProviders
+ "", // capabilities
+ 0,
+ 0, // frequency
+ timestampMs /* microsecond timestamp */);
+ }
+
+ /**
+ * Verify that scan results of the same BSSID are merged to latest one.
+ */
+ @Test
+ public void testGetScanResults_mergeSameBssid() {
+ ScanResult oldResult = buildScanResult(
+ BSSID_1, 10);
+ ScanResult newResult = buildScanResult(
+ BSSID_1, 20);
+
+ // Add initial scan result. List should have 1 scan.
+ ScanResultUpdater sru = new ScanResultUpdater();
+ sru.update(Arrays.asList(oldResult));
+ assertThat(sru.getScanResults().size(), equalTo(1));
+ assertThat(sru.getScanResults().get(0), equalTo(oldResult));
+
+ // Add new scan result. Old scan result should be replaced.
+ sru.update(Arrays.asList(newResult));
+ assertThat(sru.getScanResults().size(), equalTo(1));
+ assertThat(sru.getScanResults().get(0), equalTo(newResult));
+
+ // Add old scan result back. New scan result should still remain.
+ sru.update(Arrays.asList(oldResult));
+ assertThat(sru.getScanResults().size(), equalTo(1));
+ assertThat(sru.getScanResults().get(0), equalTo(newResult));
+ }
+
+ /**
+ * Verify that scan results are filtered out by age.
+ */
+ @Test
+ public void testGetScanResults_filtersOldScans() {
+ long now = SystemClock.elapsedRealtime();
+ long maxScanAge = 15_000;
+
+ ScanResult oldResult = buildScanResult(
+ BSSID_1, now - (maxScanAge + 1));
+ ScanResult newResult = buildScanResult(
+ BSSID_2, now);
+
+ // Add a new scan result and an out-of-date scan result.
+ ScanResultUpdater sru = new ScanResultUpdater();
+ sru.update(Arrays.asList(newResult, oldResult));
+
+ // New scan result should remain and out-of-date scan result should not be returned.
+ assertThat(sru.getScanResults(maxScanAge).size(), equalTo(1));
+ assertThat(sru.getScanResults(maxScanAge).get(0), equalTo(newResult));
+ }
+
+ /**
+ * Verify that an exception is thrown if the getScanResults max scan age is larger than the
+ * constructor's max scan age.
+ */
+ @Test
+ public void testGetScanResults_invalidMaxScanAgeMillis_throwsException() {
+ ScanResultUpdater sru = new ScanResultUpdater(15_000);
+ try {
+ sru.getScanResults(20_000);
+ fail("Should have thrown exception for maxScanAgeMillis too large.");
+ } catch (IllegalArgumentException ok) {
+ // Expected
+ }
+ }
+
+ /**
+ * Verify that the constructor max scan age is obeyed when getting scan results.
+ */
+ @Test
+ public void testConstructor_maxScanAge_filtersOldScans() {
+ ScanResultUpdater sru = new ScanResultUpdater(15_000);
+ long now = SystemClock.elapsedRealtime();
+
+ ScanResult scan1 = buildScanResult(BSSID_1, now - 10_000);
+ ScanResult scan2 = buildScanResult(BSSID_2, now - 12_000);
+ ScanResult scan3 = buildScanResult(BSSID_3, now - 20_000);
+
+ sru.update(Arrays.asList(scan1, scan2, scan3));
+
+ List<ScanResult> scanResults = sru.getScanResults();
+
+ assertThat(scanResults.size(), equalTo(2));
+ assertThat(scanResults, contains(scan1, scan2));
+ }
+
+ /**
+ * Verify that getScanResults returns results aged by the passed in max scan age even if there
+ * is a max scan age set by the constructor.
+ */
+ @Test
+ public void testGetScanResults_overridesConstructorMaxScanAge() {
+ ScanResultUpdater sru = new ScanResultUpdater(15_000);
+ long now = SystemClock.elapsedRealtime();
+
+ ScanResult scan1 = buildScanResult(BSSID_1, now - 10_000);
+ ScanResult scan2 = buildScanResult(BSSID_2, now - 12_000);
+ ScanResult scan3 = buildScanResult(BSSID_3, now - 20_000);
+
+ sru.update(Arrays.asList(scan1, scan2, scan3));
+
+ // Aged getScanResults should override the constructor max scan age.
+ List<ScanResult> scanResults = sru.getScanResults(11_000);
+ assertThat(scanResults.size(), equalTo(1));
+ assertThat(scanResults, contains(scan1));
+
+ // Non-aged getScanResults should revert to the constructor max scan age.
+ scanResults = sru.getScanResults();
+ assertThat(scanResults.size(), equalTo(2));
+ assertThat(scanResults, contains(scan1, scan2));
+ }
+}