summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/CaptivePortalLogin/res/values-bs/strings.xml24
-rw-r--r--packages/CaptivePortalLogin/res/values-de/strings.xml24
-rw-r--r--packages/ExtServices/Android.bp37
-rw-r--r--packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java566
-rw-r--r--packages/NetworkStack/tests/lib/Android.bp26
-rw-r--r--packages/NetworkStack/tests/lib/src/com/android/testutils/HandlerUtils.kt50
-rw-r--r--packages/NetworkStack/tests/unit/Android.bp102
-rw-r--r--packages/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java1154
8 files changed, 0 insertions, 1983 deletions
diff --git a/packages/CaptivePortalLogin/res/values-bs/strings.xml b/packages/CaptivePortalLogin/res/values-bs/strings.xml
deleted file mode 100644
index 83b5067235e2..000000000000
--- a/packages/CaptivePortalLogin/res/values-bs/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="5934709770924185752">"Prijava na zaštitnom portalu"</string>
- <string name="action_use_network" msgid="6076184727448466030">"Koristi ovu mrežu kakva jeste"</string>
- <string name="action_do_not_use_network" msgid="4577366536956516683">"Ne koristi ovu mrežu"</string>
- <string name="action_bar_label" msgid="917235635415966620">"Prijava na mrežu"</string>
- <string name="action_bar_title" msgid="5645564790486983117">"Prijava na %1$s"</string>
- <string name="ssl_error_warning" msgid="6653188881418638872">"Mreža kojoj pokušavate pristupiti ima sigurnosnih problema."</string>
- <string name="ssl_error_example" msgid="647898534624078900">"Naprimjer, stranica za prijavu možda ne pripada prikazanoj organizaciji."</string>
- <string name="ssl_error_continue" msgid="6492718244923937110">"Ipak nastavi preko preglednika"</string>
- <string name="ssl_error_untrusted" msgid="1496280318271264520">"Ova potvrda ne potiče iz pouzdanog izvora."</string>
- <string name="ssl_error_mismatch" msgid="3060364165934822383">"Naziv web lokacije se ne podudara s nazivom na potvrdi."</string>
- <string name="ssl_error_expired" msgid="1501588340716182495">"Ova potvrda je istekla."</string>
- <string name="ssl_error_not_yet_valid" msgid="8648649030525886924">"Ova potvrda još uvijek nije važeća."</string>
- <string name="ssl_error_date_invalid" msgid="88425990680059223">"Ova potvrda sadrži nevažeći datum."</string>
- <string name="ssl_error_invalid" msgid="2540546515565633432">"Ova potvrda je nevažeća."</string>
- <string name="ssl_error_unknown" msgid="4405203446079465859">"Nepoznata greška potvrde."</string>
- <string name="ssl_security_warning_title" msgid="8768539813847504404">"Sigurnosno upozorenje"</string>
- <string name="ssl_error_view_certificate" msgid="5722652540168339333">"Prikaži potvrdu"</string>
- <string name="ok" msgid="2817931639040794018">"Uredu"</string>
- <string name="page_info_address" msgid="1261481517455692363">"Adresa:"</string>
- <string name="page_info" msgid="4416941086705172545">"Informacije o stranici"</string>
-</resources>
diff --git a/packages/CaptivePortalLogin/res/values-de/strings.xml b/packages/CaptivePortalLogin/res/values-de/strings.xml
deleted file mode 100644
index 4276bf9c2be9..000000000000
--- a/packages/CaptivePortalLogin/res/values-de/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
- <string name="action_use_network" msgid="6076184727448466030">"Netzwerk im Istzustand verwenden"</string>
- <string name="action_do_not_use_network" msgid="4577366536956516683">"Netzwerk nicht verwenden"</string>
- <string name="action_bar_label" msgid="917235635415966620">"Im Netzwerk anmelden"</string>
- <string name="action_bar_title" msgid="5645564790486983117">"In %1$s anmelden"</string>
- <string name="ssl_error_warning" msgid="6653188881418638872">"Im Netzwerk, zu dem du eine Verbindung herstellen möchtest, liegen Sicherheitsprobleme vor."</string>
- <string name="ssl_error_example" msgid="647898534624078900">"Beispiel: Die Log-in-Seite gehört eventuell nicht zur angezeigten Organisation."</string>
- <string name="ssl_error_continue" msgid="6492718244923937110">"Trotzdem in einem Browser fortfahren"</string>
- <string name="ssl_error_untrusted" msgid="1496280318271264520">"Dieses Zertifikat stammt nicht von einer vertrauenswürdigen Stelle."</string>
- <string name="ssl_error_mismatch" msgid="3060364165934822383">"Der Name der Website stimmt nicht mit dem Namen auf dem Zertifikat überein."</string>
- <string name="ssl_error_expired" msgid="1501588340716182495">"Dieses Zertifikat ist abgelaufen."</string>
- <string name="ssl_error_not_yet_valid" msgid="8648649030525886924">"Dieses Zertifikat ist noch nicht gültig."</string>
- <string name="ssl_error_date_invalid" msgid="88425990680059223">"Dieses Zertifikat hat ein ungültiges Datum."</string>
- <string name="ssl_error_invalid" msgid="2540546515565633432">"Dieses Zertifikat ist ungültig."</string>
- <string name="ssl_error_unknown" msgid="4405203446079465859">"Unbekannter Zertifikatfehler."</string>
- <string name="ssl_security_warning_title" msgid="8768539813847504404">"Sicherheitswarnung"</string>
- <string name="ssl_error_view_certificate" msgid="5722652540168339333">"Zertifikat ansehen"</string>
- <string name="ok" msgid="2817931639040794018">"Ok"</string>
- <string name="page_info_address" msgid="1261481517455692363">"Adresse:"</string>
- <string name="page_info" msgid="4416941086705172545">"Seiteninformationen"</string>
-</resources>
diff --git a/packages/ExtServices/Android.bp b/packages/ExtServices/Android.bp
deleted file mode 100644
index 57306008bf1a..000000000000
--- a/packages/ExtServices/Android.bp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2016 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_library {
- name: "ExtServices-core",
- srcs: [
- "src/**/*.java",
- ],
- resource_dirs: [
- "res",
- ],
-
- manifest: "AndroidManifest.xml",
-}
-
-android_app {
- name: "ExtServices",
- srcs: ["src/**/*.java"],
- platform_apis: true,
- certificate: "platform",
- optimize: {
- proguard_flags_files: ["proguard.proguard"],
- },
- privileged: true,
- min_sdk_version: "28",
-}
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
deleted file mode 100644
index 52b722566459..000000000000
--- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
+++ /dev/null
@@ -1,566 +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.
- */
-package android.ext.services.notification;
-
-import static com.google.common.truth.Truth.assertAbout;
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Person;
-import android.app.RemoteInput;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.IPackageManager;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.os.Process;
-import android.service.notification.NotificationAssistantService;
-import android.service.notification.StatusBarNotification;
-import android.view.textclassifier.ConversationAction;
-import android.view.textclassifier.ConversationActions;
-import android.view.textclassifier.TextClassificationManager;
-import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextClassifierEvent;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.common.truth.FailureMetadata;
-import com.google.common.truth.Subject;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.time.Instant;
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-import javax.annotation.Nullable;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-@RunWith(AndroidJUnit4.class)
-public class SmartActionsHelperTest {
- private static final String RESULT_ID = "id";
- private static final float SCORE = 0.7f;
- private static final CharSequence SMART_REPLY = "Home";
- private static final ConversationAction REPLY_ACTION =
- new ConversationAction.Builder(ConversationAction.TYPE_TEXT_REPLY)
- .setTextReply(SMART_REPLY)
- .setConfidenceScore(SCORE)
- .build();
- private static final String MESSAGE = "Where are you?";
-
- @Mock
- IPackageManager mIPackageManager;
- @Mock
- private TextClassifier mTextClassifier;
- private StatusBarNotification mStatusBarNotification;
- @Mock
- private SmsHelper mSmsHelper;
-
- private SmartActionsHelper mSmartActionsHelper;
- private Context mContext;
- private Notification.Builder mNotificationBuilder;
- private AssistantSettings mSettings;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mContext = InstrumentationRegistry.getTargetContext();
-
- mContext.getSystemService(TextClassificationManager.class)
- .setTextClassifier(mTextClassifier);
- when(mTextClassifier.suggestConversationActions(any(ConversationActions.Request.class)))
- .thenReturn(new ConversationActions(Arrays.asList(REPLY_ACTION), RESULT_ID));
-
- mNotificationBuilder = new Notification.Builder(mContext, "channel");
- mSettings = AssistantSettings.createForTesting(
- null, null, Process.myUserHandle().getIdentifier(), null);
- mSettings.mGenerateActions = true;
- mSettings.mGenerateReplies = true;
- mSmartActionsHelper = new SmartActionsHelper(mContext, mSettings);
- }
-
- private void setStatusBarNotification(Notification n) {
- mStatusBarNotification = new StatusBarNotification("random.app", "random.app", 0,
- "tag", Process.myUid(), Process.myPid(), n, Process.myUserHandle(), null, 0);
- }
-
- @Test
- public void testSuggest_notMessageNotification() {
- Notification notification = mNotificationBuilder.setContentText(MESSAGE).build();
- setStatusBarNotification(notification);
-
- mSmartActionsHelper.suggest(createNotificationEntry());
-
- verify(mTextClassifier, never())
- .suggestConversationActions(any(ConversationActions.Request.class));
- }
-
- @Test
- public void testSuggest_noInlineReply() {
- Notification notification =
- mNotificationBuilder
- .setContentText(MESSAGE)
- .setCategory(Notification.CATEGORY_MESSAGE)
- .build();
- setStatusBarNotification(notification);
-
- ConversationActions.Request request = runSuggestAndCaptureRequest();
-
- // actions are enabled, but replies are not.
- assertThat(
- request.getTypeConfig().resolveEntityListModifications(
- Arrays.asList(ConversationAction.TYPE_TEXT_REPLY,
- ConversationAction.TYPE_OPEN_URL)))
- .containsExactly(ConversationAction.TYPE_OPEN_URL);
- }
-
- @Test
- public void testSuggest_settingsOff() {
- mSettings.mGenerateActions = false;
- mSettings.mGenerateReplies = false;
- Notification notification = createMessageNotification();
- setStatusBarNotification(notification);
-
- mSmartActionsHelper.suggest(createNotificationEntry());
-
- verify(mTextClassifier, never())
- .suggestConversationActions(any(ConversationActions.Request.class));
- }
-
- @Test
- public void testSuggest_settings_repliesOnActionsOff() {
- mSettings.mGenerateReplies = true;
- mSettings.mGenerateActions = false;
- Notification notification = createMessageNotification();
- setStatusBarNotification(notification);
-
- ConversationActions.Request request = runSuggestAndCaptureRequest();
-
- // replies are enabled, but actions are not.
- assertThat(
- request.getTypeConfig().resolveEntityListModifications(
- Arrays.asList(ConversationAction.TYPE_TEXT_REPLY,
- ConversationAction.TYPE_OPEN_URL)))
- .containsExactly(ConversationAction.TYPE_TEXT_REPLY);
- }
-
- @Test
- public void testSuggest_settings_repliesOffActionsOn() {
- mSettings.mGenerateReplies = false;
- mSettings.mGenerateActions = true;
- Notification notification = createMessageNotification();
- setStatusBarNotification(notification);
-
- ConversationActions.Request request = runSuggestAndCaptureRequest();
-
- // actions are enabled, but replies are not.
- assertThat(
- request.getTypeConfig().resolveEntityListModifications(
- Arrays.asList(ConversationAction.TYPE_TEXT_REPLY,
- ConversationAction.TYPE_OPEN_URL)))
- .containsExactly(ConversationAction.TYPE_OPEN_URL);
- }
-
-
- @Test
- public void testSuggest_nonMessageStyleMessageNotification() {
- Notification notification = createMessageNotification();
- setStatusBarNotification(notification);
-
- List<ConversationActions.Message> messages =
- runSuggestAndCaptureRequest().getConversation();
-
- assertThat(messages).hasSize(1);
- MessageSubject.assertThat(messages.get(0)).hasText(MESSAGE);
- ArgumentCaptor<TextClassifierEvent> argumentCaptor =
- ArgumentCaptor.forClass(TextClassifierEvent.class);
- verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
- TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
- assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_ACTIONS_GENERATED);
- assertThat(textClassifierEvent.getEntityTypes()).asList()
- .containsExactly(ConversationAction.TYPE_TEXT_REPLY);
- }
-
- @Test
- public void testSuggest_messageStyle() {
- Person me = new Person.Builder().setName("Me").build();
- Person userA = new Person.Builder().setName("A").build();
- Person userB = new Person.Builder().setName("B").build();
- Notification.MessagingStyle style =
- new Notification.MessagingStyle(me)
- .addMessage("firstMessage", 1000, (Person) null)
- .addMessage("secondMessage", 2000, me)
- .addMessage("thirdMessage", 3000, userA)
- .addMessage("fourthMessage", 4000, userB);
- Notification notification =
- mNotificationBuilder
- .setContentText("You have three new messages")
- .setStyle(style)
- .setActions(createReplyAction())
- .build();
- setStatusBarNotification(notification);
-
- List<ConversationActions.Message> messages =
- runSuggestAndCaptureRequest().getConversation();
- assertThat(messages).hasSize(4);
-
- ConversationActions.Message firstMessage = messages.get(0);
- MessageSubject.assertThat(firstMessage).hasText("firstMessage");
- MessageSubject.assertThat(firstMessage)
- .hasPerson(ConversationActions.Message.PERSON_USER_SELF);
- MessageSubject.assertThat(firstMessage)
- .hasReferenceTime(createZonedDateTimeFromMsUtc(1000));
-
- ConversationActions.Message secondMessage = messages.get(1);
- MessageSubject.assertThat(secondMessage).hasText("secondMessage");
- MessageSubject.assertThat(secondMessage)
- .hasPerson(ConversationActions.Message.PERSON_USER_SELF);
- MessageSubject.assertThat(secondMessage)
- .hasReferenceTime(createZonedDateTimeFromMsUtc(2000));
-
- ConversationActions.Message thirdMessage = messages.get(2);
- MessageSubject.assertThat(thirdMessage).hasText("thirdMessage");
- MessageSubject.assertThat(thirdMessage).hasPerson(userA);
- MessageSubject.assertThat(thirdMessage)
- .hasReferenceTime(createZonedDateTimeFromMsUtc(3000));
-
- ConversationActions.Message fourthMessage = messages.get(3);
- MessageSubject.assertThat(fourthMessage).hasText("fourthMessage");
- MessageSubject.assertThat(fourthMessage).hasPerson(userB);
- MessageSubject.assertThat(fourthMessage)
- .hasReferenceTime(createZonedDateTimeFromMsUtc(4000));
-
- ArgumentCaptor<TextClassifierEvent> argumentCaptor =
- ArgumentCaptor.forClass(TextClassifierEvent.class);
- verify(mTextClassifier).onTextClassifierEvent(argumentCaptor.capture());
- TextClassifierEvent textClassifierEvent = argumentCaptor.getValue();
- assertTextClassifierEvent(textClassifierEvent, TextClassifierEvent.TYPE_ACTIONS_GENERATED);
- assertThat(textClassifierEvent.getEntityTypes()).asList()
- .containsExactly(ConversationAction.TYPE_TEXT_REPLY);
- }
-
- @Test
- public void testSuggest_lastMessageLocalUser() {
- Person me = new Person.Builder().setName("Me").build();
- Person userA = new Person.Builder().setName("A").build();
- Notification.MessagingStyle style =
- new Notification.MessagingStyle(me)
- .addMessage("firstMessage", 1000, userA)
- .addMessage("secondMessage", 2000, me);
- Notification notification =
- mNotificationBuilder
- .setContentText("You have two new messages")
- .setStyle(style)
- .setActions(createReplyAction())
- .build();
- setStatusBarNotification(notification);
-
- mSmartActionsHelper.suggest(createNotificationEntry());
-
- verify(mTextClassifier, never())
- .suggestConversationActions(any(ConversationActions.Request.class));
- }
-
- @Test
- public void testSuggest_messageStyle_noPerson() {
- Person me = new Person.Builder().setName("Me").build();
- Notification.MessagingStyle style =
- new Notification.MessagingStyle(me).addMessage("message", 1000, (Person) null);
- Notification notification =
- mNotificationBuilder
- .setContentText("You have one new message")
- .setStyle(style)
- .setActions(createReplyAction())
- .build();
- setStatusBarNotification(notification);
-
- mSmartActionsHelper.suggest(createNotificationEntry());
-
- verify(mTextClassifier, never())
- .suggestConversationActions(any(ConversationActions.Request.class));
- }
-
- @Test
- public void testOnSuggestedReplySent() {
- Notification notification = createMessageNotification();
- setStatusBarNotification(notification);
-
- mSmartActionsHelper.suggest(createNotificationEntry());
- mSmartActionsHelper.onSuggestedReplySent(mStatusBarNotification.getKey(), SMART_REPLY,
- NotificationAssistantService.SOURCE_FROM_ASSISTANT);
-
- ArgumentCaptor<TextClassifierEvent> argumentCaptor =
- ArgumentCaptor.forClass(TextClassifierEvent.class);
- verify(mTextClassifier, times(2)).onTextClassifierEvent(argumentCaptor.capture());
- List<TextClassifierEvent> events = argumentCaptor.getAllValues();
- assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED);
- assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_SMART_ACTION);
- float[] scores = events.get(1).getScores();
- assertThat(scores).hasLength(1);
- assertThat(scores[0]).isEqualTo(SCORE);
- }
-
- @Test
- public void testOnSuggestedReplySent_anotherNotification() {
- Notification notification = createMessageNotification();
- setStatusBarNotification(notification);
-
- mSmartActionsHelper.suggest(createNotificationEntry());
- mSmartActionsHelper.onSuggestedReplySent(
- "something_else", MESSAGE, NotificationAssistantService.SOURCE_FROM_ASSISTANT);
-
- verify(mTextClassifier, never()).onTextClassifierEvent(
- argThat(new TextClassifierEventMatcher(TextClassifierEvent.TYPE_SMART_ACTION)));
- }
-
- @Test
- public void testOnSuggestedReplySent_missingResultId() {
- when(mTextClassifier.suggestConversationActions(any(ConversationActions.Request.class)))
- .thenReturn(new ConversationActions(Collections.singletonList(REPLY_ACTION), null));
- Notification notification = createMessageNotification();
- setStatusBarNotification(notification);
-
- mSmartActionsHelper.suggest(createNotificationEntry());
- mSmartActionsHelper.onSuggestedReplySent(mStatusBarNotification.getKey(), SMART_REPLY,
- NotificationAssistantService.SOURCE_FROM_ASSISTANT);
-
- verify(mTextClassifier, never()).onTextClassifierEvent(any(TextClassifierEvent.class));
- }
-
- @Test
- public void testOnNotificationDirectReply() {
- Notification notification = createMessageNotification();
- setStatusBarNotification(notification);
-
- mSmartActionsHelper.suggest(createNotificationEntry());
- mSmartActionsHelper.onNotificationDirectReplied(mStatusBarNotification.getKey());
-
- ArgumentCaptor<TextClassifierEvent> argumentCaptor =
- ArgumentCaptor.forClass(TextClassifierEvent.class);
- verify(mTextClassifier, times(2)).onTextClassifierEvent(argumentCaptor.capture());
- List<TextClassifierEvent> events = argumentCaptor.getAllValues();
- assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED);
- assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_MANUAL_REPLY);
- }
-
- @Test
- public void testOnNotificationExpansionChanged() {
- Notification notification = createMessageNotification();
- setStatusBarNotification(notification);
-
- mSmartActionsHelper.suggest(createNotificationEntry());
- mSmartActionsHelper.onNotificationExpansionChanged(createNotificationEntry(), true);
-
- ArgumentCaptor<TextClassifierEvent> argumentCaptor =
- ArgumentCaptor.forClass(TextClassifierEvent.class);
- verify(mTextClassifier, times(2)).onTextClassifierEvent(argumentCaptor.capture());
- List<TextClassifierEvent> events = argumentCaptor.getAllValues();
- assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED);
- assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_ACTIONS_SHOWN);
- }
-
- @Test
- public void testOnNotificationsSeen_notExpanded() {
- Notification notification = createMessageNotification();
- setStatusBarNotification(notification);
-
- mSmartActionsHelper.suggest(createNotificationEntry());
- mSmartActionsHelper.onNotificationExpansionChanged(createNotificationEntry(), false);
-
- verify(mTextClassifier, never()).onTextClassifierEvent(
- argThat(new TextClassifierEventMatcher(TextClassifierEvent.TYPE_ACTIONS_SHOWN)));
- }
-
- @Test
- public void testOnNotifications_expanded() {
- Notification notification = createMessageNotification();
- setStatusBarNotification(notification);
-
- mSmartActionsHelper.suggest(createNotificationEntry());
- mSmartActionsHelper.onNotificationExpansionChanged(createNotificationEntry(), true);
-
- ArgumentCaptor<TextClassifierEvent> argumentCaptor =
- ArgumentCaptor.forClass(TextClassifierEvent.class);
- verify(mTextClassifier, times(2)).onTextClassifierEvent(argumentCaptor.capture());
- List<TextClassifierEvent> events = argumentCaptor.getAllValues();
- assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED);
- assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_ACTIONS_SHOWN);
- }
-
- @Test
- public void testCopyAction() {
- Bundle extras = new Bundle();
- Bundle entitiesExtras = new Bundle();
- entitiesExtras.putString(SmartActionsHelper.KEY_TEXT, "12345");
- extras.putParcelable(SmartActionsHelper.ENTITIES_EXTRAS, entitiesExtras);
- ConversationAction conversationAction =
- new ConversationAction.Builder(ConversationAction.TYPE_COPY)
- .setExtras(extras)
- .build();
- when(mTextClassifier.suggestConversationActions(any(ConversationActions.Request.class)))
- .thenReturn(
- new ConversationActions(
- Collections.singletonList(conversationAction), null));
-
- Notification notification = createMessageNotification();
- setStatusBarNotification(notification);
- SmartActionsHelper.SmartSuggestions suggestions =
- mSmartActionsHelper.suggest(createNotificationEntry());
-
- assertThat(suggestions.actions).hasSize(1);
- Notification.Action action = suggestions.actions.get(0);
- assertThat(action.title).isEqualTo("12345");
- }
-
- private ZonedDateTime createZonedDateTimeFromMsUtc(long msUtc) {
- return ZonedDateTime.ofInstant(Instant.ofEpochMilli(msUtc), ZoneOffset.systemDefault());
- }
-
- private ConversationActions.Request runSuggestAndCaptureRequest() {
- mSmartActionsHelper.suggest(createNotificationEntry());
-
- ArgumentCaptor<ConversationActions.Request> argumentCaptor =
- ArgumentCaptor.forClass(ConversationActions.Request.class);
- verify(mTextClassifier).suggestConversationActions(argumentCaptor.capture());
- return argumentCaptor.getValue();
- }
-
- private Notification.Action createReplyAction() {
- PendingIntent pendingIntent =
- PendingIntent.getActivity(mContext, 0, new Intent(mContext, this.getClass()), 0);
- RemoteInput remoteInput = new RemoteInput.Builder("result")
- .setAllowFreeFormInput(true)
- .build();
- return new Notification.Action.Builder(
- Icon.createWithResource(mContext.getResources(),
- android.R.drawable.stat_sys_warning),
- "Reply", pendingIntent)
- .addRemoteInput(remoteInput)
- .build();
- }
-
- private NotificationEntry createNotificationEntry() {
- NotificationChannel channel =
- new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
- return new NotificationEntry(
- mContext, mIPackageManager, mStatusBarNotification, channel, mSmsHelper);
- }
-
- private Notification createMessageNotification() {
- return mNotificationBuilder
- .setContentText(MESSAGE)
- .setCategory(Notification.CATEGORY_MESSAGE)
- .setActions(createReplyAction())
- .build();
- }
-
- private void assertTextClassifierEvent(
- TextClassifierEvent textClassifierEvent, int expectedEventType) {
- assertThat(textClassifierEvent.getEventCategory())
- .isEqualTo(TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS);
- assertThat(textClassifierEvent.getEventContext().getPackageName())
- .isEqualTo(InstrumentationRegistry.getTargetContext().getPackageName());
- assertThat(textClassifierEvent.getEventContext().getWidgetType())
- .isEqualTo(TextClassifier.WIDGET_TYPE_NOTIFICATION);
- assertThat(textClassifierEvent.getEventType()).isEqualTo(expectedEventType);
- }
-
- private static final class MessageSubject
- extends Subject<MessageSubject, ConversationActions.Message> {
-
- private static final Subject.Factory<MessageSubject, ConversationActions.Message> FACTORY =
- new Subject.Factory<MessageSubject, ConversationActions.Message>() {
- @Override
- public MessageSubject createSubject(
- @NonNull FailureMetadata failureMetadata,
- @NonNull ConversationActions.Message subject) {
- return new MessageSubject(failureMetadata, subject);
- }
- };
-
- private MessageSubject(
- FailureMetadata failureMetadata, @Nullable ConversationActions.Message subject) {
- super(failureMetadata, subject);
- }
-
- private void hasText(String text) {
- if (!Objects.equals(text, getSubject().getText().toString())) {
- failWithBadResults("has text", text, "has", getSubject().getText());
- }
- }
-
- private void hasPerson(Person person) {
- if (!Objects.equals(person, getSubject().getAuthor())) {
- failWithBadResults("has author", person, "has", getSubject().getAuthor());
- }
- }
-
- private void hasReferenceTime(ZonedDateTime referenceTime) {
- if (!Objects.equals(referenceTime, getSubject().getReferenceTime())) {
- failWithBadResults(
- "has reference time",
- referenceTime,
- "has",
- getSubject().getReferenceTime());
- }
- }
-
- private static MessageSubject assertThat(ConversationActions.Message message) {
- return assertAbout(FACTORY).that(message);
- }
- }
-
- private final class TextClassifierEventMatcher implements ArgumentMatcher<TextClassifierEvent> {
-
- private int mType;
-
- private TextClassifierEventMatcher(int type) {
- mType = type;
- }
-
- @Override
- public boolean matches(TextClassifierEvent textClassifierEvent) {
- if (textClassifierEvent == null) {
- return false;
- }
- return mType == textClassifierEvent.getEventType();
- }
- }
-}
diff --git a/packages/NetworkStack/tests/lib/Android.bp b/packages/NetworkStack/tests/lib/Android.bp
deleted file mode 100644
index f45a81c20688..000000000000
--- a/packages/NetworkStack/tests/lib/Android.bp
+++ /dev/null
@@ -1,26 +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.
-//
-
-java_library {
- name: "net-tests-utils",
- srcs: [
- "src/**/*.java",
- "src/**/*.kt",
- ],
- static_libs: [
- "kotlin-test",
- ],
-}
diff --git a/packages/NetworkStack/tests/lib/src/com/android/testutils/HandlerUtils.kt b/packages/NetworkStack/tests/lib/src/com/android/testutils/HandlerUtils.kt
deleted file mode 100644
index 3dce5a5ee06e..000000000000
--- a/packages/NetworkStack/tests/lib/src/com/android/testutils/HandlerUtils.kt
+++ /dev/null
@@ -1,50 +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.
- */
-
-package com.android.testutils
-
-import android.os.ConditionVariable
-import android.os.Handler
-import android.os.HandlerThread
-import java.util.concurrent.Executor
-import kotlin.test.fail
-
-/**
- * Block until the specified Handler or HandlerThread becomes idle, or until timeoutMs has passed.
- */
-fun Handler.waitForIdle(timeoutMs: Long) = waitForIdleHandler(this, timeoutMs)
-fun HandlerThread.waitForIdle(timeoutMs: Long) = waitForIdleHandler(this.threadHandler, timeoutMs)
-fun waitForIdleHandler(handler: HandlerThread, timeoutMs: Long) {
- waitForIdleHandler(handler.threadHandler, timeoutMs)
-}
-fun waitForIdleHandler(handler: Handler, timeoutMs: Long) {
- val cv = ConditionVariable(false)
- handler.post(cv::open)
- if (!cv.block(timeoutMs)) {
- fail("Handler did not become idle after ${timeoutMs}ms")
- }
-}
-
-/**
- * Block until the given Serial Executor becomes idle, or until timeoutMs has passed.
- */
-fun waitForIdleSerialExecutor(executor: Executor, timeoutMs: Long) {
- val cv = ConditionVariable()
- executor.execute(cv::open)
- if (!cv.block(timeoutMs)) {
- fail("Executor did not become idle after ${timeoutMs}ms")
- }
-}
diff --git a/packages/NetworkStack/tests/unit/Android.bp b/packages/NetworkStack/tests/unit/Android.bp
deleted file mode 100644
index 48b13b0a00f1..000000000000
--- a/packages/NetworkStack/tests/unit/Android.bp
+++ /dev/null
@@ -1,102 +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.
-//
-
-android_test {
- name: "NetworkStackTests",
- certificate: "platform",
- srcs: ["src/**/*.java"],
- test_suites: ["device-tests"],
- resource_dirs: ["res"],
- static_libs: [
- "androidx.test.rules",
- "mockito-target-extended-minus-junit4",
- "net-tests-utils",
- "NetworkStackBase",
- "testables",
- ],
- libs: [
- "android.test.runner",
- "android.test.base",
- "android.test.mock",
- ],
- jni_libs: [
- // For mockito extended
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
- // For ApfTest
- "libbacktrace",
- "libbase",
- "libbinder",
- "libbinderthreadstate",
- "libc++",
- "libcgrouprc",
- "libcrypto",
- "libcutils",
- "ld-android",
- "libdl_android",
- "libhidl-gen-utils",
- "libhidlbase",
- "libhidltransport",
- "libhwbinder",
- "libjsoncpp",
- "liblog",
- "liblzma",
- "libnativehelper",
- "libnativehelper_compat_libc++",
- "libnetworkstacktestsjni",
- "libnetworkstackutilsjni",
- "libpackagelistparser",
- "libpcre2",
- "libprocessgroup",
- "libselinux",
- "libui",
- "libutils",
- "libvintf",
- "libvndksupport",
- "libtinyxml2",
- "libunwindstack",
- "libutilscallstack",
- "libziparchive",
- "libz",
- "netd_aidl_interface-V2-cpp",
- ],
-}
-
-cc_library_shared {
- name: "libnetworkstacktestsjni",
- srcs: [
- "jni/**/*.cpp"
- ],
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- ],
- include_dirs: [
- "hardware/google/apf",
- ],
- shared_libs: [
- "libbinder",
- "liblog",
- "libcutils",
- "libnativehelper",
- "netd_aidl_interface-V2-cpp",
- ],
- static_libs: [
- "libapf",
- "libpcap",
- ],
-}
diff --git a/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
deleted file mode 100644
index e4c1d1792bb7..000000000000
--- a/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ /dev/null
@@ -1,1154 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_EVALUATION_TYPE;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL;
-import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD;
-import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS;
-import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.DnsResolver;
-import android.net.INetworkMonitorCallbacks;
-import android.net.InetAddresses;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.captiveportal.CaptivePortalProbeResult;
-import android.net.metrics.IpConnectivityLog;
-import android.net.shared.PrivateDnsConfig;
-import android.net.util.SharedLog;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.telephony.CellSignalStrength;
-import android.telephony.TelephonyManager;
-import android.util.ArrayMap;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.networkstack.R;
-import com.android.networkstack.metrics.DataStallDetectionStats;
-import com.android.networkstack.metrics.DataStallStatsUtils;
-import com.android.testutils.HandlerUtilsKt;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
-import org.mockito.verification.VerificationWithTimeout;
-
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.URL;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.Executor;
-
-import javax.net.ssl.SSLHandshakeException;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkMonitorTest {
- private static final String LOCATION_HEADER = "location";
-
- private @Mock Context mContext;
- private @Mock Resources mResources;
- private @Mock IpConnectivityLog mLogger;
- private @Mock SharedLog mValidationLogger;
- private @Mock NetworkInfo mNetworkInfo;
- private @Mock DnsResolver mDnsResolver;
- private @Mock ConnectivityManager mCm;
- private @Mock TelephonyManager mTelephony;
- private @Mock WifiManager mWifi;
- private @Mock HttpURLConnection mHttpConnection;
- private @Mock HttpURLConnection mHttpsConnection;
- private @Mock HttpURLConnection mFallbackConnection;
- private @Mock HttpURLConnection mOtherFallbackConnection;
- private @Mock Random mRandom;
- private @Mock NetworkMonitor.Dependencies mDependencies;
- private @Mock INetworkMonitorCallbacks mCallbacks;
- private @Spy Network mCleartextDnsNetwork = new Network(TEST_NETID);
- private @Mock Network mNetwork;
- private @Mock DataStallStatsUtils mDataStallStatsUtils;
- private @Mock WifiInfo mWifiInfo;
- private @Captor ArgumentCaptor<String> mNetworkTestedRedirectUrlCaptor;
-
- private HashSet<WrappedNetworkMonitor> mCreatedNetworkMonitors;
- private HashSet<BroadcastReceiver> mRegisteredReceivers;
-
- private static final int TEST_NETID = 4242;
- private static final String TEST_HTTP_URL = "http://www.google.com/gen_204";
- private static final String TEST_HTTPS_URL = "https://www.google.com/gen_204";
- private static final String TEST_FALLBACK_URL = "http://fallback.google.com/gen_204";
- private static final String TEST_OTHER_FALLBACK_URL = "http://otherfallback.google.com/gen_204";
- private static final String TEST_MCCMNC = "123456";
-
- private static final int VALIDATION_RESULT_INVALID = 0;
- private static final int VALIDATION_RESULT_PORTAL = 0;
- private static final String TEST_REDIRECT_URL = "android.com";
- private static final int VALIDATION_RESULT_PARTIAL = NETWORK_VALIDATION_PROBE_DNS
- | NETWORK_VALIDATION_PROBE_HTTP
- | NETWORK_VALIDATION_RESULT_PARTIAL;
- private static final int VALIDATION_RESULT_FALLBACK_PARTIAL = NETWORK_VALIDATION_PROBE_DNS
- | NETWORK_VALIDATION_PROBE_FALLBACK
- | NETWORK_VALIDATION_RESULT_PARTIAL;
- private static final int VALIDATION_RESULT_VALID = NETWORK_VALIDATION_PROBE_DNS
- | NETWORK_VALIDATION_PROBE_HTTPS
- | NETWORK_VALIDATION_RESULT_VALID;
-
- private static final int RETURN_CODE_DNS_SUCCESS = 0;
- private static final int RETURN_CODE_DNS_TIMEOUT = 255;
- private static final int DEFAULT_DNS_TIMEOUT_THRESHOLD = 5;
-
- private static final int HANDLER_TIMEOUT_MS = 1000;
-
- private static final LinkProperties TEST_LINK_PROPERTIES = new LinkProperties();
-
- private static final NetworkCapabilities METERED_CAPABILITIES = new NetworkCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET);
-
- private static final NetworkCapabilities NOT_METERED_CAPABILITIES = new NetworkCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
-
- private static final NetworkCapabilities NO_INTERNET_CAPABILITIES = new NetworkCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-
- /**
- * Fakes DNS responses.
- *
- * Allows test methods to configure the IP addresses that will be resolved by
- * Network#getAllByName and by DnsResolver#query.
- */
- class FakeDns {
- private final ArrayMap<String, List<InetAddress>> mAnswers = new ArrayMap<>();
- private boolean mNonBypassPrivateDnsWorking = true;
-
- /** Whether DNS queries on mNonBypassPrivateDnsWorking should succeed. */
- private void setNonBypassPrivateDnsWorking(boolean working) {
- mNonBypassPrivateDnsWorking = working;
- }
-
- /** Clears all DNS entries. */
- private synchronized void clearAll() {
- mAnswers.clear();
- }
-
- /** Returns the answer for a given name on the given mock network. */
- private synchronized List<InetAddress> getAnswer(Object mock, String hostname) {
- if (mock == mNetwork && !mNonBypassPrivateDnsWorking) {
- return null;
- }
- if (mAnswers.containsKey(hostname)) {
- return mAnswers.get(hostname);
- }
- return mAnswers.get("*");
- }
-
- /** Sets the answer for a given name. */
- private synchronized void setAnswer(String hostname, String[] answer)
- throws UnknownHostException {
- if (answer == null) {
- mAnswers.remove(hostname);
- } else {
- List<InetAddress> answerList = new ArrayList<>();
- for (String addr : answer) {
- answerList.add(InetAddresses.parseNumericAddress(addr));
- }
- mAnswers.put(hostname, answerList);
- }
- }
-
- /** Simulates a getAllByName call for the specified name on the specified mock network. */
- private InetAddress[] getAllByName(Object mock, String hostname)
- throws UnknownHostException {
- List<InetAddress> answer = getAnswer(mock, hostname);
- if (answer == null || answer.size() == 0) {
- throw new UnknownHostException(hostname);
- }
- return answer.toArray(new InetAddress[0]);
- }
-
- /** Starts mocking DNS queries. */
- private void startMocking() throws UnknownHostException {
- // Queries on mNetwork using getAllByName.
- doAnswer(invocation -> {
- return getAllByName(invocation.getMock(), invocation.getArgument(0));
- }).when(mNetwork).getAllByName(any());
-
- // Queries on mCleartextDnsNetwork using DnsResolver#query.
- doAnswer(invocation -> {
- String hostname = (String) invocation.getArgument(1);
- Executor executor = (Executor) invocation.getArgument(3);
- DnsResolver.Callback<List<InetAddress>> callback = invocation.getArgument(5);
-
- List<InetAddress> answer = getAnswer(invocation.getMock(), hostname);
- if (answer != null && answer.size() > 0) {
- new Handler(Looper.getMainLooper()).post(() -> {
- executor.execute(() -> callback.onAnswer(answer, 0));
- });
- }
- // If no answers, do nothing. sendDnsProbeWithTimeout will time out and throw UHE.
- return null;
- }).when(mDnsResolver).query(any(), any(), anyInt(), any(), any(), any());
-
- // Queries on mCleartextDnsNetwork using using DnsResolver#query with QueryType.
- doAnswer(invocation -> {
- String hostname = (String) invocation.getArgument(1);
- Executor executor = (Executor) invocation.getArgument(4);
- DnsResolver.Callback<List<InetAddress>> callback = invocation.getArgument(6);
-
- List<InetAddress> answer = getAnswer(invocation.getMock(), hostname);
- if (answer != null && answer.size() > 0) {
- new Handler(Looper.getMainLooper()).post(() -> {
- executor.execute(() -> callback.onAnswer(answer, 0));
- });
- }
- // If no answers, do nothing. sendDnsProbeWithTimeout will time out and throw UHE.
- return null;
- }).when(mDnsResolver).query(any(), any(), anyInt(), anyInt(), any(), any(), any());
- }
- }
-
- private FakeDns mFakeDns;
-
- @Before
- public void setUp() throws IOException {
- MockitoAnnotations.initMocks(this);
- when(mDependencies.getPrivateDnsBypassNetwork(any())).thenReturn(mCleartextDnsNetwork);
- when(mDependencies.getDnsResolver()).thenReturn(mDnsResolver);
- when(mDependencies.getRandom()).thenReturn(mRandom);
- when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt()))
- .thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
- when(mDependencies.getDeviceConfigPropertyInt(any(), eq(CAPTIVE_PORTAL_USE_HTTPS),
- anyInt())).thenReturn(1);
- when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTP_URL), any()))
- .thenReturn(TEST_HTTP_URL);
- when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL), any()))
- .thenReturn(TEST_HTTPS_URL);
-
- doReturn(mCleartextDnsNetwork).when(mNetwork).getPrivateDnsBypassingCopy();
-
- when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mCm);
- when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephony);
- when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifi);
- when(mContext.getResources()).thenReturn(mResources);
-
- when(mResources.getString(anyInt())).thenReturn("");
- when(mResources.getStringArray(anyInt())).thenReturn(new String[0]);
-
- when(mNetworkInfo.getType()).thenReturn(ConnectivityManager.TYPE_WIFI);
- setFallbackUrl(TEST_FALLBACK_URL);
- setOtherFallbackUrls(TEST_OTHER_FALLBACK_URL);
- setFallbackSpecs(null); // Test with no fallback spec by default
- when(mRandom.nextInt()).thenReturn(0);
-
- // DNS probe timeout should not be defined more than half of HANDLER_TIMEOUT_MS. Otherwise,
- // it will fail the test because of timeout expired for querying AAAA and A sequentially.
- when(mResources.getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout)))
- .thenReturn(200);
-
- doAnswer((invocation) -> {
- URL url = invocation.getArgument(0);
- switch(url.toString()) {
- case TEST_HTTP_URL:
- return mHttpConnection;
- case TEST_HTTPS_URL:
- return mHttpsConnection;
- case TEST_FALLBACK_URL:
- return mFallbackConnection;
- case TEST_OTHER_FALLBACK_URL:
- return mOtherFallbackConnection;
- default:
- fail("URL not mocked: " + url.toString());
- return null;
- }
- }).when(mCleartextDnsNetwork).openConnection(any());
- when(mHttpConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
- when(mHttpsConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
-
- mFakeDns = new FakeDns();
- mFakeDns.startMocking();
- mFakeDns.setAnswer("*", new String[]{"2001:db8::1", "192.0.2.2"});
-
- when(mContext.registerReceiver(any(BroadcastReceiver.class), any())).then((invocation) -> {
- mRegisteredReceivers.add(invocation.getArgument(0));
- return new Intent();
- });
-
- doAnswer((invocation) -> {
- mRegisteredReceivers.remove(invocation.getArgument(0));
- return null;
- }).when(mContext).unregisterReceiver(any());
-
- setMinDataStallEvaluateInterval(500);
- setDataStallEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS);
- setValidDataStallDnsTimeThreshold(500);
- setConsecutiveDnsTimeoutThreshold(5);
-
- mCreatedNetworkMonitors = new HashSet<>();
- mRegisteredReceivers = new HashSet<>();
- }
-
- @After
- public void tearDown() {
- mFakeDns.clearAll();
- assertTrue(mCreatedNetworkMonitors.size() > 0);
- // Make a local copy of mCreatedNetworkMonitors because during the iteration below,
- // WrappedNetworkMonitor#onQuitting will delete elements from it on the handler threads.
- WrappedNetworkMonitor[] networkMonitors = mCreatedNetworkMonitors.toArray(
- new WrappedNetworkMonitor[0]);
- for (WrappedNetworkMonitor nm : networkMonitors) {
- nm.notifyNetworkDisconnected();
- nm.awaitQuit();
- }
- assertEquals("NetworkMonitor still running after disconnect",
- 0, mCreatedNetworkMonitors.size());
- assertEquals("BroadcastReceiver still registered after disconnect",
- 0, mRegisteredReceivers.size());
- }
-
- private class WrappedNetworkMonitor extends NetworkMonitor {
- private long mProbeTime = 0;
- private final ConditionVariable mQuitCv = new ConditionVariable(false);
-
- WrappedNetworkMonitor() {
- super(mContext, mCallbacks, mNetwork, mLogger, mValidationLogger,
- mDependencies, mDataStallStatsUtils);
- }
-
- @Override
- protected long getLastProbeTime() {
- return mProbeTime;
- }
-
- protected void setLastProbeTime(long time) {
- mProbeTime = time;
- }
-
- @Override
- protected void addDnsEvents(@NonNull final DataStallDetectionStats.Builder stats) {
- generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
- }
-
- @Override
- protected void onQuitting() {
- assertTrue(mCreatedNetworkMonitors.remove(this));
- mQuitCv.open();
- }
-
- protected void awaitQuit() {
- assertTrue("NetworkMonitor did not quit after " + HANDLER_TIMEOUT_MS + "ms",
- mQuitCv.block(HANDLER_TIMEOUT_MS));
- }
- }
-
- private WrappedNetworkMonitor makeMonitor(NetworkCapabilities nc) {
- final WrappedNetworkMonitor nm = new WrappedNetworkMonitor();
- nm.start();
- setNetworkCapabilities(nm, nc);
- HandlerUtilsKt.waitForIdle(nm.getHandler(), HANDLER_TIMEOUT_MS);
- mCreatedNetworkMonitors.add(nm);
- return nm;
- }
-
- private WrappedNetworkMonitor makeMeteredNetworkMonitor() {
- final WrappedNetworkMonitor nm = makeMonitor(METERED_CAPABILITIES);
- return nm;
- }
-
- private WrappedNetworkMonitor makeNotMeteredNetworkMonitor() {
- final WrappedNetworkMonitor nm = makeMonitor(NOT_METERED_CAPABILITIES);
- return nm;
- }
-
- private void setNetworkCapabilities(NetworkMonitor nm, NetworkCapabilities nc) {
- nm.notifyNetworkCapabilitiesChanged(nc);
- HandlerUtilsKt.waitForIdle(nm.getHandler(), HANDLER_TIMEOUT_MS);
- }
-
- @Test
- public void testGetIntSetting() throws Exception {
- WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
-
- // No config resource, no device config. Expect to get default resource.
- doThrow(new Resources.NotFoundException())
- .when(mResources).getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout));
- doAnswer(invocation -> {
- int defaultValue = invocation.getArgument(2);
- return defaultValue;
- }).when(mDependencies).getDeviceConfigPropertyInt(any(),
- eq(NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT),
- anyInt());
- when(mResources.getInteger(eq(R.integer.default_captive_portal_dns_probe_timeout)))
- .thenReturn(42);
- assertEquals(42, wnm.getIntSetting(mContext,
- R.integer.config_captive_portal_dns_probe_timeout,
- NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
- R.integer.default_captive_portal_dns_probe_timeout));
-
- // Set device config. Expect to get device config.
- when(mDependencies.getDeviceConfigPropertyInt(any(),
- eq(NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT), anyInt()))
- .thenReturn(1234);
- assertEquals(1234, wnm.getIntSetting(mContext,
- R.integer.config_captive_portal_dns_probe_timeout,
- NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
- R.integer.default_captive_portal_dns_probe_timeout));
-
- // Set config resource. Expect to get config resource.
- when(mResources.getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout)))
- .thenReturn(5678);
- assertEquals(5678, wnm.getIntSetting(mContext,
- R.integer.config_captive_portal_dns_probe_timeout,
- NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
- R.integer.default_captive_portal_dns_probe_timeout));
- }
-
- @Test
- public void testIsCaptivePortal_HttpProbeIsPortal() throws IOException {
- setSslException(mHttpsConnection);
- setPortal302(mHttpConnection);
- runPortalNetworkTest(VALIDATION_RESULT_PORTAL);
- }
-
- @Test
- public void testIsCaptivePortal_HttpsProbeIsNotPortal() throws IOException {
- setStatus(mHttpsConnection, 204);
- setStatus(mHttpConnection, 500);
-
- runNotPortalNetworkTest();
- }
-
- @Test
- public void testIsCaptivePortal_FallbackProbeIsPortal() throws IOException {
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
- setPortal302(mFallbackConnection);
- runPortalNetworkTest(VALIDATION_RESULT_INVALID);
- }
-
- @Test
- public void testIsCaptivePortal_FallbackProbeIsNotPortal() throws IOException {
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
- setStatus(mFallbackConnection, 500);
-
- // Fallback probe did not see portal, HTTPS failed -> inconclusive
- runFailedNetworkTest();
- }
-
- @Test
- public void testIsCaptivePortal_OtherFallbackProbeIsPortal() throws IOException {
- // Set all fallback probes but one to invalid URLs to verify they are being skipped
- setFallbackUrl(TEST_FALLBACK_URL);
- setOtherFallbackUrls(TEST_FALLBACK_URL + "," + TEST_OTHER_FALLBACK_URL);
-
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
- setStatus(mFallbackConnection, 500);
- setPortal302(mOtherFallbackConnection);
-
- // TEST_OTHER_FALLBACK_URL is third
- when(mRandom.nextInt()).thenReturn(2);
-
- // First check always uses the first fallback URL: inconclusive
- final NetworkMonitor monitor = runNetworkTest(VALIDATION_RESULT_INVALID);
- assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
- verify(mFallbackConnection, times(1)).getResponseCode();
- verify(mOtherFallbackConnection, never()).getResponseCode();
-
- // Second check uses the URL chosen by Random
- final CaptivePortalProbeResult result = monitor.isCaptivePortal();
- assertTrue(result.isPortal());
- verify(mOtherFallbackConnection, times(1)).getResponseCode();
- }
-
- @Test
- public void testIsCaptivePortal_AllProbesFailed() throws IOException {
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
- setStatus(mFallbackConnection, 404);
-
- runFailedNetworkTest();
- verify(mFallbackConnection, times(1)).getResponseCode();
- verify(mOtherFallbackConnection, never()).getResponseCode();
- }
-
- @Test
- public void testIsCaptivePortal_InvalidUrlSkipped() throws IOException {
- setFallbackUrl("invalid");
- setOtherFallbackUrls("otherinvalid," + TEST_OTHER_FALLBACK_URL + ",yetanotherinvalid");
-
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
- setPortal302(mOtherFallbackConnection);
- runPortalNetworkTest(VALIDATION_RESULT_INVALID);
- verify(mOtherFallbackConnection, times(1)).getResponseCode();
- verify(mFallbackConnection, never()).getResponseCode();
- }
-
- private void setupFallbackSpec() throws IOException {
- setFallbackSpecs("http://example.com@@/@@204@@/@@"
- + "@@,@@"
- + TEST_OTHER_FALLBACK_URL + "@@/@@30[12]@@/@@https://(www\\.)?google.com/?.*");
-
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
-
- // Use the 2nd fallback spec
- when(mRandom.nextInt()).thenReturn(1);
- }
-
- @Test
- public void testIsCaptivePortal_FallbackSpecIsPartial() throws IOException {
- setupFallbackSpec();
- set302(mOtherFallbackConnection, "https://www.google.com/test?q=3");
-
- // HTTPS failed, fallback spec went through -> partial connectivity
- runPartialConnectivityNetworkTest(VALIDATION_RESULT_FALLBACK_PARTIAL);
- verify(mOtherFallbackConnection, times(1)).getResponseCode();
- verify(mFallbackConnection, never()).getResponseCode();
- }
-
- @Test
- public void testIsCaptivePortal_FallbackSpecIsPortal() throws IOException {
- setupFallbackSpec();
- set302(mOtherFallbackConnection, "http://login.portal.example.com");
- runPortalNetworkTest(VALIDATION_RESULT_INVALID);
- }
-
- @Test
- public void testIsCaptivePortal_IgnorePortals() throws IOException {
- setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE);
- setSslException(mHttpsConnection);
- setPortal302(mHttpConnection);
-
- runNoValidationNetworkTest();
- }
-
- @Test
- public void testIsDataStall_EvaluationDisabled() {
- setDataStallEvaluationType(0);
- WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
- assertFalse(wrappedMonitor.isDataStall());
- }
-
- @Test
- public void testIsDataStall_EvaluationDnsOnNotMeteredNetwork() {
- WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
- makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
- assertTrue(wrappedMonitor.isDataStall());
- }
-
- @Test
- public void testIsDataStall_EvaluationDnsOnMeteredNetwork() {
- WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
- assertFalse(wrappedMonitor.isDataStall());
-
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
- assertTrue(wrappedMonitor.isDataStall());
- }
-
- @Test
- public void testIsDataStall_EvaluationDnsWithDnsTimeoutCount() {
- WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- makeDnsTimeoutEvent(wrappedMonitor, 3);
- assertFalse(wrappedMonitor.isDataStall());
- // Reset consecutive timeout counts.
- makeDnsSuccessEvent(wrappedMonitor, 1);
- makeDnsTimeoutEvent(wrappedMonitor, 2);
- assertFalse(wrappedMonitor.isDataStall());
-
- makeDnsTimeoutEvent(wrappedMonitor, 3);
- assertTrue(wrappedMonitor.isDataStall());
-
- // Set the value to larger than the default dns log size.
- setConsecutiveDnsTimeoutThreshold(51);
- wrappedMonitor = makeMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- makeDnsTimeoutEvent(wrappedMonitor, 50);
- assertFalse(wrappedMonitor.isDataStall());
-
- makeDnsTimeoutEvent(wrappedMonitor, 1);
- assertTrue(wrappedMonitor.isDataStall());
- }
-
- @Test
- public void testIsDataStall_EvaluationDnsWithDnsTimeThreshold() {
- // Test dns events happened in valid dns time threshold.
- WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
- makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
- assertFalse(wrappedMonitor.isDataStall());
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- assertTrue(wrappedMonitor.isDataStall());
-
- // Test dns events happened before valid dns time threshold.
- setValidDataStallDnsTimeThreshold(0);
- wrappedMonitor = makeMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
- makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
- assertFalse(wrappedMonitor.isDataStall());
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- assertFalse(wrappedMonitor.isDataStall());
- }
-
- @Test
- public void testBrokenNetworkNotValidated() throws Exception {
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
- setStatus(mFallbackConnection, 404);
-
- runFailedNetworkTest();
- }
-
- @Test
- public void testNoInternetCapabilityValidated() throws Exception {
- runNetworkTest(NO_INTERNET_CAPABILITIES, NETWORK_VALIDATION_RESULT_VALID,
- getGeneralVerification());
- verify(mCleartextDnsNetwork, never()).openConnection(any());
- }
-
- @Test
- public void testLaunchCaptivePortalApp() throws Exception {
- setSslException(mHttpsConnection);
- setPortal302(mHttpConnection);
-
- final NetworkMonitor nm = makeMonitor(METERED_CAPABILITIES);
- nm.notifyNetworkConnected(TEST_LINK_PROPERTIES, METERED_CAPABILITIES);
-
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .showProvisioningNotification(any(), any());
-
- assertEquals(1, mRegisteredReceivers.size());
-
- // Check that startCaptivePortalApp sends the expected intent.
- nm.launchCaptivePortalApp();
-
- final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
- final ArgumentCaptor<Network> networkCaptor = ArgumentCaptor.forClass(Network.class);
- verify(mCm, timeout(HANDLER_TIMEOUT_MS).times(1))
- .startCaptivePortalApp(networkCaptor.capture(), bundleCaptor.capture());
- final Bundle bundle = bundleCaptor.getValue();
- final Network bundleNetwork = bundle.getParcelable(ConnectivityManager.EXTRA_NETWORK);
- assertEquals(TEST_NETID, bundleNetwork.netId);
- // network is passed both in bundle and as parameter, as the bundle is opaque to the
- // framework and only intended for the captive portal app, but the framework needs
- // the network to identify the right NetworkMonitor.
- assertEquals(TEST_NETID, networkCaptor.getValue().netId);
-
- // Have the app report that the captive portal is dismissed, and check that we revalidate.
- setStatus(mHttpsConnection, 204);
- setStatus(mHttpConnection, 204);
-
- reset(mCallbacks);
- nm.notifyCaptivePortalAppFinished(APP_RETURN_DISMISSED);
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
- .notifyNetworkTested(eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP
- | NETWORK_VALIDATION_RESULT_VALID), any());
- assertEquals(0, mRegisteredReceivers.size());
- }
-
- @Test
- public void testPrivateDnsSuccess() throws Exception {
- setStatus(mHttpsConnection, 204);
- setStatus(mHttpConnection, 204);
- mFakeDns.setAnswer("dns.google", new String[]{"2001:db8::53"});
-
- WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
- wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google", new InetAddress[0]));
- wnm.notifyNetworkConnected(TEST_LINK_PROPERTIES, NOT_METERED_CAPABILITIES);
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS),
- eq(null));
- }
-
- @Test
- public void testPrivateDnsResolutionRetryUpdate() throws Exception {
- // Set a private DNS hostname that doesn't resolve and expect validation to fail.
- mFakeDns.setAnswer("dns.google", new String[0]);
- setStatus(mHttpsConnection, 204);
- setStatus(mHttpConnection, 204);
-
- WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
- wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google", new InetAddress[0]));
- wnm.notifyNetworkConnected(TEST_LINK_PROPERTIES, NOT_METERED_CAPABILITIES);
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
- .notifyNetworkTested(
- eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS),
- eq(null));
-
- // Fix DNS and retry, expect validation to succeed.
- reset(mCallbacks);
- mFakeDns.setAnswer("dns.google", new String[]{"2001:db8::1"});
-
- wnm.forceReevaluation(Process.myUid());
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
- .notifyNetworkTested(eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS),
- eq(null));
-
- // Change configuration to an invalid DNS name, expect validation to fail.
- reset(mCallbacks);
- mFakeDns.setAnswer("dns.bad", new String[0]);
- wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.bad", new InetAddress[0]));
- // Strict mode hostname resolve fail. Expect only notification for evaluation fail. No probe
- // notification.
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(eq(VALIDATION_RESULT_VALID), eq(null));
-
- // Change configuration back to working again, but make private DNS not work.
- // Expect validation to fail.
- reset(mCallbacks);
- mFakeDns.setNonBypassPrivateDnsWorking(false);
- wnm.notifyPrivateDnsSettingsChanged(new PrivateDnsConfig("dns.google",
- new InetAddress[0]));
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
- .notifyNetworkTested(
- eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS),
- eq(null));
-
- // Make private DNS work again. Expect validation to succeed.
- reset(mCallbacks);
- mFakeDns.setNonBypassPrivateDnsWorking(true);
- wnm.forceReevaluation(Process.myUid());
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).atLeastOnce())
- .notifyNetworkTested(
- eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_PRIVDNS), eq(null));
- }
-
- @Test
- public void testDataStall_StallSuspectedAndSendMetrics() throws IOException {
- WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- makeDnsTimeoutEvent(wrappedMonitor, 5);
- assertTrue(wrappedMonitor.isDataStall());
- verify(mDataStallStatsUtils, times(1)).write(makeEmptyDataStallDetectionStats(), any());
- }
-
- @Test
- public void testDataStall_NoStallSuspectedAndSendMetrics() throws IOException {
- WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
- wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
- makeDnsTimeoutEvent(wrappedMonitor, 3);
- assertFalse(wrappedMonitor.isDataStall());
- verify(mDataStallStatsUtils, never()).write(makeEmptyDataStallDetectionStats(), any());
- }
-
- @Test
- public void testCollectDataStallMetrics() {
- WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
-
- when(mTelephony.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE);
- when(mTelephony.getNetworkOperator()).thenReturn(TEST_MCCMNC);
- when(mTelephony.getSimOperator()).thenReturn(TEST_MCCMNC);
-
- DataStallDetectionStats.Builder stats =
- new DataStallDetectionStats.Builder()
- .setEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS)
- .setNetworkType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .setCellData(TelephonyManager.NETWORK_TYPE_LTE /* radioType */,
- true /* roaming */,
- TEST_MCCMNC /* networkMccmnc */,
- TEST_MCCMNC /* simMccmnc */,
- CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN /* signalStrength */);
- generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
-
- assertEquals(wrappedMonitor.buildDataStallDetectionStats(
- NetworkCapabilities.TRANSPORT_CELLULAR), stats.build());
-
- when(mWifi.getConnectionInfo()).thenReturn(mWifiInfo);
-
- stats = new DataStallDetectionStats.Builder()
- .setEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS)
- .setNetworkType(NetworkCapabilities.TRANSPORT_WIFI)
- .setWiFiData(mWifiInfo);
- generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
-
- assertEquals(
- wrappedMonitor.buildDataStallDetectionStats(NetworkCapabilities.TRANSPORT_WIFI),
- stats.build());
- }
-
- @Test
- public void testIgnoreHttpsProbe() throws Exception {
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 204);
- // Expect to send HTTP, HTTPS, FALLBACK probe and evaluation result notifications to CS.
- final NetworkMonitor nm = runNetworkTest(VALIDATION_RESULT_PARTIAL);
-
- reset(mCallbacks);
- nm.setAcceptPartialConnectivity();
- // Expect to update evaluation result notifications to CS.
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
- eq(VALIDATION_RESULT_PARTIAL | NETWORK_VALIDATION_RESULT_VALID), eq(null));
- }
-
- @Test
- public void testIsPartialConnectivity() throws IOException {
- setStatus(mHttpsConnection, 500);
- setStatus(mHttpConnection, 204);
- setStatus(mFallbackConnection, 500);
- runPartialConnectivityNetworkTest(VALIDATION_RESULT_PARTIAL);
-
- reset(mCallbacks);
- setStatus(mHttpsConnection, 500);
- setStatus(mHttpConnection, 500);
- setStatus(mFallbackConnection, 204);
- runPartialConnectivityNetworkTest(VALIDATION_RESULT_FALLBACK_PARTIAL);
- }
-
- private void assertIpAddressArrayEquals(String[] expected, InetAddress[] actual) {
- String[] actualStrings = new String[actual.length];
- for (int i = 0; i < actual.length; i++) {
- actualStrings[i] = actual[i].getHostAddress();
- }
- assertArrayEquals("Array of IP addresses differs", expected, actualStrings);
- }
-
- @Test
- public void testSendDnsProbeWithTimeout() throws Exception {
- WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
- final int shortTimeoutMs = 200;
-
- // Clear the wildcard DNS response created in setUp.
- mFakeDns.setAnswer("*", null);
-
- String[] expected = new String[]{"2001:db8::"};
- mFakeDns.setAnswer("www.google.com", expected);
- InetAddress[] actual = wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs);
- assertIpAddressArrayEquals(expected, actual);
-
- expected = new String[]{"2001:db8::", "192.0.2.1"};
- mFakeDns.setAnswer("www.googleapis.com", expected);
- actual = wnm.sendDnsProbeWithTimeout("www.googleapis.com", shortTimeoutMs);
- assertIpAddressArrayEquals(expected, actual);
-
- mFakeDns.setAnswer("www.google.com", new String[0]);
- try {
- wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs);
- fail("No DNS results, expected UnknownHostException");
- } catch (UnknownHostException e) {
- }
-
- mFakeDns.setAnswer("www.google.com", null);
- try {
- wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs);
- fail("DNS query timed out, expected UnknownHostException");
- } catch (UnknownHostException e) {
- }
- }
-
- @Test
- public void testNotifyNetwork_WithforceReevaluation() throws Exception {
- final NetworkMonitor nm = runValidatedNetworkTest();
- // Verify forceReevalution will not reset the validation result but only probe result until
- // getting the validation result.
- reset(mCallbacks);
- setSslException(mHttpsConnection);
- setStatus(mHttpConnection, 500);
- setStatus(mFallbackConnection, 204);
- nm.forceReevaluation(Process.myUid());
- final ArgumentCaptor<Integer> intCaptor = ArgumentCaptor.forClass(Integer.class);
- // Expect to send HTTP, HTTPs, FALLBACK and evaluation results.
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(4))
- .notifyNetworkTested(intCaptor.capture(), any());
- List<Integer> intArgs = intCaptor.getAllValues();
-
- // None of these exact values can be known in advance except for intArgs.get(0) because the
- // HTTP and HTTPS probes race and the order in which they complete is non-deterministic.
- // Thus, check only exact value for intArgs.get(0) and only check the validation result for
- // the rest ones.
- assertEquals(Integer.valueOf(NETWORK_VALIDATION_PROBE_DNS
- | NETWORK_VALIDATION_PROBE_FALLBACK | NETWORK_VALIDATION_RESULT_VALID),
- intArgs.get(0));
- assertTrue((intArgs.get(1) & NETWORK_VALIDATION_RESULT_VALID) != 0);
- assertTrue((intArgs.get(2) & NETWORK_VALIDATION_RESULT_VALID) != 0);
- assertTrue((intArgs.get(3) & NETWORK_VALIDATION_RESULT_PARTIAL) != 0);
- assertTrue((intArgs.get(3) & NETWORK_VALIDATION_RESULT_VALID) == 0);
- }
-
- @Test
- public void testEvaluationState_clearProbeResults() throws Exception {
- final NetworkMonitor nm = runValidatedNetworkTest();
- nm.getEvaluationState().clearProbeResults();
- // Verify probe results are all reset and only evaluation result left.
- assertEquals(NETWORK_VALIDATION_RESULT_VALID,
- nm.getEvaluationState().getNetworkTestResult());
- }
-
- @Test
- public void testEvaluationState_reportProbeResult() throws Exception {
- final NetworkMonitor nm = runValidatedNetworkTest();
-
- reset(mCallbacks);
-
- nm.reportHttpProbeResult(NETWORK_VALIDATION_PROBE_HTTP, CaptivePortalProbeResult.SUCCESS);
- // Verify result should be appended and notifyNetworkTested callback is triggered once.
- assertEquals(nm.getEvaluationState().getNetworkTestResult(),
- VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_HTTP);
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
- eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_PROBE_HTTP), any());
-
- nm.reportHttpProbeResult(NETWORK_VALIDATION_PROBE_HTTP, CaptivePortalProbeResult.FAILED);
- // Verify DNS probe result should not be cleared.
- assertTrue((nm.getEvaluationState().getNetworkTestResult() & NETWORK_VALIDATION_PROBE_DNS)
- == NETWORK_VALIDATION_PROBE_DNS);
- }
-
- @Test
- public void testEvaluationState_reportEvaluationResult() throws Exception {
- final NetworkMonitor nm = runValidatedNetworkTest();
-
- nm.getEvaluationState().reportEvaluationResult(NETWORK_VALIDATION_RESULT_PARTIAL,
- null /* redirectUrl */);
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
- eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
- | NETWORK_VALIDATION_RESULT_PARTIAL), eq(null));
-
- nm.getEvaluationState().reportEvaluationResult(
- NETWORK_VALIDATION_RESULT_VALID | NETWORK_VALIDATION_RESULT_PARTIAL,
- null /* redirectUrl */);
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
- eq(VALIDATION_RESULT_VALID | NETWORK_VALIDATION_RESULT_PARTIAL), eq(null));
-
- nm.getEvaluationState().reportEvaluationResult(VALIDATION_RESULT_INVALID,
- TEST_REDIRECT_URL);
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1)).notifyNetworkTested(
- eq(NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS),
- eq(TEST_REDIRECT_URL));
- }
-
- private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
- for (int i = 0; i < count; i++) {
- wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
- RETURN_CODE_DNS_TIMEOUT);
- }
- }
-
- private void makeDnsSuccessEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
- for (int i = 0; i < count; i++) {
- wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
- RETURN_CODE_DNS_SUCCESS);
- }
- }
-
- private DataStallDetectionStats makeEmptyDataStallDetectionStats() {
- return new DataStallDetectionStats.Builder().build();
- }
-
- private void setDataStallEvaluationType(int type) {
- when(mDependencies.getDeviceConfigPropertyInt(any(),
- eq(CONFIG_DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type);
- }
-
- private void setMinDataStallEvaluateInterval(int time) {
- when(mDependencies.getDeviceConfigPropertyInt(any(),
- eq(CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time);
- }
-
- private void setValidDataStallDnsTimeThreshold(int time) {
- when(mDependencies.getDeviceConfigPropertyInt(any(),
- eq(CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time);
- }
-
- private void setConsecutiveDnsTimeoutThreshold(int num) {
- when(mDependencies.getDeviceConfigPropertyInt(any(),
- eq(CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt())).thenReturn(num);
- }
-
- private void setFallbackUrl(String url) {
- when(mDependencies.getSetting(any(),
- eq(Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL), any())).thenReturn(url);
- }
-
- private void setOtherFallbackUrls(String urls) {
- when(mDependencies.getDeviceConfigProperty(any(),
- eq(CAPTIVE_PORTAL_OTHER_FALLBACK_URLS), any())).thenReturn(urls);
- }
-
- private void setFallbackSpecs(String specs) {
- when(mDependencies.getDeviceConfigProperty(any(),
- eq(CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS), any())).thenReturn(specs);
- }
-
- private void setCaptivePortalMode(int mode) {
- when(mDependencies.getSetting(any(),
- eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt())).thenReturn(mode);
- }
-
- private void runPortalNetworkTest(int result) {
- // The network test event will be triggered twice with the same result. Expect to capture
- // the second one with direct url.
- runPortalNetworkTest(result,
- (VerificationWithTimeout) timeout(HANDLER_TIMEOUT_MS).times(2));
- }
-
- private void runPortalNetworkTest(int result, VerificationWithTimeout mode) {
- runNetworkTest(result, mode);
- assertEquals(1, mRegisteredReceivers.size());
- assertNotNull(mNetworkTestedRedirectUrlCaptor.getValue());
- }
-
- private void runNotPortalNetworkTest() {
- runNetworkTest(VALIDATION_RESULT_VALID);
- assertEquals(0, mRegisteredReceivers.size());
- assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
- }
-
- private void runNoValidationNetworkTest() {
- runNetworkTest(NETWORK_VALIDATION_RESULT_VALID);
- assertEquals(0, mRegisteredReceivers.size());
- assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
- }
-
- private void runFailedNetworkTest() {
- runNetworkTest(VALIDATION_RESULT_INVALID);
- assertEquals(0, mRegisteredReceivers.size());
- assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
- }
-
- private void runPartialConnectivityNetworkTest(int result) {
- runNetworkTest(result);
- assertEquals(0, mRegisteredReceivers.size());
- assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
- }
-
- private NetworkMonitor runValidatedNetworkTest() throws Exception {
- setStatus(mHttpsConnection, 204);
- setStatus(mHttpConnection, 204);
- // Expect to send HTTPs and evaluation results.
- return runNetworkTest(VALIDATION_RESULT_VALID);
- }
-
- private NetworkMonitor runNetworkTest(int testResult) {
- return runNetworkTest(METERED_CAPABILITIES, testResult, getGeneralVerification());
- }
-
- private NetworkMonitor runNetworkTest(int testResult, VerificationWithTimeout mode) {
- return runNetworkTest(METERED_CAPABILITIES, testResult, mode);
- }
-
- private NetworkMonitor runNetworkTest(NetworkCapabilities nc, int testResult,
- VerificationWithTimeout mode) {
- final NetworkMonitor monitor = makeMonitor(nc);
- monitor.notifyNetworkConnected(TEST_LINK_PROPERTIES, nc);
- try {
- verify(mCallbacks, mode)
- .notifyNetworkTested(eq(testResult), mNetworkTestedRedirectUrlCaptor.capture());
- } catch (RemoteException e) {
- fail("Unexpected exception: " + e);
- }
- HandlerUtilsKt.waitForIdle(monitor.getHandler(), HANDLER_TIMEOUT_MS);
-
- return monitor;
- }
-
- private void setSslException(HttpURLConnection connection) throws IOException {
- doThrow(new SSLHandshakeException("Invalid cert")).when(connection).getResponseCode();
- }
-
- private void set302(HttpURLConnection connection, String location) throws IOException {
- setStatus(connection, 302);
- doReturn(location).when(connection).getHeaderField(LOCATION_HEADER);
- }
-
- private void setPortal302(HttpURLConnection connection) throws IOException {
- set302(connection, "http://login.example.com");
- }
-
- private void setStatus(HttpURLConnection connection, int status) throws IOException {
- doReturn(status).when(connection).getResponseCode();
- }
-
- private void generateTimeoutDnsEvent(DataStallDetectionStats.Builder stats, int num) {
- for (int i = 0; i < num; i++) {
- stats.addDnsEvent(RETURN_CODE_DNS_TIMEOUT, 123456789 /* timeMs */);
- }
- }
-
- private VerificationWithTimeout getGeneralVerification() {
- return (VerificationWithTimeout) timeout(HANDLER_TIMEOUT_MS).atLeastOnce();
- }
-
-}
-