1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16package com.android.settingslib.wifi;
17
18import static com.google.common.truth.Truth.assertThat;
19import static com.google.common.truth.Truth.assertWithMessage;
20
21import static org.mockito.Mockito.any;
22import static org.mockito.Mockito.anyInt;
23import static org.mockito.Mockito.mock;
24import static org.mockito.Mockito.verify;
25import static org.mockito.Mockito.when;
26
27import android.content.Context;
28import android.net.ConnectivityManager;
29import android.net.NetworkInfo;
30import android.net.NetworkKey;
31import android.net.RssiCurve;
32import android.net.ScoredNetwork;
33import android.net.WifiKey;
34import android.net.wifi.ScanResult;
35import android.net.wifi.WifiConfiguration;
36import android.net.wifi.WifiEnterpriseConfig;
37import android.net.wifi.WifiInfo;
38import android.net.wifi.WifiNetworkScoreCache;
39import android.net.wifi.WifiSsid;
40import android.net.wifi.hotspot2.PasspointConfiguration;
41import android.net.wifi.hotspot2.pps.HomeSp;
42import android.os.Bundle;
43import android.os.SystemClock;
44import android.support.test.InstrumentationRegistry;
45import android.support.test.filters.SmallTest;
46import android.support.test.runner.AndroidJUnit4;
47import android.text.SpannableString;
48import android.text.format.DateUtils;
49import android.text.style.TtsSpan;
50
51import com.android.settingslib.R;
52import com.android.settingslib.wifi.AccessPoint.Speed;
53
54import org.junit.Before;
55import org.junit.Test;
56import org.junit.runner.RunWith;
57import org.mockito.Mock;
58import org.mockito.MockitoAnnotations;
59
60import java.util.ArrayList;
61import java.util.Arrays;
62import java.util.Collections;
63
64@SmallTest
65@RunWith(AndroidJUnit4.class)
66public class AccessPointTest {
67
68    private static final String TEST_SSID = "\"test_ssid\"";
69    private static final int NUM_SCAN_RESULTS = 5;
70
71    private static final ArrayList<ScanResult> SCAN_RESULTS = buildScanResultCache();
72
73    private static final RssiCurve FAST_BADGE_CURVE =
74            new RssiCurve(-150, 10, new byte[]{Speed.FAST});
75    public static final String TEST_BSSID = "00:00:00:00:00:00";
76    private static final long MAX_SCORE_CACHE_AGE_MILLIS =
77            20 * DateUtils.MINUTE_IN_MILLIS;;
78
79    private Context mContext;
80    @Mock private RssiCurve mockBadgeCurve;
81    @Mock private WifiNetworkScoreCache mockWifiNetworkScoreCache;
82
83    private static ScanResult createScanResult(String ssid, String bssid, int rssi) {
84        ScanResult scanResult = new ScanResult();
85        scanResult.SSID = ssid;
86        scanResult.level = rssi;
87        scanResult.BSSID = bssid;
88        scanResult.timestamp = SystemClock.elapsedRealtime() * 1000;
89        scanResult.capabilities = "";
90        return scanResult;
91    }
92
93    @Before
94    public void setUp() {
95        MockitoAnnotations.initMocks(this);
96        mContext = InstrumentationRegistry.getTargetContext();
97        WifiTracker.sVerboseLogging = false;
98    }
99
100    @Test
101    public void testSsidIsTelephoneSpan() {
102        final Bundle bundle = new Bundle();
103        bundle.putString("key_ssid", TEST_SSID);
104        final AccessPoint ap = new AccessPoint(InstrumentationRegistry.getTargetContext(), bundle);
105        final CharSequence ssid = ap.getSsid();
106
107        assertThat(ssid instanceof SpannableString).isTrue();
108
109        TtsSpan[] spans = ((SpannableString) ssid).getSpans(0, TEST_SSID.length(), TtsSpan.class);
110
111        assertThat(spans.length).isEqualTo(1);
112        assertThat(spans[0].getType()).isEqualTo(TtsSpan.TYPE_TELEPHONE);
113    }
114
115    @Test
116    public void testCopyAccessPoint_dataShouldMatch() {
117        WifiConfiguration configuration = createWifiConfiguration();
118        configuration.meteredHint = true;
119
120        NetworkInfo networkInfo =
121                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
122        AccessPoint originalAccessPoint = new AccessPoint(mContext, configuration);
123        WifiInfo wifiInfo = new WifiInfo();
124        wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
125        wifiInfo.setBSSID(configuration.BSSID);
126        originalAccessPoint.update(configuration, wifiInfo, networkInfo);
127        AccessPoint copy = new AccessPoint(mContext, originalAccessPoint);
128
129        assertThat(originalAccessPoint.getSsid().toString()).isEqualTo(copy.getSsid().toString());
130        assertThat(originalAccessPoint.getBssid()).isEqualTo(copy.getBssid());
131        assertThat(originalAccessPoint.getConfig()).isEqualTo(copy.getConfig());
132        assertThat(originalAccessPoint.getSecurity()).isEqualTo(copy.getSecurity());
133        assertThat(originalAccessPoint.isMetered()).isEqualTo(copy.isMetered());
134        assertThat(originalAccessPoint.compareTo(copy) == 0).isTrue();
135    }
136
137    @Test
138    public void testThatCopyAccessPoint_scanCacheShouldMatch() {
139        AccessPoint original = createAccessPointWithScanResultCache();
140        assertThat(original.getRssi()).isEqualTo(4);
141        AccessPoint copy = new AccessPoint(mContext, createWifiConfiguration());
142        assertThat(copy.getRssi()).isEqualTo(AccessPoint.UNREACHABLE_RSSI);
143        copy.copyFrom(original);
144        assertThat(original.getRssi()).isEqualTo(copy.getRssi());
145    }
146
147    @Test
148    public void testCompareTo_GivesActiveBeforeInactive() {
149        AccessPoint activeAp = new TestAccessPointBuilder(mContext).setActive(true).build();
150        AccessPoint inactiveAp = new TestAccessPointBuilder(mContext).setActive(false).build();
151
152        assertSortingWorks(activeAp, inactiveAp);
153    }
154
155    @Test
156    public void testCompareTo_GivesReachableBeforeUnreachable() {
157        AccessPoint nearAp = new TestAccessPointBuilder(mContext).setReachable(true).build();
158        AccessPoint farAp = new TestAccessPointBuilder(mContext).setReachable(false).build();
159
160        assertSortingWorks(nearAp, farAp);
161    }
162
163    @Test
164    public void testCompareTo_GivesSavedBeforeUnsaved() {
165        AccessPoint savedAp = new TestAccessPointBuilder(mContext).setSaved(true).build();
166        AccessPoint notSavedAp = new TestAccessPointBuilder(mContext).setSaved(false).build();
167
168        assertSortingWorks(savedAp, notSavedAp);
169    }
170
171    @Test
172    public void testCompareTo_GivesHighSpeedBeforeLowSpeed() {
173        AccessPoint fastAp = new TestAccessPointBuilder(mContext).setSpeed(Speed.FAST).build();
174        AccessPoint slowAp = new TestAccessPointBuilder(mContext).setSpeed(Speed.SLOW).build();
175
176        assertSortingWorks(fastAp, slowAp);
177    }
178
179    @Test
180    public void testCompareTo_GivesHighLevelBeforeLowLevel() {
181        final int highLevel = AccessPoint.SIGNAL_LEVELS - 1;
182        final int lowLevel = 1;
183        assertThat(highLevel).isGreaterThan(lowLevel);
184
185        AccessPoint strongAp = new TestAccessPointBuilder(mContext).setLevel(highLevel).build();
186        AccessPoint weakAp = new TestAccessPointBuilder(mContext).setLevel(lowLevel).build();
187
188        assertSortingWorks(strongAp, weakAp);
189    }
190
191    @Test
192    public void testCompareTo_GivesSsidAlphabetically() {
193
194        final String firstName = "AAAAAA";
195        final String secondName = "zzzzzz";
196
197        AccessPoint firstAp = new TestAccessPointBuilder(mContext).setSsid(firstName).build();
198        AccessPoint secondAp = new TestAccessPointBuilder(mContext).setSsid(secondName).build();
199
200        assertThat(firstAp.getSsidStr().compareToIgnoreCase(secondAp.getSsidStr()) < 0).isTrue();
201        assertSortingWorks(firstAp, secondAp);
202    }
203
204    @Test
205    public void testCompareTo_GivesSsidCasePrecendenceAfterAlphabetical() {
206
207        final String firstName = "aaAaaa";
208        final String secondName = "aaaaaa";
209        final String thirdName = "BBBBBB";
210
211        AccessPoint firstAp = new TestAccessPointBuilder(mContext).setSsid(firstName).build();
212        AccessPoint secondAp = new TestAccessPointBuilder(mContext).setSsid(secondName).build();
213        AccessPoint thirdAp = new TestAccessPointBuilder(mContext).setSsid(thirdName).build();
214
215        assertSortingWorks(firstAp, secondAp);
216        assertSortingWorks(secondAp, thirdAp);
217    }
218
219    @Test
220    public void testCompareTo_AllSortingRulesCombined() {
221
222        AccessPoint active = new TestAccessPointBuilder(mContext).setActive(true).build();
223        AccessPoint reachableAndMinLevel = new TestAccessPointBuilder(mContext)
224                .setReachable(true).build();
225        AccessPoint saved = new TestAccessPointBuilder(mContext).setSaved(true).build();
226        AccessPoint highLevelAndReachable = new TestAccessPointBuilder(mContext)
227                .setLevel(AccessPoint.SIGNAL_LEVELS - 1).build();
228        AccessPoint firstName = new TestAccessPointBuilder(mContext).setSsid("a").build();
229        AccessPoint lastname = new TestAccessPointBuilder(mContext).setSsid("z").build();
230
231        ArrayList<AccessPoint> points = new ArrayList<AccessPoint>();
232        points.add(lastname);
233        points.add(firstName);
234        points.add(highLevelAndReachable);
235        points.add(saved);
236        points.add(reachableAndMinLevel);
237        points.add(active);
238
239        Collections.sort(points);
240        assertThat(points.indexOf(active)).isLessThan(points.indexOf(reachableAndMinLevel));
241        assertThat(points.indexOf(reachableAndMinLevel)).isLessThan(points.indexOf(saved));
242        // note: the saved AP will not appear before highLevelAndReachable,
243        // because all APs with a signal level are reachable,
244        // and isReachable() takes higher sorting precedence than isSaved().
245        assertThat(points.indexOf(saved)).isLessThan(points.indexOf(firstName));
246        assertThat(points.indexOf(highLevelAndReachable)).isLessThan(points.indexOf(firstName));
247        assertThat(points.indexOf(firstName)).isLessThan(points.indexOf(lastname));
248    }
249
250    @Test
251    public void testRssiIsSetFromScanResults() {
252        AccessPoint ap = createAccessPointWithScanResultCache();
253        int originalRssi = ap.getRssi();
254        assertThat(originalRssi).isNotEqualTo(AccessPoint.UNREACHABLE_RSSI);
255    }
256
257    @Test
258    public void testGetRssiShouldReturnSetRssiValue() {
259        AccessPoint ap = createAccessPointWithScanResultCache();
260        int originalRssi = ap.getRssi();
261        int newRssi = originalRssi - 10;
262        ap.setRssi(newRssi);
263        assertThat(ap.getRssi()).isEqualTo(newRssi);
264    }
265
266    @Test
267    public void testUpdateWithScanResultShouldAverageRssi() {
268        String ssid = "ssid";
269        int originalRssi = -65;
270        int newRssi = -80;
271        int expectedRssi = (originalRssi + newRssi) / 2;
272        AccessPoint ap =
273                new TestAccessPointBuilder(mContext).setSsid(ssid).setRssi(originalRssi).build();
274
275        ScanResult scanResult = new ScanResult();
276        scanResult.SSID = ssid;
277        scanResult.level = newRssi;
278        scanResult.BSSID = "bssid";
279        scanResult.timestamp = SystemClock.elapsedRealtime() * 1000;
280        scanResult.capabilities = "";
281        assertThat(ap.update(scanResult, true /* evict old scan results */)).isTrue();
282
283        assertThat(ap.getRssi()).isEqualTo(expectedRssi);
284    }
285
286    @Test
287    public void testCreateFromPasspointConfig() {
288        PasspointConfiguration config = new PasspointConfiguration();
289        HomeSp homeSp = new HomeSp();
290        homeSp.setFqdn("test.com");
291        homeSp.setFriendlyName("Test Provider");
292        config.setHomeSp(homeSp);
293        AccessPoint ap = new AccessPoint(mContext, config);
294        assertThat(ap.isPasspointConfig()).isTrue();
295    }
296
297    @Test
298    public void testIsMetered_returnTrueWhenWifiConfigurationIsMetered() {
299        WifiConfiguration configuration = createWifiConfiguration();
300        configuration.meteredHint = true;
301
302        NetworkInfo networkInfo =
303                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
304        AccessPoint accessPoint = new AccessPoint(mContext, configuration);
305        WifiInfo wifiInfo = new WifiInfo();
306        wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
307        wifiInfo.setBSSID(configuration.BSSID);
308        wifiInfo.setNetworkId(configuration.networkId);
309        accessPoint.update(configuration, wifiInfo, networkInfo);
310
311        assertThat(accessPoint.isMetered()).isTrue();
312    }
313
314    @Test
315    public void testIsMetered_returnTrueWhenWifiInfoIsMetered() {
316        WifiConfiguration configuration = createWifiConfiguration();
317
318        NetworkInfo networkInfo =
319                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
320        AccessPoint accessPoint = new AccessPoint(mContext, configuration);
321        WifiInfo wifiInfo = new WifiInfo();
322        wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
323        wifiInfo.setBSSID(configuration.BSSID);
324        wifiInfo.setNetworkId(configuration.networkId);
325        wifiInfo.setMeteredHint(true);
326        accessPoint.update(configuration, wifiInfo, networkInfo);
327
328        assertThat(accessPoint.isMetered()).isTrue();
329    }
330
331    @Test
332    public void testIsMetered_returnTrueWhenScoredNetworkIsMetered() {
333        AccessPoint ap = createAccessPointWithScanResultCache();
334
335        when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
336                .thenReturn(
337                        new ScoredNetwork(
338                                null /* NetworkKey */,
339                                null /* rssiCurve */,
340                                true /* metered */));
341        ap.update(mockWifiNetworkScoreCache, false /* scoringUiEnabled */,
342                MAX_SCORE_CACHE_AGE_MILLIS);
343
344        assertThat(ap.isMetered()).isTrue();
345    }
346
347    @Test
348    public void testIsMetered_returnFalseByDefault() {
349        WifiConfiguration configuration = createWifiConfiguration();
350
351        NetworkInfo networkInfo =
352                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE");
353        AccessPoint accessPoint = new AccessPoint(mContext, configuration);
354        WifiInfo wifiInfo = new WifiInfo();
355        wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID));
356        wifiInfo.setBSSID(configuration.BSSID);
357        wifiInfo.setNetworkId(configuration.networkId);
358        accessPoint.update(configuration, wifiInfo, networkInfo);
359
360        assertThat(accessPoint.isMetered()).isFalse();
361    }
362
363    @Test
364    public void testSpeedLabel_returnsVeryFast() {
365        AccessPoint ap = createAccessPointWithScanResultCache();
366
367        when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
368                .thenReturn(buildScoredNetworkWithMockBadgeCurve());
369        when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST);
370
371        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
372                MAX_SCORE_CACHE_AGE_MILLIS);
373
374        assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.VERY_FAST);
375        assertThat(ap.getSpeedLabel())
376                .isEqualTo(mContext.getString(R.string.speed_label_very_fast));
377    }
378
379    @Test
380    public void testSpeedLabel_returnsFast() {
381        AccessPoint ap = createAccessPointWithScanResultCache();
382
383        when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
384                .thenReturn(buildScoredNetworkWithMockBadgeCurve());
385        when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.FAST);
386
387        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
388                MAX_SCORE_CACHE_AGE_MILLIS);
389
390
391        assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.FAST);
392        assertThat(ap.getSpeedLabel())
393                .isEqualTo(mContext.getString(R.string.speed_label_fast));
394    }
395
396    @Test
397    public void testSpeedLabel_returnsOkay() {
398        AccessPoint ap = createAccessPointWithScanResultCache();
399
400        when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
401                .thenReturn(buildScoredNetworkWithMockBadgeCurve());
402        when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.MODERATE);
403
404        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
405                MAX_SCORE_CACHE_AGE_MILLIS);
406
407        assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.MODERATE);
408        assertThat(ap.getSpeedLabel())
409                .isEqualTo(mContext.getString(R.string.speed_label_okay));
410    }
411
412    @Test
413    public void testSpeedLabel_returnsSlow() {
414        AccessPoint ap = createAccessPointWithScanResultCache();
415
416        when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
417                .thenReturn(buildScoredNetworkWithMockBadgeCurve());
418        when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.SLOW);
419
420        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
421                MAX_SCORE_CACHE_AGE_MILLIS);
422
423        assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.SLOW);
424        assertThat(ap.getSpeedLabel())
425                .isEqualTo(mContext.getString(R.string.speed_label_slow));
426    }
427
428    @Test
429    public void testSummaryString_showsSpeedLabel() {
430        AccessPoint ap = createAccessPointWithScanResultCache();
431
432        when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
433                .thenReturn(buildScoredNetworkWithMockBadgeCurve());
434        when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST);
435
436        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
437                MAX_SCORE_CACHE_AGE_MILLIS);
438
439        assertThat(ap.getSummary()).isEqualTo(mContext.getString(R.string.speed_label_very_fast));
440    }
441
442    @Test
443    public void testVerboseSummaryString_showsScanResultSpeedLabel() {
444        WifiTracker.sVerboseLogging = true;
445
446        Bundle bundle = new Bundle();
447        ArrayList<ScanResult> scanResults = buildScanResultCache();
448        bundle.putParcelableArrayList(AccessPoint.KEY_SCANRESULTCACHE, scanResults);
449        AccessPoint ap = new AccessPoint(mContext, bundle);
450
451        when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
452                .thenReturn(buildScoredNetworkWithMockBadgeCurve());
453        when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST);
454
455        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
456                MAX_SCORE_CACHE_AGE_MILLIS);
457        String summary = ap.verboseScanResultSummary(scanResults.get(0), null, 0);
458
459        assertThat(summary.contains(mContext.getString(R.string.speed_label_very_fast))).isTrue();
460    }
461
462    @Test
463    public void testSummaryString_concatenatesSpeedLabel() {
464        AccessPoint ap = createAccessPointWithScanResultCache();
465        ap.update(new WifiConfiguration());
466
467        when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
468                .thenReturn(buildScoredNetworkWithMockBadgeCurve());
469        when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST);
470
471        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
472                MAX_SCORE_CACHE_AGE_MILLIS);
473
474        String expectedString = mContext.getString(R.string.speed_label_very_fast) + " / "
475                + mContext.getString(R.string.wifi_remembered);
476        assertThat(ap.getSummary()).isEqualTo(expectedString);
477    }
478
479    @Test
480    public void testSummaryString_showsWrongPasswordLabel() {
481        WifiConfiguration configuration = createWifiConfiguration();
482        configuration.getNetworkSelectionStatus().setNetworkSelectionStatus(
483                WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED);
484        configuration.getNetworkSelectionStatus().setNetworkSelectionDisableReason(
485                WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD);
486        AccessPoint ap = new AccessPoint(mContext, configuration);
487
488        assertThat(ap.getSummary()).isEqualTo(mContext.getString(
489                R.string.wifi_check_password_try_again));
490    }
491
492    @Test
493    public void testSummaryString_showsAvaiableViaCarrier() {
494        String carrierName = "Test Carrier";
495        ScanResult result = new ScanResult();
496        result.BSSID = "00:11:22:33:44:55";
497        result.capabilities = "EAP";
498        result.isCarrierAp = true;
499        result.carrierApEapType = WifiEnterpriseConfig.Eap.SIM;
500        result.carrierName = carrierName;
501
502        AccessPoint ap = new AccessPoint(mContext, result);
503        assertThat(ap.getSummary()).isEqualTo(String.format(mContext.getString(
504                R.string.available_via_carrier), carrierName));
505        assertThat(ap.isCarrierAp()).isEqualTo(true);
506        assertThat(ap.getCarrierApEapType()).isEqualTo(WifiEnterpriseConfig.Eap.SIM);
507        assertThat(ap.getCarrierName()).isEqualTo(carrierName);
508    }
509
510    @Test
511    public void testSummaryString_showsConnectedViaCarrier() {
512        int networkId = 123;
513        int rssi = -55;
514        String carrierName = "Test Carrier";
515        WifiConfiguration config = new WifiConfiguration();
516        config.networkId = networkId;
517        WifiInfo wifiInfo = new WifiInfo();
518        wifiInfo.setNetworkId(networkId);
519        wifiInfo.setRssi(rssi);
520
521        NetworkInfo networkInfo =
522                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
523        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
524
525        AccessPoint ap = new TestAccessPointBuilder(mContext)
526                .setNetworkInfo(networkInfo)
527                .setNetworkId(networkId)
528                .setRssi(rssi)
529                .setWifiInfo(wifiInfo)
530                .setIsCarrierAp(true)
531                .setCarrierName(carrierName)
532                .build();
533        assertThat(ap.getSummary()).isEqualTo(String.format(mContext.getString(
534                R.string.connected_via_carrier), carrierName));
535    }
536
537    @Test
538    public void testUpdateScanResultWithCarrierInfo() {
539        String ssid = "ssid";
540        AccessPoint ap = new TestAccessPointBuilder(mContext).setSsid(ssid).build();
541        assertThat(ap.isCarrierAp()).isEqualTo(false);
542        assertThat(ap.getCarrierApEapType()).isEqualTo(WifiEnterpriseConfig.Eap.NONE);
543        assertThat(ap.getCarrierName()).isEqualTo(null);
544
545        int carrierApEapType = WifiEnterpriseConfig.Eap.SIM;
546        String carrierName = "Test Carrier";
547        ScanResult scanResult = new ScanResult();
548        scanResult.SSID = ssid;
549        scanResult.BSSID = "00:11:22:33:44:55";
550        scanResult.capabilities = "";
551        scanResult.isCarrierAp = true;
552        scanResult.carrierApEapType = carrierApEapType;
553        scanResult.carrierName = carrierName;
554        assertThat(ap.update(scanResult, true /* evictOldScanresults */)).isTrue();
555
556        assertThat(ap.isCarrierAp()).isEqualTo(true);
557        assertThat(ap.getCarrierApEapType()).isEqualTo(carrierApEapType);
558        assertThat(ap.getCarrierName()).isEqualTo(carrierName);
559    }
560
561    private ScoredNetwork buildScoredNetworkWithMockBadgeCurve() {
562        return buildScoredNetworkWithGivenBadgeCurve(mockBadgeCurve);
563
564    }
565
566    private ScoredNetwork buildScoredNetworkWithGivenBadgeCurve(RssiCurve badgeCurve) {
567        Bundle attr1 = new Bundle();
568        attr1.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, badgeCurve);
569        return new ScoredNetwork(
570                new NetworkKey(new WifiKey(TEST_SSID, TEST_BSSID)),
571                badgeCurve,
572                false /* meteredHint */,
573                attr1);
574
575    }
576
577    private AccessPoint createAccessPointWithScanResultCache() {
578        Bundle bundle = new Bundle();
579        bundle.putParcelableArrayList(AccessPoint.KEY_SCANRESULTCACHE, SCAN_RESULTS);
580        return new AccessPoint(mContext, bundle);
581    }
582
583    private static ArrayList<ScanResult> buildScanResultCache() {
584        ArrayList<ScanResult> scanResults = new ArrayList<>();
585        for (int i = 0; i < 5; i++) {
586            ScanResult scanResult = createScanResult(TEST_SSID, "bssid-" + i, i);
587            scanResults.add(scanResult);
588        }
589        return scanResults;
590    }
591
592    private WifiConfiguration createWifiConfiguration() {
593        WifiConfiguration configuration = new WifiConfiguration();
594        configuration.BSSID = "bssid";
595        configuration.SSID = "ssid";
596        configuration.networkId = 123;
597        return configuration;
598    }
599
600    private AccessPoint createApWithFastTimestampedScoredNetworkCache(
601            long elapsedTimeMillis) {
602        TimestampedScoredNetwork recentScore = new TimestampedScoredNetwork(
603                buildScoredNetworkWithGivenBadgeCurve(FAST_BADGE_CURVE),
604                elapsedTimeMillis);
605        return new TestAccessPointBuilder(mContext)
606                .setSsid(TEST_SSID)
607                .setScoredNetworkCache(
608                        new ArrayList<>(Arrays.asList(recentScore)))
609                .build();
610    }
611
612    /**
613    * Assert that the first AccessPoint appears before the second AccessPoint
614    * once sorting has been completed.
615    */
616    private void assertSortingWorks(AccessPoint first, AccessPoint second) {
617
618        ArrayList<AccessPoint> points = new ArrayList<AccessPoint>();
619
620        // add in reverse order so we can tell that sorting actually changed something
621        points.add(second);
622        points.add(first);
623        Collections.sort(points);
624        assertWithMessage(
625                String.format("After sorting: second AccessPoint should have higher array index "
626                    + "than the first, but found indicies second '%s' and first '%s'.",
627                    points.indexOf(second), points.indexOf(first)))
628            .that(points.indexOf(second)).isGreaterThan(points.indexOf(first));
629    }
630
631    @Test
632    public void testBuilder_setActive() {
633        AccessPoint activeAp = new TestAccessPointBuilder(mContext).setActive(true).build();
634        assertThat(activeAp.isActive()).isTrue();
635
636        AccessPoint inactiveAp = new TestAccessPointBuilder(mContext).setActive(false).build();
637        assertThat(inactiveAp.isActive()).isFalse();
638    }
639
640    @Test
641    public void testBuilder_setReachable() {
642        AccessPoint nearAp = new TestAccessPointBuilder(mContext).setReachable(true).build();
643        assertThat(nearAp.isReachable()).isTrue();
644
645        AccessPoint farAp = new TestAccessPointBuilder(mContext).setReachable(false).build();
646        assertThat(farAp.isReachable()).isFalse();
647    }
648
649    @Test
650    public void testBuilder_setSaved() {
651        AccessPoint savedAp = new TestAccessPointBuilder(mContext).setSaved(true).build();
652        assertThat(savedAp.isSaved()).isTrue();
653
654        AccessPoint newAp = new TestAccessPointBuilder(mContext).setSaved(false).build();
655        assertThat(newAp.isSaved()).isFalse();
656    }
657
658    @Test
659    public void testBuilder_setLevel() {
660        AccessPoint testAp;
661
662        for (int i = 0; i < AccessPoint.SIGNAL_LEVELS; i++) {
663            testAp = new TestAccessPointBuilder(mContext).setLevel(i).build();
664            assertThat(testAp.getLevel()).isEqualTo(i);
665        }
666
667        // numbers larger than the max level should be set to max
668        testAp = new TestAccessPointBuilder(mContext).setLevel(AccessPoint.SIGNAL_LEVELS).build();
669        assertThat(testAp.getLevel()).isEqualTo(AccessPoint.SIGNAL_LEVELS - 1);
670
671        // numbers less than 0 should give level 0
672        testAp = new TestAccessPointBuilder(mContext).setLevel(-100).build();
673        assertThat(testAp.getLevel()).isEqualTo(0);
674    }
675
676    @Test
677    public void testBuilder_settingReachableAfterLevelDoesNotAffectLevel() {
678        int level = 1;
679        assertThat(level).isLessThan(AccessPoint.SIGNAL_LEVELS - 1);
680
681        AccessPoint testAp =
682                new TestAccessPointBuilder(mContext).setLevel(level).setReachable(true).build();
683        assertThat(testAp.getLevel()).isEqualTo(level);
684    }
685
686    @Test
687    public void testBuilder_setSsid() {
688        String name = "AmazingSsid!";
689        AccessPoint namedAp = new TestAccessPointBuilder(mContext).setSsid(name).build();
690        assertThat(namedAp.getSsidStr()).isEqualTo(name);
691    }
692
693    @Test
694    public void testBuilder_passpointConfig() {
695        String fqdn = "Test.com";
696        String providerFriendlyName = "Test Provider";
697        AccessPoint ap = new TestAccessPointBuilder(mContext).setFqdn(fqdn)
698                .setProviderFriendlyName(providerFriendlyName).build();
699        assertThat(ap.isPasspointConfig()).isTrue();
700        assertThat(ap.getPasspointFqdn()).isEqualTo(fqdn);
701        assertThat(ap.getConfigName()).isEqualTo(providerFriendlyName);
702    }
703
704    @Test
705    public void testUpdateNetworkInfo_returnsTrue() {
706        int networkId = 123;
707        int rssi = -55;
708        WifiConfiguration config = new WifiConfiguration();
709        config.networkId = networkId;
710        WifiInfo wifiInfo = new WifiInfo();
711        wifiInfo.setNetworkId(networkId);
712        wifiInfo.setRssi(rssi);
713
714        NetworkInfo networkInfo =
715                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
716        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
717
718        AccessPoint ap = new TestAccessPointBuilder(mContext)
719                .setNetworkInfo(networkInfo)
720                .setNetworkId(networkId)
721                .setRssi(rssi)
722                .setWifiInfo(wifiInfo)
723                .build();
724
725        NetworkInfo newInfo = new NetworkInfo(networkInfo);
726        newInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
727        assertThat(ap.update(config, wifiInfo, newInfo)).isTrue();
728    }
729
730    @Test
731    public void testUpdateNetworkInfoWithSameInfo_returnsFalse() {
732        int networkId = 123;
733        int rssi = -55;
734        WifiConfiguration config = new WifiConfiguration();
735        config.networkId = networkId;
736        WifiInfo wifiInfo = new WifiInfo();
737        wifiInfo.setNetworkId(networkId);
738        wifiInfo.setRssi(rssi);
739
740        NetworkInfo networkInfo =
741                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
742        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
743
744        AccessPoint ap = new TestAccessPointBuilder(mContext)
745                .setNetworkInfo(networkInfo)
746                .setNetworkId(networkId)
747                .setRssi(rssi)
748                .setWifiInfo(wifiInfo)
749                .build();
750
751        NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values
752        assertThat(ap.update(config, wifiInfo, newInfo)).isFalse();
753    }
754
755    @Test
756    public void testUpdateWithDifferentRssi_returnsTrue() {
757        int networkId = 123;
758        int rssi = -55;
759        WifiConfiguration config = new WifiConfiguration();
760        config.networkId = networkId;
761        WifiInfo wifiInfo = new WifiInfo();
762        wifiInfo.setNetworkId(networkId);
763        wifiInfo.setRssi(rssi);
764
765        NetworkInfo networkInfo =
766                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
767        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
768
769        AccessPoint ap = new TestAccessPointBuilder(mContext)
770                .setNetworkInfo(networkInfo)
771                .setNetworkId(networkId)
772                .setRssi(rssi)
773                .setWifiInfo(wifiInfo)
774                .build();
775
776        NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values
777        wifiInfo.setRssi(rssi + 1);
778        assertThat(ap.update(config, wifiInfo, newInfo)).isTrue();
779    }
780
781    @Test
782    public void testUpdateWithInvalidRssi_returnsFalse() {
783        int networkId = 123;
784        int rssi = -55;
785        WifiConfiguration config = new WifiConfiguration();
786        config.networkId = networkId;
787        WifiInfo wifiInfo = new WifiInfo();
788        wifiInfo.setNetworkId(networkId);
789        wifiInfo.setRssi(rssi);
790
791        NetworkInfo networkInfo =
792                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
793        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
794
795        AccessPoint ap = new TestAccessPointBuilder(mContext)
796                .setNetworkInfo(networkInfo)
797                .setNetworkId(networkId)
798                .setRssi(rssi)
799                .setWifiInfo(wifiInfo)
800                .build();
801
802        NetworkInfo newInfo = new NetworkInfo(networkInfo); // same values
803        wifiInfo.setRssi(WifiInfo.INVALID_RSSI);
804        assertThat(ap.update(config, wifiInfo, newInfo)).isFalse();
805    }
806    @Test
807    public void testUpdateWithConfigChangeOnly_returnsFalseButInvokesListener() {
808        int networkId = 123;
809        int rssi = -55;
810        WifiConfiguration config = new WifiConfiguration();
811        config.networkId = networkId;
812        config.numNoInternetAccessReports = 1;
813
814        WifiInfo wifiInfo = new WifiInfo();
815        wifiInfo.setNetworkId(networkId);
816        wifiInfo.setRssi(rssi);
817
818        NetworkInfo networkInfo =
819                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
820        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
821
822        AccessPoint ap = new TestAccessPointBuilder(mContext)
823                .setNetworkInfo(networkInfo)
824                .setNetworkId(networkId)
825                .setRssi(rssi)
826                .setWifiInfo(wifiInfo)
827                .build();
828
829        AccessPoint.AccessPointListener mockListener = mock(AccessPoint.AccessPointListener.class);
830        ap.setListener(mockListener);
831        WifiConfiguration newConfig = new WifiConfiguration(config);
832        config.validatedInternetAccess = true;
833
834        assertThat(ap.update(newConfig, wifiInfo, networkInfo)).isFalse();
835        verify(mockListener).onAccessPointChanged(ap);
836    }
837
838    @Test
839    public void testUpdateWithNullWifiConfiguration_doesNotThrowNPE() {
840        int networkId = 123;
841        int rssi = -55;
842        WifiConfiguration config = new WifiConfiguration();
843        config.networkId = networkId;
844        WifiInfo wifiInfo = new WifiInfo();
845        wifiInfo.setNetworkId(networkId);
846        wifiInfo.setRssi(rssi);
847
848        NetworkInfo networkInfo =
849                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
850        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
851
852        AccessPoint ap = new TestAccessPointBuilder(mContext)
853                .setNetworkInfo(networkInfo)
854                .setNetworkId(networkId)
855                .setRssi(rssi)
856                .setWifiInfo(wifiInfo)
857                .build();
858
859        ap.update(null, wifiInfo, networkInfo);
860    }
861
862    @Test
863    public void testSpeedLabelAveragesAllBssidScores() {
864        AccessPoint ap = createAccessPointWithScanResultCache();
865
866        int speed1 = Speed.MODERATE;
867        RssiCurve badgeCurve1 = mock(RssiCurve.class);
868        when(badgeCurve1.lookupScore(anyInt())).thenReturn((byte) speed1);
869        when(mockWifiNetworkScoreCache.getScoredNetwork(SCAN_RESULTS.get(0)))
870                .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve1));
871        int speed2 = Speed.VERY_FAST;
872        RssiCurve badgeCurve2 = mock(RssiCurve.class);
873        when(badgeCurve2.lookupScore(anyInt())).thenReturn((byte) speed2);
874        when(mockWifiNetworkScoreCache.getScoredNetwork(SCAN_RESULTS.get(1)))
875                .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve2));
876
877        int expectedSpeed = (speed1 + speed2) / 2;
878
879        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
880                MAX_SCORE_CACHE_AGE_MILLIS);
881
882        assertThat(ap.getSpeed()).isEqualTo(expectedSpeed);
883    }
884
885    @Test
886    public void testSpeedLabelAverageIgnoresNoSpeedScores() {
887        AccessPoint ap = createAccessPointWithScanResultCache();
888
889        int speed1 = Speed.VERY_FAST;
890        RssiCurve badgeCurve1 = mock(RssiCurve.class);
891        when(badgeCurve1.lookupScore(anyInt())).thenReturn((byte) speed1);
892        when(mockWifiNetworkScoreCache.getScoredNetwork(SCAN_RESULTS.get(0)))
893                .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve1));
894        int speed2 = Speed.NONE;
895        RssiCurve badgeCurve2 = mock(RssiCurve.class);
896        when(badgeCurve2.lookupScore(anyInt())).thenReturn((byte) speed2);
897        when(mockWifiNetworkScoreCache.getScoredNetwork(SCAN_RESULTS.get(1)))
898                .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve2));
899
900        ap.update(
901        mockWifiNetworkScoreCache, true /* scoringUiEnabled */, MAX_SCORE_CACHE_AGE_MILLIS);
902
903        assertThat(ap.getSpeed()).isEqualTo(speed1);
904    }
905
906    @Test
907    public void testSpeedLabelFallbackScoreIgnoresNullCurves() {
908        int rssi = -55;
909        String bssid = "00:00:00:00:00:00";
910        int networkId = 123;
911
912        WifiInfo info = new WifiInfo();
913        info.setRssi(rssi);
914        info.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID));
915        info.setBSSID(bssid);
916        info.setNetworkId(networkId);
917
918        ArrayList<ScanResult> scanResults = new ArrayList<>();
919        ScanResult scanResultUnconnected = createScanResult(TEST_SSID, "11:11:11:11:11:11", rssi);
920        scanResults.add(scanResultUnconnected);
921
922        ScanResult scanResultConnected = createScanResult(TEST_SSID, bssid, rssi);
923        scanResults.add(scanResultConnected);
924
925        AccessPoint ap =
926                new TestAccessPointBuilder(mContext)
927                        .setActive(true)
928                        .setNetworkId(networkId)
929                        .setSsid(TEST_SSID)
930                        .setScanResultCache(scanResults)
931                        .setWifiInfo(info)
932                        .build();
933
934        int fallbackSpeed = Speed.SLOW;
935        when(mockWifiNetworkScoreCache.getScoredNetwork(scanResultUnconnected))
936                .thenReturn(buildScoredNetworkWithMockBadgeCurve());
937        when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) fallbackSpeed);
938
939        when(mockWifiNetworkScoreCache.getScoredNetwork(scanResultConnected))
940                .thenReturn(null);
941
942        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
943                MAX_SCORE_CACHE_AGE_MILLIS);
944
945        assertThat(ap.getSpeed()).isEqualTo(fallbackSpeed);
946    }
947
948    @Test
949    public void testScoredNetworkCacheBundling() {
950        long timeMillis = SystemClock.elapsedRealtime();
951        AccessPoint ap = createApWithFastTimestampedScoredNetworkCache(timeMillis);
952        Bundle bundle = new Bundle();
953        ap.saveWifiState(bundle);
954
955        ArrayList<TimestampedScoredNetwork> list =
956                bundle.getParcelableArrayList(AccessPoint.KEY_SCOREDNETWORKCACHE);
957        assertThat(list).hasSize(1);
958        assertThat(list.get(0).getUpdatedTimestampMillis()).isEqualTo(timeMillis);
959
960        RssiCurve curve = list.get(0).getScore().attributes.getParcelable(
961                ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE);
962        assertThat(curve).isEqualTo(FAST_BADGE_CURVE);
963    }
964
965    @Test
966    public void testRecentNetworkScoresAreUsedForSpeedLabelGeneration() {
967        AccessPoint ap =
968                createApWithFastTimestampedScoredNetworkCache(SystemClock.elapsedRealtime());
969
970        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
971                MAX_SCORE_CACHE_AGE_MILLIS);
972
973        assertThat(ap.getSpeed()).isEqualTo(Speed.FAST);
974    }
975
976    @Test
977    public void testNetworkScoresAreUsedForSpeedLabelGenerationWhenWithinAgeRange() {
978        long withinRangeTimeMillis =
979                SystemClock.elapsedRealtime() - (MAX_SCORE_CACHE_AGE_MILLIS - 10000);
980        AccessPoint ap =
981                createApWithFastTimestampedScoredNetworkCache(withinRangeTimeMillis);
982
983        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
984                MAX_SCORE_CACHE_AGE_MILLIS);
985
986        assertThat(ap.getSpeed()).isEqualTo(Speed.FAST);
987    }
988
989    @Test
990    public void testOldNetworkScoresAreNotUsedForSpeedLabelGeneration() {
991        long tooOldTimeMillis =
992                SystemClock.elapsedRealtime() - (MAX_SCORE_CACHE_AGE_MILLIS + 1);
993        AccessPoint ap =
994                createApWithFastTimestampedScoredNetworkCache(tooOldTimeMillis);
995
996        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
997                MAX_SCORE_CACHE_AGE_MILLIS);
998
999        assertThat(ap.getSpeed()).isEqualTo(Speed.NONE);
1000    }
1001
1002    @Test
1003    public void testUpdateScoresRefreshesScoredNetworkCacheTimestamps () {
1004        long tooOldTimeMillis =
1005                SystemClock.elapsedRealtime() - (MAX_SCORE_CACHE_AGE_MILLIS + 1);
1006
1007        ScoredNetwork scoredNetwork = buildScoredNetworkWithGivenBadgeCurve(FAST_BADGE_CURVE);
1008        TimestampedScoredNetwork recentScore = new TimestampedScoredNetwork(
1009                scoredNetwork,
1010                tooOldTimeMillis);
1011        AccessPoint ap = new TestAccessPointBuilder(mContext)
1012                .setSsid(TEST_SSID)
1013                .setBssid(TEST_BSSID)
1014                .setActive(true)
1015                .setScoredNetworkCache(
1016                        new ArrayList(Arrays.asList(recentScore)))
1017                .setScanResultCache(SCAN_RESULTS)
1018                .build();
1019
1020        when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
1021                .thenReturn(scoredNetwork);
1022
1023        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
1024                MAX_SCORE_CACHE_AGE_MILLIS);
1025
1026        // Fast should still be returned since cache was updated with recent time
1027        assertThat(ap.getSpeed()).isEqualTo(Speed.FAST);
1028    }
1029
1030    @Test
1031    public void testUpdateScoresRefreshesScoredNetworkCacheWithNewSpeed () {
1032        long tooOldTimeMillis =
1033                SystemClock.elapsedRealtime() - (MAX_SCORE_CACHE_AGE_MILLIS + 1);
1034
1035        ScoredNetwork scoredNetwork = buildScoredNetworkWithGivenBadgeCurve(FAST_BADGE_CURVE);
1036        TimestampedScoredNetwork recentScore = new TimestampedScoredNetwork(
1037                scoredNetwork,
1038                tooOldTimeMillis);
1039        AccessPoint ap = new TestAccessPointBuilder(mContext)
1040                .setSsid(TEST_SSID)
1041                .setBssid(TEST_BSSID)
1042                .setActive(true)
1043                .setScoredNetworkCache(
1044                        new ArrayList(Arrays.asList(recentScore)))
1045                .setScanResultCache(SCAN_RESULTS)
1046                .build();
1047
1048        int newSpeed = Speed.MODERATE;
1049        when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class)))
1050                .thenReturn(buildScoredNetworkWithMockBadgeCurve());
1051        when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) newSpeed);
1052
1053        ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */,
1054                MAX_SCORE_CACHE_AGE_MILLIS);
1055
1056        // Fast should still be returned since cache was updated with recent time
1057        assertThat(ap.getSpeed()).isEqualTo(newSpeed);
1058    }
1059}
1060