diff options
Diffstat (limited to 'tests')
30 files changed, 687 insertions, 220 deletions
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp index a23ac38785f6..125deb521ddc 100644 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.bp @@ -33,5 +33,6 @@ cc_test_library { "-Werror", "-Wno-unused-parameter", ], + header_libs: ["jni_headers"], stl: "c++_static", } diff --git a/tests/DynamicCodeLoggerIntegrationTests/Android.mk b/tests/DynamicCodeLoggerIntegrationTests/Android.mk index 62c1ba89653c..2d58ce8baddc 100644 --- a/tests/DynamicCodeLoggerIntegrationTests/Android.mk +++ b/tests/DynamicCodeLoggerIntegrationTests/Android.mk @@ -36,8 +36,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_MODULE := DynamicCodeLoggerNativeTestLibrary LOCAL_SRC_FILES := src/cpp/com_android_dcl_Jni.cpp -LOCAL_C_INCLUDES += \ - $(JNI_H_INCLUDE) +LOCAL_HEADER_LIBRARIES := jni_headers LOCAL_SDK_VERSION := 28 LOCAL_NDK_STL_VARIANT := c++_static diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml index d1da47f0f9d8..a331ec5b52bd 100644 --- a/tests/FlickerTests/AndroidTest.xml +++ b/tests/FlickerTests/AndroidTest.xml @@ -9,6 +9,14 @@ <option name="screen-always-on" value="on" /> <!-- prevents the phone from restarting --> <option name="force-skip-system-props" value="true" /> + <!-- set WM tracing verbose level to all --> + <option name="run-command" value="adb shell cmd window tracing level all" /> + <!-- inform WM to log all transactions --> + <option name="run-command" value="adb shell cmd window tracing transaction" /> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.DeviceCleaner"> + <!-- keeps the screen on during tests --> + <option name="cleanup-action" value="REBOOT" /> </target_preparer> <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true"/> diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java index 5a66e805c575..ad64840aaee2 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java @@ -144,6 +144,19 @@ public class ChangeAppRotationTest extends FlickerTestBase { ); } + @Test + public void checkVisibility_screenshotLayerBecomesInvisible() { + checkResults(result -> LayersTraceSubject.assertThat(result) + .showsLayer(mTestApp.getPackage()) + .then() + .replaceVisibleLayer(mTestApp.getPackage(), "Screenshot") + .then() + .showsLayer(mTestApp.getPackage()).and().showsLayer("Screenshot") + .then() + .replaceVisibleLayer("Screenshot", mTestApp.getPackage()) + .forAllEntries()); + } + @FlakyTest(bugId = 140855415) @Ignore("Waiting bug feedback") @Test diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java index e033d0ab9578..0201a95b18bb 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java @@ -20,7 +20,6 @@ import static android.os.SystemClock.sleep; import static android.view.Surface.rotationToString; import static com.android.server.wm.flicker.helpers.AutomationUtils.clearRecents; -import static com.android.server.wm.flicker.helpers.AutomationUtils.closePipWindow; import static com.android.server.wm.flicker.helpers.AutomationUtils.exitSplitScreen; import static com.android.server.wm.flicker.helpers.AutomationUtils.expandPipWindow; import static com.android.server.wm.flicker.helpers.AutomationUtils.launchSplitScreen; @@ -176,11 +175,15 @@ class CommonTransitions { .repeat(ITERATIONS); } - static TransitionBuilder appToSplitScreen(IAppHelper testApp, UiDevice device) { + static TransitionBuilder appToSplitScreen(IAppHelper testApp, UiDevice device, + int beginRotation) { + final String testTag = "appToSplitScreen_" + testApp.getLauncherName() + "_" + + rotationToString(beginRotation); return TransitionRunner.newBuilder() - .withTag("appToSplitScreen_" + testApp.getLauncherName()) + .withTag(testTag) .recordAllRuns() .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) + .runBeforeAll(() -> setRotation(device, beginRotation)) .runBefore(testApp::open) .runBefore(device::waitForIdle) .runBefore(() -> sleep(500)) @@ -285,41 +288,52 @@ class CommonTransitions { .repeat(ITERATIONS); } - static TransitionBuilder enterPipMode(PipAppHelper testApp, UiDevice device) { + static TransitionBuilder enterPipMode(PipAppHelper testApp, UiDevice device, + int beginRotation) { return TransitionRunner.newBuilder() - .withTag("enterPipMode_" + testApp.getLauncherName()) + .withTag("enterPipMode_" + testApp.getLauncherName() + + rotationToString(beginRotation)) .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) .runBefore(device::pressHome) + .runBefore(() -> setRotation(device, beginRotation)) .runBefore(testApp::open) .run(() -> testApp.clickEnterPipButton(device)) - .runAfter(() -> closePipWindow(device)) + .runAfter(() -> testApp.closePipWindow(device)) .runAfterAll(testApp::exit) .repeat(ITERATIONS); } - static TransitionBuilder exitPipModeToHome(PipAppHelper testApp, UiDevice device) { + static TransitionBuilder exitPipModeToHome(PipAppHelper testApp, UiDevice device, + int beginRotation) { return TransitionRunner.newBuilder() - .withTag("exitPipModeToHome_" + testApp.getLauncherName()) + .withTag("exitPipModeToHome_" + testApp.getLauncherName() + + rotationToString(beginRotation)) + .recordAllRuns() .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) .runBefore(device::pressHome) + .runBefore(() -> setRotation(device, beginRotation)) .runBefore(testApp::open) - .runBefore(() -> testApp.clickEnterPipButton(device)) - .run(() -> closePipWindow(device)) + .run(() -> testApp.clickEnterPipButton(device)) + .run(() -> testApp.closePipWindow(device)) .run(device::waitForIdle) - .runAfterAll(testApp::exit) + .run(testApp::exit) .repeat(ITERATIONS); } - static TransitionBuilder exitPipModeToApp(PipAppHelper testApp, UiDevice device) { + static TransitionBuilder exitPipModeToApp(PipAppHelper testApp, UiDevice device, + int beginRotation) { return TransitionRunner.newBuilder() - .withTag("exitPipModeToApp_" + testApp.getLauncherName()) + .withTag("exitPipModeToApp_" + testApp.getLauncherName() + + rotationToString(beginRotation)) + .recordAllRuns() .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) - .runBefore(device::pressHome) - .runBefore(testApp::open) - .runBefore(() -> testApp.clickEnterPipButton(device)) + .run(device::pressHome) + .run(() -> setRotation(device, beginRotation)) + .run(testApp::open) + .run(() -> testApp.clickEnterPipButton(device)) .run(() -> expandPipWindow(device)) .run(device::waitForIdle) - .runAfterAll(testApp::exit) + .run(testApp::exit) .repeat(ITERATIONS); } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java index 8f0177c7afc5..666a0b9be779 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java @@ -94,7 +94,8 @@ public class DebugTest { */ @Test public void openAppToSplitScreen() { - CommonTransitions.appToSplitScreen(testApp, uiDevice).includeJankyRuns().recordAllRuns() + CommonTransitions.appToSplitScreen(testApp, uiDevice, + Surface.ROTATION_0).includeJankyRuns().recordAllRuns() .build().run(); } @@ -116,7 +117,7 @@ public class DebugTest { ImeAppHelper bottomApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); CommonTransitions.resizeSplitScreen(testApp, bottomApp, uiDevice, Surface.ROTATION_0, new Rational(1, 3), new Rational(2, 3)) - .includeJankyRuns().recordEachRun().build().run(); + .includeJankyRuns().build().run(); } // IME tests @@ -128,7 +129,7 @@ public class DebugTest { public void editTextSetFocus() { ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); CommonTransitions.editTextSetFocus(testApp, uiDevice, Surface.ROTATION_0) - .includeJankyRuns().recordEachRun() + .includeJankyRuns() .build().run(); } @@ -139,7 +140,7 @@ public class DebugTest { public void editTextLoseFocusToHome() { ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0) - .includeJankyRuns().recordEachRun() + .includeJankyRuns() .build().run(); } @@ -150,7 +151,7 @@ public class DebugTest { public void editTextLoseFocusToApp() { ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0) - .includeJankyRuns().recordEachRun() + .includeJankyRuns() .build().run(); } @@ -162,7 +163,7 @@ public class DebugTest { @Test public void enterPipMode() { PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation()); - CommonTransitions.enterPipMode(testApp, uiDevice).includeJankyRuns().recordEachRun() + CommonTransitions.enterPipMode(testApp, uiDevice, Surface.ROTATION_0).includeJankyRuns() .build().run(); } @@ -172,7 +173,8 @@ public class DebugTest { @Test public void exitPipModeToHome() { PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation()); - CommonTransitions.exitPipModeToHome(testApp, uiDevice).includeJankyRuns().recordEachRun() + CommonTransitions.exitPipModeToHome(testApp, uiDevice, Surface.ROTATION_0) + .includeJankyRuns() .build().run(); } @@ -182,7 +184,7 @@ public class DebugTest { @Test public void exitPipModeToApp() { PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation()); - CommonTransitions.exitPipModeToApp(testApp, uiDevice).includeJankyRuns().recordEachRun() + CommonTransitions.exitPipModeToApp(testApp, uiDevice, Surface.ROTATION_0).includeJankyRuns() .build().run(); } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java index 883d59ea8a92..4578fa3f0b9a 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java @@ -89,7 +89,7 @@ public class FlickerTestBase { } if (result.screenCaptureVideoExists()) { Log.e(TAG, "Screen capture video saved to " + result - .screenCaptureVideo.toString()); + .screenCaptureVideoPath().toString()); } } }); diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java index efdfaee60e64..2981ff9aefe6 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java @@ -19,6 +19,8 @@ package com.android.server.wm.flicker; import static com.android.server.wm.flicker.CommonTransitions.openAppCold; import static com.android.server.wm.flicker.WmTraceSubject.assertThat; +import android.view.Surface; + import androidx.test.InstrumentationRegistry; import androidx.test.filters.FlakyTest; import androidx.test.filters.LargeTest; @@ -76,10 +78,20 @@ public class OpenAppColdTest extends NonRotationTestBase { @Test public void checkVisibility_wallpaperLayerBecomesInvisible() { - checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer("Wallpaper") - .then() - .hidesLayer("Wallpaper") - .forAllEntries()); + if (mBeginRotation == Surface.ROTATION_0) { + checkResults(result -> LayersTraceSubject.assertThat(result) + .showsLayer("Wallpaper") + .then() + .replaceVisibleLayer("Wallpaper", mTestApp.getPackage()) + .forAllEntries()); + } else { + checkResults(result -> LayersTraceSubject.assertThat(result) + .showsLayer("Wallpaper") + .then() + .replaceVisibleLayer("Wallpaper", "Screenshot") + .then() + .showsLayer(mTestApp.getPackage()) + .forAllEntries()); + } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java index f8b7938901a8..ddead6d321a0 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppToSplitScreenTest.java @@ -17,35 +17,38 @@ package com.android.server.wm.flicker; import static com.android.server.wm.flicker.CommonTransitions.appToSplitScreen; -import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; /** * Test open app to split screen. * To run this test: {@code atest FlickerTests:OpenAppToSplitScreenTest} */ @LargeTest -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class OpenAppToSplitScreenTest extends FlickerTestBase { +public class OpenAppToSplitScreenTest extends NonRotationTestBase { + + public OpenAppToSplitScreenTest(String beginRotationName, int beginRotation) { + super(beginRotationName, beginRotation); - public OpenAppToSplitScreenTest() { this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(), "com.android.server.wm.flicker.testapp", "SimpleApp"); } @Before public void runTransition() { - super.runTransition(appToSplitScreen(mTestApp, mUiDevice).includeJankyRuns().build()); + super.runTransition(appToSplitScreen(mTestApp, mUiDevice, mBeginRotation) + .includeJankyRuns() + .build()); } @Test @@ -70,25 +73,6 @@ public class OpenAppToSplitScreenTest extends FlickerTestBase { } @Test - public void checkCoveredRegion_noUncoveredRegions() { - checkResults(result -> - LayersTraceSubject.assertThat(result) - .coversRegion(getDisplayBounds()).forAllEntries()); - } - - @Test - public void checkVisibility_navBarLayerIsAlwaysVisible() { - checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()); - } - - @Test - public void checkVisibility_statusBarLayerIsAlwaysVisible() { - checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries()); - } - - @Test public void checkVisibility_dividerLayerBecomesVisible() { checkResults(result -> LayersTraceSubject.assertThat(result) .hidesLayer(DOCKED_STACK_DIVIDER) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java index 7ce6315f529a..bb684d19d645 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java @@ -19,6 +19,8 @@ package com.android.server.wm.flicker; import static com.android.server.wm.flicker.CommonTransitions.openAppWarm; import static com.android.server.wm.flicker.WmTraceSubject.assertThat; +import android.view.Surface; + import androidx.test.InstrumentationRegistry; import androidx.test.filters.FlakyTest; import androidx.test.filters.LargeTest; @@ -76,10 +78,20 @@ public class OpenAppWarmTest extends NonRotationTestBase { @Test public void checkVisibility_wallpaperLayerBecomesInvisible() { - checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer("Wallpaper") - .then() - .hidesLayer("Wallpaper") - .forAllEntries()); + if (mBeginRotation == Surface.ROTATION_0) { + checkResults(result -> LayersTraceSubject.assertThat(result) + .showsLayer("Wallpaper") + .then() + .replaceVisibleLayer("Wallpaper", mTestApp.getPackage()) + .forAllEntries()); + } else { + checkResults(result -> LayersTraceSubject.assertThat(result) + .showsLayer("Wallpaper") + .then() + .replaceVisibleLayer("Wallpaper", "Screenshot") + .then() + .showsLayer(mTestApp.getPackage()) + .forAllEntries()); + } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java new file mode 100644 index 000000000000..85706bd14c5e --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/PipToAppTest.java @@ -0,0 +1,89 @@ +/* + * 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.server.wm.flicker; + +import static com.android.server.wm.flicker.CommonTransitions.exitPipModeToApp; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; + +import com.android.server.wm.flicker.helpers.PipAppHelper; + +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; + +/** + * Test Pip launch. + * To run this test: {@code atest FlickerTests:PipToAppTest} + */ +@LargeTest +@RunWith(Parameterized.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class PipToAppTest extends NonRotationTestBase { + + static final String sPipWindowTitle = "PipMenuActivity"; + + public PipToAppTest(String beginRotationName, int beginRotation) { + super(beginRotationName, beginRotation); + + this.mTestApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation()); + } + + @Before + public void runTransition() { + run(exitPipModeToApp((PipAppHelper) mTestApp, mUiDevice, mBeginRotation) + .includeJankyRuns().build()); + } + + @Test + public void checkVisibility_pipWindowBecomesVisible() { + checkResults(result -> WmTraceSubject.assertThat(result) + .skipUntilFirstAssertion() + .showsAppWindowOnTop(sPipWindowTitle) + .then() + .hidesAppWindow(sPipWindowTitle) + .forAllEntries()); + } + + @Test + public void checkVisibility_pipLayerBecomesVisible() { + checkResults(result -> LayersTraceSubject.assertThat(result) + .skipUntilFirstAssertion() + .showsLayer(sPipWindowTitle) + .then() + .hidesLayer(sPipWindowTitle) + .forAllEntries()); + } + + @Test + public void checkVisibility_backgroundWindowVisibleBehindPipLayer() { + checkResults(result -> WmTraceSubject.assertThat(result) + .skipUntilFirstAssertion() + .showsAppWindowOnTop(sPipWindowTitle) + .then() + .showsBelowAppWindow("Wallpaper") + .then() + .showsAppWindowOnTop(mTestApp.getPackage()) + .then() + .hidesAppWindowOnTop(mTestApp.getPackage()) + .forAllEntries()); + } +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java new file mode 100644 index 000000000000..ef856dc52167 --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/PipToHomeTest.java @@ -0,0 +1,93 @@ +/* + * 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.server.wm.flicker; + +import static com.android.server.wm.flicker.CommonTransitions.exitPipModeToHome; + +import android.view.Surface; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.wm.flicker.helpers.PipAppHelper; + +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; + +/** + * Test Pip launch. + * To run this test: {@code atest FlickerTests:PipToHomeTest} + */ +@LargeTest +@RunWith(AndroidJUnit4.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class PipToHomeTest extends FlickerTestBase { + + static final String sPipWindowTitle = "PipActivity"; + + // public PipToHomeTest(String beginRotationName, int beginRotation) { + public PipToHomeTest() { + // super(beginRotationName, beginRotation); + + this.mTestApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation()); + } + + @Before + public void runTransition() { + // run(exitPipModeToHome((PipAppHelper) mTestApp, mUiDevice, mBeginRotation) + run(exitPipModeToHome((PipAppHelper) mTestApp, mUiDevice, Surface.ROTATION_0) + .includeJankyRuns().build()); + } + + @Ignore + @Test + public void checkVisibility_pipWindowBecomesVisible() { + checkResults(result -> WmTraceSubject.assertThat(result) + .skipUntilFirstAssertion() + .showsAppWindowOnTop(sPipWindowTitle) + .then() + .hidesAppWindow(sPipWindowTitle) + .forAllEntries()); + } + + @Test + public void checkVisibility_pipLayerBecomesVisible() { + checkResults(result -> LayersTraceSubject.assertThat(result) + .skipUntilFirstAssertion() + .showsLayer(sPipWindowTitle) + .then() + .hidesLayer(sPipWindowTitle) + .forAllEntries()); + } + + @Ignore + @Test + public void checkVisibility_backgroundWindowVisibleBehindPipLayer() { + checkResults(result -> WmTraceSubject.assertThat(result) + .showsAppWindowOnTop(sPipWindowTitle) + .then() + .showsBelowAppWindow("Wallpaper") + .then() + .showsAppWindowOnTop("Wallpaper") + .forAllEntries()); + } +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java index 29b624005495..e36701be0cad 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java @@ -95,7 +95,7 @@ public class ResizeSplitScreenTest extends NonRotationTestBase { Rect displayBounds = getDisplayBounds(); checkResults(result -> { LayersTrace entries = LayersTrace.parseFrom(result.getLayersTrace(), - result.getLayersTracePath()); + result.getLayersTracePath(), result.getLayersTraceChecksum()); assertThat(entries.getEntries()).isNotEmpty(); Rect startingDividerBounds = entries.getEntries().get(0).getVisibleBounds @@ -124,7 +124,7 @@ public class ResizeSplitScreenTest extends NonRotationTestBase { Rect displayBounds = getDisplayBounds(); checkResults(result -> { LayersTrace entries = LayersTrace.parseFrom(result.getLayersTrace(), - result.getLayersTracePath()); + result.getLayersTracePath(), result.getLayersTraceChecksum()); assertThat(entries.getEntries()).isNotEmpty(); Rect endingDividerBounds = entries.getEntries().get( diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java index d00e11b2994d..d5f9a2062a17 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java @@ -40,4 +40,8 @@ public class PipAppHelper extends FlickerAppHelper { } } + public void closePipWindow(UiDevice device) { + AutomationUtils.closePipWindow(device); + } + } diff --git a/tests/GamePerformance/Android.bp b/tests/GamePerformance/Android.bp new file mode 100644 index 000000000000..648fd8151b4e --- /dev/null +++ b/tests/GamePerformance/Android.bp @@ -0,0 +1,32 @@ +// Copyright (C) 2018 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_helper_app { + name: "GamePerformance", + // Don't include this package in any target + dex_preopt: { + enabled: false, + }, + optimize: { + enabled: false, + }, + srcs: ["src/**/*.java"], + static_libs: ["android-support-test"], + libs: [ + "android.test.base", + "android.test.runner", + ], + platform_apis: true, + certificate: "platform", +} diff --git a/tests/GamePerformance/Android.mk b/tests/GamePerformance/Android.mk deleted file mode 100644 index 58654de34029..000000000000 --- a/tests/GamePerformance/Android.mk +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (C) 2018 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. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -# Don't include this package in any target -LOCAL_MODULE_TAGS := tests - -LOCAL_DEX_PREOPT := false - -LOCAL_PROGUARD_ENABLED := disabled - -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_STATIC_JAVA_LIBRARIES := android-support-test - -LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner - -LOCAL_PACKAGE_NAME := GamePerformance - -LOCAL_PRIVATE_PLATFORM_APIS := true - -LOCAL_CERTIFICATE := platform - - -include $(BUILD_PACKAGE) diff --git a/tests/ProtoInputStreamTests/Android.bp b/tests/ProtoInputStreamTests/Android.bp new file mode 100644 index 000000000000..ecc405664128 --- /dev/null +++ b/tests/ProtoInputStreamTests/Android.bp @@ -0,0 +1,33 @@ +// 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: "ProtoInputStreamTests", + proto: { + type: "nano", + }, + srcs: [ + "src/**/*.java", + "src/**/*.proto", + ], + platform_apis: true, + certificate: "platform", + test_suites: ["device-tests"], + libs: ["android.test.runner"], + static_libs: [ + "androidx.test.rules", + "frameworks-base-testutils", + "mockito-target-minus-junit4", + ], +} diff --git a/tests/ProtoInputStreamTests/Android.mk b/tests/ProtoInputStreamTests/Android.mk deleted file mode 100644 index eb747cc2cdcc..000000000000 --- a/tests/ProtoInputStreamTests/Android.mk +++ /dev/null @@ -1,34 +0,0 @@ -# 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. - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_PACKAGE_NAME := ProtoInputStreamTests -LOCAL_PROTOC_OPTIMIZE_TYPE := nano -LOCAL_MODULE_TAGS := tests optional -LOCAL_SRC_FILES := \ - $(call all-java-files-under, src) \ - $(call all-proto-files-under, src) -LOCAL_PRIVATE_PLATFORM_APIS := true -LOCAL_CERTIFICATE := platform -LOCAL_COMPATIBILITY_SUITE := device-tests - -LOCAL_JAVA_LIBRARIES := android.test.runner -LOCAL_STATIC_JAVA_LIBRARIES := \ - androidx.test.rules \ - frameworks-base-testutils \ - mockito-target-minus-junit4 - -include $(BUILD_PACKAGE)
\ No newline at end of file diff --git a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt index ef15b668e24c..a50f0461fae6 100644 --- a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt +++ b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt @@ -39,12 +39,12 @@ class MatchAllNetworkSpecifierTest { } @Test(expected = IllegalStateException::class) - fun testSatisfiedBy() { + fun testCanBeSatisfiedBy() { val specifier = MatchAllNetworkSpecifier() val discoverySession = Mockito.mock(DiscoverySession::class.java) val peerHandle = Mockito.mock(PeerHandle::class.java) val wifiAwareNetworkSpecifier = WifiAwareNetworkSpecifier.Builder(discoverySession, peerHandle).build() - specifier.satisfiedBy(wifiAwareNetworkSpecifier) + specifier.canBeSatisfiedBy(wifiAwareNetworkSpecifier) } } diff --git a/tests/net/integration/AndroidManifest.xml b/tests/net/integration/AndroidManifest.xml index 09c0e4826075..f5a4234ede9e 100644 --- a/tests/net/integration/AndroidManifest.xml +++ b/tests/net/integration/AndroidManifest.xml @@ -16,50 +16,55 @@ * limitations under the License. */ --> + <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.server.net.integrationtests"> + package="com.android.server.net.integrationtests"> <!-- For ConnectivityService registerReceiverAsUser (receiving broadcasts) --> - <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/> <!-- PermissionMonitor sets network permissions for each user --> - <uses-permission android:name="android.permission.MANAGE_USERS" /> + <uses-permission android:name="android.permission.MANAGE_USERS"/> <!-- ConnectivityService sends notifications to BatteryStats --> - <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" /> + <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS"/> <!-- Reading network status --> - <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> - <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> - <uses-permission android:name="android.permission.NETWORK_FACTORY" /> - <uses-permission android:name="android.permission.NETWORK_STACK" /> - <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" /> - <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" /> + <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> + <uses-permission android:name="android.permission.NETWORK_FACTORY"/> + <!-- Obtain LinkProperties callbacks with sensitive fields --> + <uses-permission android:name="android.permission.NETWORK_SETTINGS" /> + <uses-permission android:name="android.permission.NETWORK_STACK"/> + <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY"/> + <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> <!-- Reading DeviceConfig flags --> - <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> + <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/> <application android:debuggable="true"> - <uses-library android:name="android.test.runner" /> + <uses-library android:name="android.test.runner"/> <!-- This manifest is merged with the base manifest of the real NetworkStack app. - Remove the NetworkStackService from the base (real) manifest, and replace with a test - service that responds to the same intent --> + Remove the NetworkStackService from the base (real) manifest, and replace with a test + service that responds to the same intent --> <service android:name=".TestNetworkStackService" - android:process="com.android.server.net.integrationtests.testnetworkstack"> + android:process="com.android.server.net.integrationtests.testnetworkstack" + android:exported="true"> <intent-filter> <action android:name="android.net.INetworkStackConnector.Test"/> </intent-filter> </service> <service android:name=".NetworkStackInstrumentationService" - android:process="com.android.server.net.integrationtests.testnetworkstack"> + android:process="com.android.server.net.integrationtests.testnetworkstack" + android:exported="true"> <intent-filter> <action android:name=".INetworkStackInstrumentation"/> </intent-filter> </service> <service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService" - android:process="com.android.server.net.integrationtests.testnetworkstack" - android:permission="android.permission.BIND_JOB_SERVICE"/> + android:process="com.android.server.net.integrationtests.testnetworkstack" + android:permission="android.permission.BIND_JOB_SERVICE"/> </application> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.server.net.integrationtests" - android:label="Frameworks Net Integration Tests" /> + android:targetPackage="com.android.server.net.integrationtests" + android:label="Frameworks Net Integration Tests"/> </manifest> diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt index c4801aab5c32..bc069e148b99 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt @@ -28,10 +28,13 @@ import android.net.INetd import android.net.INetworkPolicyManager import android.net.INetworkStatsService import android.net.LinkProperties +import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET +import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED import android.net.NetworkCapabilities.TRANSPORT_CELLULAR import android.net.NetworkRequest import android.net.TestNetworkStackClient +import android.net.Uri import android.net.metrics.IpConnectivityLog import android.os.ConditionVariable import android.os.IBinder @@ -64,6 +67,8 @@ import org.mockito.Mockito.spy import org.mockito.MockitoAnnotations import org.mockito.Spy import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull import kotlin.test.assertTrue import kotlin.test.fail @@ -110,6 +115,10 @@ class ConnectivityServiceIntegrationTest { private val bindingCondition = ConditionVariable(false) private val realContext get() = InstrumentationRegistry.getInstrumentation().context + private val httpProbeUrl get() = + realContext.getResources().getString(R.string.config_captive_portal_http_url) + private val httpsProbeUrl get() = + realContext.getResources().getString(R.string.config_captive_portal_https_url) private class InstrumentationServiceConnection : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { @@ -188,12 +197,8 @@ class ConnectivityServiceIntegrationTest { val testCallback = TestableNetworkCallback() cm.registerNetworkCallback(request, testCallback) - nsInstrumentation.addHttpResponse(HttpResponse( - "http://test.android.com", - responseCode = 204, contentLength = 42, redirectUrl = null)) - nsInstrumentation.addHttpResponse(HttpResponse( - "https://secure.test.android.com", - responseCode = 204, contentLength = 42, redirectUrl = null)) + nsInstrumentation.addHttpResponse(HttpResponse(httpProbeUrl, responseCode = 204)) + nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204)) val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, LinkProperties(), context) networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS) @@ -204,4 +209,52 @@ class ConnectivityServiceIntegrationTest { testCallback.expectAvailableThenValidatedCallbacks(na.network, TEST_TIMEOUT_MS) assertEquals(2, nsInstrumentation.getRequestUrls().size) } + + @Test + fun testCapportApi() { + val request = NetworkRequest.Builder() + .clearCapabilities() + .addCapability(NET_CAPABILITY_INTERNET) + .build() + val testCb = TestableNetworkCallback() + val apiUrl = "https://capport.android.com" + + cm.registerNetworkCallback(request, testCb) + nsInstrumentation.addHttpResponse(HttpResponse( + apiUrl, + """ + |{ + | "captive": true, + | "user-portal-url": "https://login.capport.android.com", + | "venue-info-url": "https://venueinfo.capport.android.com" + |} + """.trimMargin())) + + // Tests will fail if a non-mocked query is received: mock the HTTPS probe, but not the + // HTTP probe as it should not be sent. + // Even if the HTTPS probe succeeds, a portal should be detected as the API takes precedence + // in that case. + nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204)) + + val lp = LinkProperties() + lp.captivePortalApiUrl = Uri.parse(apiUrl) + val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, lp, context) + networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS) + + na.addCapability(NET_CAPABILITY_INTERNET) + na.connect() + + testCb.expectAvailableCallbacks(na.network, validated = false, tmt = TEST_TIMEOUT_MS) + + val capportData = testCb.expectLinkPropertiesThat(na, TEST_TIMEOUT_MS) { + it.captivePortalData != null + }.lp.captivePortalData + assertNotNull(capportData) + assertTrue(capportData.isCaptive) + assertEquals(Uri.parse("https://login.capport.android.com"), capportData.userPortalUrl) + assertEquals(Uri.parse("https://venueinfo.capport.android.com"), capportData.venueInfoUrl) + + val nc = testCb.expectCapabilitiesWith(NET_CAPABILITY_CAPTIVE_PORTAL, na, TEST_TIMEOUT_MS) + assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED)) + } }
\ No newline at end of file diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt b/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt index 45073d8df3f7..e2063138fef1 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt @@ -22,16 +22,21 @@ import android.os.Parcelable data class HttpResponse( val requestUrl: String, val responseCode: Int, - val contentLength: Long, - val redirectUrl: String? + val content: String = "", + val redirectUrl: String? = null ) : Parcelable { - constructor(p: Parcel): this(p.readString(), p.readInt(), p.readLong(), p.readString()) + constructor(p: Parcel): this(p.readString(), p.readInt(), p.readString(), p.readString()) + constructor(requestUrl: String, contentBody: String): this( + requestUrl, + responseCode = 200, + content = contentBody, + redirectUrl = null) override fun writeToParcel(dest: Parcel, flags: Int) { with(dest) { writeString(requestUrl) writeInt(responseCode) - writeLong(contentLength) + writeString(content) writeString(redirectUrl) } } diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt index 4827d2997d93..e807952cec11 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt @@ -65,6 +65,9 @@ class NetworkStackInstrumentationService : Service() { * * <p>For any subsequent HTTP/HTTPS query, the first response with a matching URL will be * used to mock the query response. + * + * <p>All requests that are expected to be sent must have a mock response: if an unexpected + * request is seen, the test will fail. */ override fun addHttpResponse(response: HttpResponse) { httpResponses.getValue(response.requestUrl).add(response) diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt index 8c2de4035d0b..a44ad1e05259 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt @@ -33,9 +33,11 @@ import com.android.server.net.integrationtests.NetworkStackInstrumentationServic import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock import org.mockito.Mockito.spy +import java.io.ByteArrayInputStream import java.net.HttpURLConnection import java.net.URL import java.net.URLConnection +import java.nio.charset.StandardCharsets private const val TEST_NETID = 42 @@ -71,11 +73,13 @@ class TestNetworkStackService : Service() { private inner class TestNetwork(netId: Int) : Network(netId) { override fun openConnection(url: URL): URLConnection { val response = InstrumentationConnector.processRequest(url) + val responseBytes = response.content.toByteArray(StandardCharsets.UTF_8) val connection = mock(HttpURLConnection::class.java) doReturn(response.responseCode).`when`(connection).responseCode - doReturn(response.contentLength).`when`(connection).contentLengthLong + doReturn(responseBytes.size.toLong()).`when`(connection).contentLengthLong doReturn(response.redirectUrl).`when`(connection).getHeaderField("location") + doReturn(ByteArrayInputStream(responseBytes)).`when`(connection).inputStream return connection } } diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java index d6bf334ee56a..d74a621842f9 100644 --- a/tests/net/java/android/net/ConnectivityManagerTest.java +++ b/tests/net/java/android/net/ConnectivityManagerTest.java @@ -36,6 +36,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; @@ -213,7 +214,7 @@ public class ConnectivityManagerTest { // register callback when(mService.requestNetwork( - any(), captor.capture(), anyInt(), any(), anyInt(), any())) + any(), captor.capture(), anyInt(), any(), anyInt(), any(), nullable(String.class))) .thenReturn(request); manager.requestNetwork(request, callback, handler); @@ -242,7 +243,7 @@ public class ConnectivityManagerTest { // register callback when(mService.requestNetwork( - any(), captor.capture(), anyInt(), any(), anyInt(), any())) + any(), captor.capture(), anyInt(), any(), anyInt(), any(), nullable(String.class))) .thenReturn(req1); manager.requestNetwork(req1, callback, handler); @@ -261,7 +262,7 @@ public class ConnectivityManagerTest { // callback can be registered again when(mService.requestNetwork( - any(), captor.capture(), anyInt(), any(), anyInt(), any())) + any(), captor.capture(), anyInt(), any(), anyInt(), any(), nullable(String.class))) .thenReturn(req2); manager.requestNetwork(req2, callback, handler); @@ -285,8 +286,8 @@ public class ConnectivityManagerTest { info.targetSdkVersion = VERSION_CODES.N_MR1 + 1; when(mCtx.getApplicationInfo()).thenReturn(info); - when(mService.requestNetwork(any(), any(), anyInt(), any(), anyInt(), any())) - .thenReturn(request); + when(mService.requestNetwork(any(), any(), anyInt(), any(), anyInt(), any(), + nullable(String.class))).thenReturn(request); Handler handler = new Handler(Looper.getMainLooper()); manager.requestNetwork(request, callback, handler); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 385005f90c3b..bc853749e294 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -3054,6 +3054,13 @@ public class ConnectivityServiceTest { assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar); } + /** + * @return the context's attribution tag + */ + private String getAttributionTag() { + return null; + } + @Test public void testInvalidNetworkSpecifier() { assertThrows(IllegalArgumentException.class, () -> { @@ -3066,7 +3073,8 @@ public class ConnectivityServiceTest { networkCapabilities.addTransportType(TRANSPORT_WIFI) .setNetworkSpecifier(new MatchAllNetworkSpecifier()); mService.requestNetwork(networkCapabilities, null, 0, null, - ConnectivityManager.TYPE_WIFI, mContext.getPackageName()); + ConnectivityManager.TYPE_WIFI, mContext.getPackageName(), + getAttributionTag()); }); class NonParcelableSpecifier extends NetworkSpecifier { diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt index 42d4cf3c382b..a10a3c81bc86 100644 --- a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt +++ b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt @@ -14,6 +14,11 @@ * limitations under the License. */ +// Don't warn about deprecated types anywhere in this test, because LegacyTypeTracker's very reason +// for existence is to power deprecated APIs. The annotation has to apply to the whole file because +// otherwise warnings will be generated by the imports of deprecated constants like TYPE_xxx. +@file:Suppress("DEPRECATION") + package com.android.server import android.net.ConnectivityManager.TYPE_ETHERNET diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index 39f849c340f7..5a29c2c96ba7 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -76,7 +76,6 @@ import com.android.server.pm.PackageList; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; @@ -88,7 +87,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Set; - @RunWith(AndroidJUnit4.class) @SmallTest public class PermissionMonitorTest { @@ -116,8 +114,8 @@ public class PermissionMonitorTest { @Mock private INetd mNetdService; @Mock private PackageManagerInternal mMockPmi; @Mock private UserManager mUserManager; + @Mock private PermissionMonitor.Dependencies mDeps; - private PackageManagerInternal.PackageListObserver mObserver; private PermissionMonitor mPermissionMonitor; @Before @@ -131,7 +129,7 @@ public class PermissionMonitorTest { new UserInfo(MOCK_USER2, "", 0), })); - mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService)); + mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps)); LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, mMockPmi); @@ -139,11 +137,7 @@ public class PermissionMonitorTest { /* observer */ null)); when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null); mPermissionMonitor.startMonitoring(); - - final ArgumentCaptor<PackageManagerInternal.PackageListObserver> observerCaptor = - ArgumentCaptor.forClass(PackageManagerInternal.PackageListObserver.class); - verify(mMockPmi).getPackageList(observerCaptor.capture()); - mObserver = observerCaptor.getValue(); + verify(mMockPmi).getPackageList(mPermissionMonitor); } private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid, @@ -290,14 +284,14 @@ public class PermissionMonitorTest { @Test public void testHasRestrictedNetworkPermissionSystemUid() { - doReturn(VERSION_P).when(mPermissionMonitor).getDeviceFirstSdkInt(); + doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt(); assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID)); assertTrue(hasRestrictedNetworkPermission( PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_INTERNAL)); assertTrue(hasRestrictedNetworkPermission( PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); - doReturn(VERSION_Q).when(mPermissionMonitor).getDeviceFirstSdkInt(); + doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt(); assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID)); assertFalse(hasRestrictedNetworkPermission( PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_INTERNAL)); @@ -450,13 +444,13 @@ public class PermissionMonitorTest { new int[]{MOCK_UID1}); // Remove MOCK_UID1, expect no permission left for all user. - mPermissionMonitor.onPackageRemoved(MOCK_UID1); - removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1); + mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); + removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1); mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1}); // Remove SYSTEM_PACKAGE1, expect permission downgrade. when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2}); - removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID); + removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_PACKAGE1, SYSTEM_UID); mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2}, new int[]{SYSTEM_UID}); @@ -465,7 +459,7 @@ public class PermissionMonitorTest { // Remove all packages, expect no permission left. when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{}); - removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_UID); + removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID); mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{SYSTEM_UID, MOCK_UID1}); @@ -501,7 +495,8 @@ public class PermissionMonitorTest { reset(mNetdService); // When MOCK_UID1 package is uninstalled and reinstalled, expect Netd to be updated - mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1)); + mPermissionMonitor.onPackageRemoved( + MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1)); verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1})); mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1)); verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"), @@ -545,7 +540,8 @@ public class PermissionMonitorTest { aryEq(new int[] {MOCK_UID1})); // Removed package should have its uid rules removed - mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1)); + mPermissionMonitor.onPackageRemoved( + MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1)); verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1})); } @@ -559,9 +555,9 @@ public class PermissionMonitorTest { } } - private void removePackageForUsers(int[] users, int uid) { + private void removePackageForUsers(int[] users, String packageName, int uid) { for (final int user : users) { - mPermissionMonitor.onPackageRemoved(UserHandle.getUid(user, uid)); + mPermissionMonitor.onPackageRemoved(packageName, UserHandle.getUid(user, uid)); } } @@ -647,7 +643,7 @@ public class PermissionMonitorTest { private PackageInfo addPackage(String packageName, int uid, String[] permissions) throws Exception { PackageInfo packageInfo = setPackagePermissions(packageName, uid, permissions); - mObserver.onPackageAdded(packageName, uid); + mPermissionMonitor.onPackageAdded(packageName, uid); return packageInfo; } @@ -678,7 +674,7 @@ public class PermissionMonitorTest { when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2); when(mPackageManager.getPackagesForUid(MOCK_UID1)) .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2}); - mObserver.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1); + mPermissionMonitor.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); } @@ -692,7 +688,7 @@ public class PermissionMonitorTest { | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{}); - mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); + mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1}); } @@ -705,7 +701,7 @@ public class PermissionMonitorTest { | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{}); - mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); + mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1}); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET}); @@ -719,10 +715,7 @@ public class PermissionMonitorTest { addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {}); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1}); - // When updating a package, the broadcast receiver gets two broadcasts (a remove and then an - // add), but the observer sees only one callback (an update). - setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET}); - mObserver.onPackageChanged(MOCK_PACKAGE1, MOCK_UID1); + addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET}); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1}); } @@ -740,7 +733,7 @@ public class PermissionMonitorTest { when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{ MOCK_PACKAGE2}); - mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); + mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1}); } diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index a1bb0d586916..1307a849f1eb 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -41,6 +41,7 @@ import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; +import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateMobileWithRatType; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; @@ -62,6 +63,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -71,6 +73,7 @@ import android.app.AlarmManager; import android.app.usage.NetworkStatsManager; import android.content.Context; import android.content.Intent; +import android.database.ContentObserver; import android.net.DataUsageRequest; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsSession; @@ -94,6 +97,7 @@ import android.os.Message; import android.os.Messenger; import android.os.PowerManager; import android.os.SimpleClock; +import android.provider.Settings; import android.telephony.TelephonyManager; import androidx.test.InstrumentationRegistry; @@ -173,6 +177,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { private NetworkStatsService mService; private INetworkStatsSession mSession; private INetworkManagementEventObserver mNetworkObserver; + private ContentObserver mContentObserver; + private Handler mHandler; private final Clock mClock = new SimpleClock(ZoneOffset.UTC) { @Override @@ -212,6 +218,12 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { mService.systemReady(); // Verify that system ready fetches realtime stats verify(mStatsFactory).readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL); + // Wait for posting onChange() event to handler thread and verify that when system ready, + // start monitoring data usage per RAT type because the settings value is mock as false + // by default in expectSettings(). + waitForIdle(); + verify(mNetworkStatsSubscriptionsMonitor).start(); + reset(mNetworkStatsSubscriptionsMonitor); mSession = mService.openSession(); assertNotNull("openSession() failed", mSession); @@ -233,11 +245,19 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { @Override public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor( - @NonNull Context context, @NonNull Executor executor, + @NonNull Context context, @NonNull Looper looper, @NonNull Executor executor, @NonNull NetworkStatsService service) { return mNetworkStatsSubscriptionsMonitor; } + + @Override + public ContentObserver makeContentObserver(Handler handler, + NetworkStatsSettings settings, NetworkStatsSubscriptionsMonitor monitor) { + mHandler = handler; + return mContentObserver = super.makeContentObserver(handler, settings, monitor); + } + }; } @@ -1191,6 +1211,99 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { provider.expectOnSetAlert(MB_IN_BYTES); } + private void setCombineSubtypeEnabled(boolean enable) { + when(mSettings.getCombineSubtypeEnabled()).thenReturn(enable); + mHandler.post(() -> mContentObserver.onChange(false, Settings.Global + .getUriFor(Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED))); + waitForIdle(); + if (enable) { + verify(mNetworkStatsSubscriptionsMonitor).stop(); + } else { + verify(mNetworkStatsSubscriptionsMonitor).start(); + } + } + + @Test + public void testDynamicWatchForNetworkRatTypeChanges() throws Exception { + // Build 3G template, type unknown template to get stats while network type is unknown + // and type all template to get the sum of all network type stats. + final NetworkTemplate template3g = + buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS); + final NetworkTemplate templateUnknown = + buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN); + final NetworkTemplate templateAll = + buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL); + final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)}; + + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(buildEmptyStats()); + + // 3G network comes online. + setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS); + mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + new VpnInfo[0]); + + // Create some traffic. + incrementCurrentTime(MINUTE_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, + 12L, 18L, 14L, 1L, 0L))); + forcePollAndWaitForIdle(); + + // Since CombineSubtypeEnabled is false by default in unit test, the generated traffic + // will be split by RAT type. Verify 3G templates gets stats, while template with unknown + // RAT type gets nothing, and template with NETWORK_TYPE_ALL gets all stats. + assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0); + assertUidTotal(templateUnknown, UID_RED, 0L, 0L, 0L, 0L, 0); + assertUidTotal(templateAll, UID_RED, 12L, 18L, 14L, 1L, 0); + + // Stop monitoring data usage per RAT type changes NetworkStatsService records data + // to {@link TelephonyManager#NETWORK_TYPE_UNKNOWN}. + setCombineSubtypeEnabled(true); + + // Call handleOnCollapsedRatTypeChanged manually to simulate the callback fired + // when stopping monitor, this is needed by NetworkStatsService to trigger updateIfaces. + mService.handleOnCollapsedRatTypeChanged(); + HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT); + // Create some traffic. + incrementCurrentTime(MINUTE_IN_MILLIS); + // Append more traffic on existing snapshot. + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, + 12L + 4L, 18L + 4L, 14L + 3L, 1L + 1L, 0L)) + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, + 35L, 29L, 7L, 11L, 1L))); + forcePollAndWaitForIdle(); + + // Verify 3G counters do not increase, while template with unknown RAT type gets new + // traffic and template with NETWORK_TYPE_ALL gets all stats. + assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0); + assertUidTotal(templateUnknown, UID_RED, 4L + 35L, 4L + 29L, 3L + 7L, 1L + 11L, 1); + assertUidTotal(templateAll, UID_RED, 16L + 35L, 22L + 29L, 17L + 7L, 2L + 11L, 1); + + // Start monitoring data usage per RAT type changes and NetworkStatsService records data + // by a granular subtype representative of the actual subtype + setCombineSubtypeEnabled(false); + + mService.handleOnCollapsedRatTypeChanged(); + HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT); + // Create some traffic. + incrementCurrentTime(MINUTE_IN_MILLIS); + // Append more traffic on existing snapshot. + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, + 22L, 26L, 19L, 5L, 0L)) + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, + 35L, 29L, 7L, 11L, 1L))); + forcePollAndWaitForIdle(); + + // Verify traffic is split by RAT type, no increase on template with unknown RAT type + // and template with NETWORK_TYPE_ALL gets all stats. + assertUidTotal(template3g, UID_RED, 6L + 12L , 4L + 18L, 2L + 14L, 3L + 1L, 0); + assertUidTotal(templateUnknown, UID_RED, 4L + 35L, 4L + 29L, 3L + 7L, 1L + 11L, 1); + assertUidTotal(templateAll, UID_RED, 22L + 35L, 26L + 29L, 19L + 7L, 5L + 11L, 1); + } + private static File getBaseDir(File statsDir) { File baseDir = new File(statsDir, "netstats"); baseDir.mkdirs(); @@ -1403,6 +1516,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { private void forcePollAndWaitForIdle() { mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); + waitForIdle(); + } + + private void waitForIdle() { HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT); } diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java index 058856dcd6fb..9adbf21a1219 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java @@ -17,6 +17,8 @@ package com.android.server.net; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.eq; @@ -29,14 +31,14 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.content.Context; -import android.os.Looper; +import android.os.test.TestLooper; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import com.android.internal.util.CollectionUtils; -import com.android.server.net.NetworkStatsSubscriptionsMonitor.Delegate; import com.android.server.net.NetworkStatsSubscriptionsMonitor.RatTypeListener; import org.junit.Before; @@ -61,23 +63,19 @@ public final class NetworkStatsSubscriptionsMonitorTest { private static final String TEST_IMSI3 = "466929999999999"; @Mock private Context mContext; - @Mock private PhoneStateListener mPhoneStateListener; @Mock private SubscriptionManager mSubscriptionManager; @Mock private TelephonyManager mTelephonyManager; - @Mock private Delegate mDelegate; + @Mock private NetworkStatsSubscriptionsMonitor.Delegate mDelegate; private final List<Integer> mTestSubList = new ArrayList<>(); private final Executor mExecutor = Executors.newSingleThreadExecutor(); private NetworkStatsSubscriptionsMonitor mMonitor; + private TestLooper mTestLooper = new TestLooper(); @Before public void setUp() { MockitoAnnotations.initMocks(this); - if (Looper.myLooper() == null) { - Looper.prepare(); - } - when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager); when(mContext.getSystemService(eq(Context.TELEPHONY_SUBSCRIPTION_SERVICE))) @@ -85,7 +83,8 @@ public final class NetworkStatsSubscriptionsMonitorTest { when(mContext.getSystemService(eq(Context.TELEPHONY_SERVICE))) .thenReturn(mTelephonyManager); - mMonitor = new NetworkStatsSubscriptionsMonitor(mContext, mExecutor, mDelegate); + mMonitor = new NetworkStatsSubscriptionsMonitor(mContext, mTestLooper.getLooper(), + mExecutor, mDelegate); } @Test @@ -117,16 +116,18 @@ public final class NetworkStatsSubscriptionsMonitorTest { when(serviceState.getDataNetworkType()).thenReturn(type); final RatTypeListener match = CollectionUtils .find(listeners, it -> it.getSubId() == subId); - if (match != null) { - match.onServiceStateChanged(serviceState); + if (match == null) { + fail("Could not find listener with subId: " + subId); } + match.onServiceStateChanged(serviceState); } private void addTestSub(int subId, String subscriberId) { // add SubId to TestSubList. - if (!mTestSubList.contains(subId)) { - mTestSubList.add(subId); - } + if (mTestSubList.contains(subId)) fail("The subscriber list already contains this ID"); + + mTestSubList.add(subId); + final int[] subList = convertArrayListToIntArray(mTestSubList); when(mSubscriptionManager.getCompleteActiveSubscriptionIdList()).thenReturn(subList); when(mTelephonyManager.getSubscriberId(subId)).thenReturn(subscriberId); @@ -215,4 +216,53 @@ public final class NetworkStatsSubscriptionsMonitorTest { verify(mTelephonyManager, times(2)).listen(any(), eq(PhoneStateListener.LISTEN_NONE)); assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); } + + @Test + public void test5g() { + mMonitor.start(); + // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback + // before changing RAT type. Also capture listener for later use. + addTestSub(TEST_SUBID1, TEST_IMSI1); + assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor = + ArgumentCaptor.forClass(RatTypeListener.class); + verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(), + eq(PhoneStateListener.LISTEN_SERVICE_STATE)); + final RatTypeListener listener = CollectionUtils + .find(ratTypeListenerCaptor.getAllValues(), it -> it.getSubId() == TEST_SUBID1); + assertNotNull(listener); + + // Set RAT type to 5G NSA (non-standalone) mode, verify the monitor outputs NETWORK_TYPE_NR. + final ServiceState serviceState = mock(ServiceState.class); + when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE); + when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED); + listener.onServiceStateChanged(serviceState); + assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR); + reset(mDelegate); + + // Set RAT type to LTE without NR connected, the RAT type should be downgraded to LTE. + when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE); + listener.onServiceStateChanged(serviceState); + assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE); + reset(mDelegate); + + // Verify NR connected with other RAT type does not take effect. + when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_UMTS); + when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED); + listener.onServiceStateChanged(serviceState); + assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS); + reset(mDelegate); + + // Set RAT type to 5G standalone mode, the RAT type should be NR. + setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1, + TelephonyManager.NETWORK_TYPE_NR); + assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR); + reset(mDelegate); + + // Set NR state to none in standalone mode does not change anything. + when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_NR); + when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE); + listener.onServiceStateChanged(serviceState); + assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR); + } } |