Merge "Tweak search result for adaptive brightness" into qt-dev
diff --git a/res/drawable/ic_face_enroll_introduction_detail.xml b/res/drawable/ic_face_enroll_introduction_detail.xml
index 7159148..386f8c7 100644
--- a/res/drawable/ic_face_enroll_introduction_detail.xml
+++ b/res/drawable/ic_face_enroll_introduction_detail.xml
@@ -14,7 +14,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
@@ -23,8 +22,13 @@
android:viewportHeight="24">
<path
- android:pathData="M0 0h24v24H0V0z" />
+ android:pathData="M0,0h24v24H0V0z" />
+ <path
+ android:pathData="M0,0h24v24H0V0z" />
<path
android:fillColor="#000000"
- android:pathData="M11 15h2v2h-2zm0-8h2v6h-2zm0.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z" />
+ android:pathData="M12,2L3.82,5.64v5.45c0,5.05,3.49,9.76,8.18,10.91c4.69-1.15,8.18-5.86,8.18-10.91V5.64L12,2z M18.18,11.09 c0,1.55-0.41,3.05-1.1,4.38C15.77,14.5,13.4,14,12,14s-3.77,0.5-5.08,1.47c-0.69-1.33-1.1-2.83-1.1-4.38V6.94L12,4.19l6.18,2.75 V11.09z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M 12 7.5 C 13.6568542495 7.5 15 8.84314575051 15 10.5 C 15 12.1568542495 13.6568542495 13.5 12 13.5 C 10.3431457505 13.5 9 12.1568542495 9 10.5 C 9 8.84314575051 10.3431457505 7.5 12 7.5 Z" />
</vector>
\ No newline at end of file
diff --git a/res/layout/face_enroll_accessibility_toggle.xml b/res/layout/face_enroll_accessibility_toggle.xml
index 4dda2a7..d37175b 100644
--- a/res/layout/face_enroll_accessibility_toggle.xml
+++ b/res/layout/face_enroll_accessibility_toggle.xml
@@ -14,33 +14,68 @@
limitations under the License.
-->
-<LinearLayout
+<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
+ android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingEnd="16dp"
- android:paddingStart="16dp">
+ android:layout_height="wrap_content"
+ style="?attr/face_layout_theme">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/title"/>
-
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"/>
-
+ <!-- Top divider -->
<View
- android:layout_width="1dp"
- android:layout_height="match_parent"
+ android:layout_alignParentTop="true"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
android:background="?android:attr/listDivider" />
+ <!-- Title -->
+ <com.google.android.setupdesign.view.RichTextView
+ style="@style/SudDescription.Glif"
+ android:id="@+id/title"
+ android:paddingHorizontal="8dp"
+ android:paddingTop="8dp"
+ android:gravity="start"
+ android:layout_alignParentStart="true"
+ android:layout_toLeftOf="@+id/toggle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <!-- Subtitle -->
+ <TextView
+ android:id="@+id/subtitle"
+ android:paddingHorizontal="8dp"
+ android:paddingBottom="8dp"
+ android:layout_alignParentStart="true"
+ android:layout_toLeftOf="@+id/toggle"
+ android:layout_below="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/security_settings_face_enroll_introduction_accessibility_expanded"/>
+
+ <!-- Vertical divider -->
+ <View
+ android:layout_centerVertical="true"
+ android:layout_alignTop="@+id/toggle"
+ android:layout_alignBottom="@+id/toggle"
+ android:layout_toStartOf="@+id/toggle"
+ android:layout_width="1dp"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/listDivider" />
+
+ <!-- Toggle -->
<Switch
+ android:layout_alignParentEnd="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/toggle"
+ android:layout_centerVertical="true"
android:checked="true"/>
-</LinearLayout>
+ <!-- Bottom divider -->
+ <View
+ android:layout_below="@+id/subtitle"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:attr/listDivider" />
+
+</RelativeLayout>
diff --git a/res/layout/face_enroll_button.xml b/res/layout/face_enroll_button.xml
new file mode 100644
index 0000000..2a6d676
--- /dev/null
+++ b/res/layout/face_enroll_button.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <Button
+ android:id="@+id/security_settings_face_settings_enroll_button"
+ android:layout_marginStart="@dimen/screen_margin_sides"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:text="@string/security_settings_face_settings_enroll"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/face_enroll_introduction.xml b/res/layout/face_enroll_introduction.xml
index 900f378..3115bb4 100644
--- a/res/layout/face_enroll_introduction.xml
+++ b/res/layout/face_enroll_introduction.xml
@@ -45,14 +45,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"/>
-
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:layout_marginVertical="48dp">
<com.google.android.setupdesign.view.IllustrationVideoView
android:id="@+id/illustration_normal"
@@ -71,22 +67,17 @@
</FrameLayout>
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"/>
-
<!-- Contains the buttons and extra information text at the bottom -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:layout_gravity="center_horizontal|bottom"
- android:layout_marginTop="24dp">
+ android:layout_gravity="center_horizontal|bottom">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
+
<Button
android:id="@+id/accessibility_button"
style="@style/SudGlifButton.Secondary"
@@ -99,7 +90,7 @@
android:id="@+id/toggle_diversity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:visibility="invisible"
+ android:visibility="gone"
FaceEnrollAccessibilitySwitch:messageText="@string/security_settings_face_enroll_introduction_accessibility_diversity"/>
</FrameLayout>
@@ -110,7 +101,8 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="16dp"
- android:paddingEnd="16dp">
+ android:paddingEnd="16dp"
+ android:paddingTop="24dp">
<ImageView
android:layout_width="wrap_content"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7ad36f0..525e32c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -890,6 +890,8 @@
<string name="security_settings_face_preference_title">Face authentication</string>
<!-- Button shown which shows accessibility toggles for face enrollment when clicked. [CHAR LIMIT=32] -->
<string name="security_settings_face_enroll_introduction_accessibility">Use accessibility setup</string>
+ <!-- Additional details shown when the accessibility toggle is expanded. [CHAR LIMIT=NONE]-->
+ <string name="security_settings_face_enroll_introduction_accessibility_expanded"></string>
<!-- Message shown for a toggle which when enabled, allows the user to enroll using a simpler flow for accessibility [CHAR LIMIT=NONE] -->
<string name="security_settings_face_enroll_introduction_accessibility_diversity"></string>
<!-- Message shown for a toggle which when enabled, allows the user to enroll using a simpler flow for accessibility [CHAR LIMIT=NONE] -->
@@ -946,6 +948,8 @@
<string name="security_settings_face_settings_require_confirmation_details">When authenticating in apps, always require confirmation</string>
<!-- Button text in face settings which removes the user's faces from the device [CHAR LIMIT=20] -->
<string name="security_settings_face_settings_remove_face_data">Remove face data</string>
+ <!-- Button text in face settings which lets the user enroll their face [CHAR LIMIT=40] -->
+ <string name="security_settings_face_settings_enroll">Set up face authentication</string>
<!-- Text shown in face settings explaining what your face can be used for. [CHAR LIMIT=NONE] -->
<string name="security_settings_face_settings_footer">Your face can be used to unlock your device and access apps.
<annotation id="url">Learn more</annotation></string>
@@ -2203,10 +2207,10 @@
<string name="wifi_dpp_wifi_password">Wi\u2011Fi password: <xliff:g id="password" example="my password">%1$s</xliff:g></string>
<!-- Hint for Wi-Fi hotspot password [CHAR LIMIT=50] -->
<string name="wifi_dpp_hotspot_password">Hotspot password: <xliff:g id="password" example="my password">%1$s</xliff:g></string>
- <!-- Label for "Connect to this network using a QR code" [CHAR LIMIT=50] -->
+ <!-- Label for "Use a QR code to add a device to this network" [CHAR LIMIT=50] -->
<string name="wifi_dpp_add_device">Add device</string>
<!-- Hint for "Add device" [CHAR LIMIT=NONE] -->
- <string name="wifi_dpp_connect_network_using_qr_code">Connect to this network using a QR code</string>
+ <string name="wifi_dpp_connect_network_using_qr_code">Use a QR code to add a device to this network</string>
<!-- Label for the try again button [CHAR LIMIT=20]-->
<string name="retry">Retry</string>
<!-- Label for the check box to share a network with other users on the same device -->
@@ -2243,7 +2247,7 @@
<string name="wifi_carrier_content">Connect via <xliff:g id="name">%1$s</xliff:g></string>
<string name="wifi_scan_always_turnon_message">To improve location accuracy and for other purposes, <xliff:g id="app_name">%1$s</xliff:g> wants to turn on network scanning, even when Wi-Fi is off.\n\nAllow this for all apps that want to scan?</string>
- <!-- Message to inform user, an unknown app want to enable network scanning. [CHAR LIMIT=200] -->
+ <!-- Message to inform user, an unknown app want to enable network scanning. [CHAR LIMIT=250] -->
<string name="wifi_scan_always_turn_on_message_unknown">To improve location accuracy and for other purposes, an unknown app wants to turn on network scanning, even when Wi\u2011Fi is off.\n\nAllow this for all apps that want to scan?</string>
<!-- Message informing the user how to turn off [CHAR LIMIT=200] -->
<string name="wifi_scan_always_turnoff_message">To turn this off, go to Advanced in the overflow menu.</string>
@@ -2308,12 +2312,12 @@
<item quantity="one">1 network</item>
<item quantity="other">%d networks</item>
</plurals>
- <!-- Wi-Fi settings screen, Saved passpoint networks summary. This shows below the "Saved networks" item and indicates the number of passpoint networks a user has saved. [CHAR LIMIT=30] -->
+ <!-- Wi-Fi settings screen, Saved networks summary. This shows below the "Saved networks" item and indicates the number of passpoint networks a user has saved. [CHAR LIMIT=30] -->
<plurals name="wifi_saved_passpoint_access_points_summary">
<item quantity="one">1 subscription</item>
<item quantity="other">%d subscriptions</item>
</plurals>
- <!-- Wi-Fi settings screen, Saved passpoint networks summary. This shows below the "Saved networks" item and indicates number of whole kinds networks, if there are both normal saved networks and saved passpoint networks. The number will be at least 2. [CHAR LIMIT=60] -->
+ <!-- Wi-Fi settings screen, Saved networks summary. This shows below the "Saved networks" item and indicates number of whole kinds networks, if there are both normal saved networks and saved passpoint networks. The number will be at least 2. [CHAR LIMIT=60] -->
<plurals name="wifi_saved_all_access_points_summary">
<item quantity="other">%d networks & subscriptions</item>
</plurals>
@@ -6996,6 +7000,10 @@
<string name="preferred_network_type_title">Preferred network type</string>
<!-- Preferred network type summary. [CHAR LIMIT=100] -->
<string name="preferred_network_type_summary">LTE (recommended)</string>
+ <!-- Title of multimedia messaging service settings. [CHAR LIMIT=50] -->
+ <string name="mms_message_title">MMS messages</string>
+ <!-- Summary of multimedia messaging service settings. [CHAR LIMIT=100] -->
+ <string name="mms_message_summary">Send & receive when mobile data is off</string>
<!-- Work SIM title. [CHAR LIMIT=50] -->
<string name="work_sim_title">Work SIM</string>
@@ -7648,19 +7656,19 @@
<string name="zen_mode_sound_summary_on">On</string>
<!-- Do not disturb: Summary for zen mode duration setting indicating user will be prompted to set dnd duration whenever dnd is manually toggled on [CHAR LIMIT=NONE]-->
- <string name="zen_mode_duration_summary_always_prompt">Ask every time (unless turned on automatically)</string>
+ <string name="zen_mode_duration_summary_always_prompt">Ask every time</string>
<!-- Do not disturb: Summary for zen mode duration setting indicating how long dnd will last when dnd is manually toggled on [CHAR LIMIT=NONE] -->
- <string name="zen_mode_duration_summary_forever">Until you turn off (unless turned on automatically)</string>
+ <string name="zen_mode_duration_summary_forever">Until you turn off</string>
<!-- Do not disturb: Summary for zen mode duration setting indicating how long dnd will last when dnd is manually toggled on [CHAR LIMIT=NONE] -->
<plurals name="zen_mode_duration_summary_time_hours">
- <item quantity="one">1 hour (unless turned on automatically)</item>
- <item quantity="other"><xliff:g id="num_hours" example="3">%d</xliff:g> hours (unless turned on automatically)</item>
+ <item quantity="one">1 hour</item>
+ <item quantity="other"><xliff:g id="num_hours" example="3">%d</xliff:g> hours</item>
</plurals>
<!-- Do not disturb: Summary for zen mode duration setting indicating how long dnd will last when toggled on -->
- <string name="zen_mode_duration_summary_time_minutes"><xliff:g id="num_minutes" example="5">%d</xliff:g> minutes (unless turned on automatically)</string>
+ <string name="zen_mode_duration_summary_time_minutes"><xliff:g id="num_minutes" example="5">%d</xliff:g> minutes</string>
<!-- Summary for the Sound Do not Disturb option when at least one automatic rules is enabled. [CHAR LIMIT=NONE]-->
<plurals name="zen_mode_sound_summary_summary_off_info">
diff --git a/res/xml/adaptive_sleep_detail.xml b/res/xml/adaptive_sleep_detail.xml
index cada2e8..2fa511b 100644
--- a/res/xml/adaptive_sleep_detail.xml
+++ b/res/xml/adaptive_sleep_detail.xml
@@ -21,7 +21,6 @@
android:key="adaptive_sleep_detail"
android:title="@string/adaptive_sleep_title">
- <!-- TODO(111939367): add correct animation -->
<com.android.settings.widget.VideoPreference
android:key="adaptive_sleep_video"
android:title="@string/summary_placeholder"
diff --git a/res/xml/mobile_network_settings_v2.xml b/res/xml/mobile_network_settings_v2.xml
index e7cc1dc..6682437 100644
--- a/res/xml/mobile_network_settings_v2.xml
+++ b/res/xml/mobile_network_settings_v2.xml
@@ -74,6 +74,12 @@
settings:controller="com.android.settings.datausage.BillingCyclePreferenceController" />
<SwitchPreference
+ android:key="mms_message"
+ android:title="@string/mms_message_title"
+ android:summary="@string/mms_message_summary"
+ settings:controller="com.android.settings.network.telephony.MmsMessagePreferenceController" />
+
+ <SwitchPreference
android:key="enhanced_4g_lte"
android:title="@string/enhanced_4g_lte_mode_title"
android:persistent="false"
diff --git a/res/xml/security_settings_face.xml b/res/xml/security_settings_face.xml
index ad37a3e..39bf73b 100644
--- a/res/xml/security_settings_face.xml
+++ b/res/xml/security_settings_face.xml
@@ -61,6 +61,11 @@
android:key="security_settings_face_delete_faces_container"
android:selectable="false"
android:layout="@layout/face_remove_button" />
+
+ <com.android.settingslib.widget.LayoutPreference
+ android:key="security_settings_face_enroll_faces_container"
+ android:selectable="false"
+ android:layout="@layout/face_enroll_button " />
</PreferenceCategory>
<PreferenceCategory
diff --git a/src/com/android/settings/accounts/RemoveAccountPreferenceController.java b/src/com/android/settings/accounts/RemoveAccountPreferenceController.java
index 938606b..1bc30d0 100644
--- a/src/com/android/settings/accounts/RemoveAccountPreferenceController.java
+++ b/src/com/android/settings/accounts/RemoveAccountPreferenceController.java
@@ -17,8 +17,6 @@
import android.accounts.Account;
import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
@@ -30,6 +28,7 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
@@ -153,28 +152,27 @@
public void onClick(DialogInterface dialog, int which) {
Activity activity = getTargetFragment().getActivity();
AccountManager.get(activity).removeAccountAsUser(mAccount, activity,
- new AccountManagerCallback<Bundle>() {
- @Override
- public void run(AccountManagerFuture<Bundle> future) {
- boolean failed = true;
- try {
- if (future.getResult()
- .getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
- failed = false;
- }
- } catch (OperationCanceledException e) {
- // handled below
- } catch (IOException e) {
- // handled below
- } catch (AuthenticatorException e) {
- // handled below
+ future -> {
+ final Activity targetActivity = getTargetFragment().getActivity();
+ if (targetActivity == null || targetActivity.isFinishing()) {
+ Log.w(TAG, "Activity is no longer alive, skipping results");
+ return;
+ }
+ boolean failed = true;
+ try {
+ if (future.getResult()
+ .getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
+ failed = false;
}
- final Activity activity = getTargetFragment().getActivity();
- if (failed && activity != null && !activity.isFinishing()) {
- RemoveAccountFailureDialog.show(getTargetFragment());
- } else {
- activity.finish();
- }
+ } catch (OperationCanceledException
+ | IOException
+ | AuthenticatorException e) {
+ // handled below
+ }
+ if (failed) {
+ RemoveAccountFailureDialog.show(getTargetFragment());
+ } else {
+ targetActivity.finish();
}
}, null, mUserHandle);
}
diff --git a/src/com/android/settings/biometrics/BiometricEnrollBase.java b/src/com/android/settings/biometrics/BiometricEnrollBase.java
index a961921..52eaa17 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollBase.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollBase.java
@@ -76,7 +76,7 @@
public static final int BIOMETRIC_FIND_SENSOR_REQUEST = 2;
public static final int LEARN_MORE_REQUEST = 3;
public static final int CONFIRM_REQUEST = 4;
- public static final int ENROLLING = 5;
+ public static final int ENROLL_REQUEST = 5;
protected boolean mLaunchedConfirmLock;
protected byte[] mToken;
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index d923e55..6887d51 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -72,12 +72,10 @@
mFaceManager = Utils.getFaceManagerOrNull(this);
final Button accessibilityButton = findViewById(R.id.accessibility_button);
- final View footerView = findViewById(R.id.footer_layout);
accessibilityButton.setOnClickListener(view -> {
mSwitchDiversity.setChecked(true);
accessibilityButton.setVisibility(View.GONE);
mSwitchDiversity.setVisibility(View.VISIBLE);
- footerView.setVisibility(View.GONE);
});
mSwitchDiversity = findViewById(R.id.toggle_diversity);
diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java
index b65a31d..f5216d8 100644
--- a/src/com/android/settings/biometrics/face/FaceSettings.java
+++ b/src/com/android/settings/biometrics/face/FaceSettings.java
@@ -31,6 +31,8 @@
import android.provider.SearchIndexableResource;
import android.util.Log;
+import androidx.preference.Preference;
+
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
@@ -60,12 +62,23 @@
private byte[] mToken;
private FaceSettingsAttentionPreferenceController mAttentionController;
private FaceSettingsRemoveButtonPreferenceController mRemoveController;
+ private FaceSettingsEnrollButtonPreferenceController mEnrollController;
private List<AbstractPreferenceController> mControllers;
+ private List<Preference> mTogglePreferences;
+ private Preference mRemoveButton;
+ private Preference mEnrollButton;
+
private final FaceSettingsRemoveButtonPreferenceController.Listener mRemovalListener = () -> {
- if (getActivity() != null) {
- getActivity().finish();
+
+ // Disable the toggles until the user re-enrolls
+ for (Preference preference : mTogglePreferences) {
+ preference.setEnabled(false);
}
+
+ // Hide the "remove" button and show the "set up face authentication" button.
+ mRemoveButton.setVisible(false);
+ mEnrollButton.setVisible(true);
};
public static boolean isAvailable(Context context) {
@@ -103,10 +116,22 @@
mUserId = getActivity().getIntent().getIntExtra(
Intent.EXTRA_USER_ID, UserHandle.myUserId());
+ Preference keyguardPref = findPreference(FaceSettingsKeyguardPreferenceController.KEY);
+ Preference appPref = findPreference(FaceSettingsAppPreferenceController.KEY);
+ Preference attentionPref = findPreference(FaceSettingsAttentionPreferenceController.KEY);
+ Preference confirmPref = findPreference(FaceSettingsConfirmPreferenceController.KEY);
+ mTogglePreferences = new ArrayList<>(
+ Arrays.asList(keyguardPref, appPref, attentionPref, confirmPref));
+
+ mRemoveButton = findPreference(FaceSettingsRemoveButtonPreferenceController.KEY);
+ mEnrollButton = findPreference(FaceSettingsEnrollButtonPreferenceController.KEY);
+
// There is no better way to do this :/
for (AbstractPreferenceController controller : mControllers) {
if (controller instanceof FaceSettingsPreferenceController) {
((FaceSettingsPreferenceController) controller).setUserId(mUserId);
+ } else if (controller instanceof FaceSettingsEnrollButtonPreferenceController) {
+ ((FaceSettingsEnrollButtonPreferenceController) controller).setUserId(mUserId);
}
}
mRemoveController.setUserId(mUserId);
@@ -137,7 +162,12 @@
super.onResume();
if (mToken != null) {
mAttentionController.setToken(mToken);
+ mEnrollController.setToken(mToken);
}
+
+ final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId);
+ mEnrollButton.setVisible(!hasEnrolled);
+ mRemoveButton.setVisible(hasEnrolled);
}
@Override
@@ -152,6 +182,7 @@
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
if (mToken != null) {
mAttentionController.setToken(mToken);
+ mEnrollController.setToken(mToken);
}
}
}
@@ -188,6 +219,9 @@
mRemoveController = (FaceSettingsRemoveButtonPreferenceController) controller;
mRemoveController.setListener(mRemovalListener);
mRemoveController.setActivity((SettingsActivity) getActivity());
+ } else if (controller instanceof FaceSettingsEnrollButtonPreferenceController) {
+ mEnrollController = (FaceSettingsEnrollButtonPreferenceController) controller;
+ mEnrollController.setActivity((SettingsActivity) getActivity());
}
}
@@ -204,6 +238,7 @@
controllers.add(new FaceSettingsRemoveButtonPreferenceController(context));
controllers.add(new FaceSettingsFooterPreferenceController(context));
controllers.add(new FaceSettingsConfirmPreferenceController(context));
+ controllers.add(new FaceSettingsEnrollButtonPreferenceController(context));
return controllers;
}
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java
index 78389b6..1ffcb4c 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java
@@ -19,22 +19,28 @@
import static android.provider.Settings.Secure.FACE_UNLOCK_APP_ENABLED;
import android.content.Context;
+import android.hardware.face.FaceManager;
import android.provider.Settings;
+import androidx.preference.Preference;
+
/**
* Preference controller for Face settings page controlling the ability to use
* Face authentication in apps (through BiometricPrompt).
*/
public class FaceSettingsAppPreferenceController extends FaceSettingsPreferenceController {
- private static final String KEY = "security_settings_face_app";
+ static final String KEY = "security_settings_face_app";
private static final int ON = 1;
private static final int OFF = 0;
private static final int DEFAULT = ON; // face unlock is enabled for BiometricPrompt by default
+ private FaceManager mFaceManager;
+
public FaceSettingsAppPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
+ mFaceManager = context.getSystemService(FaceManager.class);
}
public FaceSettingsAppPreferenceController(Context context) {
@@ -57,6 +63,18 @@
}
@Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ if (!FaceSettings.isAvailable(mContext)) {
+ preference.setEnabled(false);
+ } else if (!mFaceManager.hasEnrolledTemplates(getUserId())) {
+ preference.setEnabled(false);
+ } else {
+ preference.setEnabled(true);
+ }
+ }
+
+ @Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java
index 9e4fd38..ef90b1e 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java
@@ -60,8 +60,12 @@
@Override
public void onCompleted(boolean success, int feature, boolean value) {
if (feature == FaceManager.FEATURE_REQUIRE_ATTENTION && success) {
- mPreference.setEnabled(true);
- mPreference.setChecked(value);
+ if (!mFaceManager.hasEnrolledTemplates(getUserId())) {
+ mPreference.setEnabled(false);
+ } else {
+ mPreference.setEnabled(true);
+ mPreference.setChecked(value);
+ }
}
}
};
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsConfirmPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsConfirmPreferenceController.java
index b721072..7dbe557 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsConfirmPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsConfirmPreferenceController.java
@@ -19,8 +19,11 @@
import static android.provider.Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION;
import android.content.Context;
+import android.hardware.face.FaceManager;
import android.provider.Settings;
+import androidx.preference.Preference;
+
import com.android.settings.core.TogglePreferenceController;
/**
@@ -28,12 +31,14 @@
*/
public class FaceSettingsConfirmPreferenceController extends FaceSettingsPreferenceController {
- private static final String KEY = "security_settings_face_require_confirmation";
+ static final String KEY = "security_settings_face_require_confirmation";
private static final int ON = 1;
private static final int OFF = 0;
private static final int DEFAULT = OFF;
+ private FaceManager mFaceManager;
+
public FaceSettingsConfirmPreferenceController(Context context) {
this(context, KEY);
}
@@ -41,6 +46,7 @@
public FaceSettingsConfirmPreferenceController(Context context,
String preferenceKey) {
super(context, preferenceKey);
+ mFaceManager = context.getSystemService(FaceManager.class);
}
@Override
@@ -56,6 +62,18 @@
}
@Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ if (!FaceSettings.isAvailable(mContext)) {
+ preference.setEnabled(false);
+ } else if (!mFaceManager.hasEnrolledTemplates(getUserId())) {
+ preference.setEnabled(false);
+ } else {
+ preference.setEnabled(true);
+ }
+ }
+
+ @Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java
new file mode 100644
index 0000000..ec7b194
--- /dev/null
+++ b/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.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.settings.biometrics.face;
+
+import android.content.Context;
+import android.content.Intent;
+import android.view.View;
+import android.widget.Button;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.password.ChooseLockSettingsHelper;
+import com.android.settingslib.widget.LayoutPreference;
+
+/**
+ * Preference controller that allows a user to enroll their face.
+ */
+public class FaceSettingsEnrollButtonPreferenceController extends BasePreferenceController
+ implements View.OnClickListener {
+
+ private static final String TAG = "FaceSettings/Remove";
+ static final String KEY = "security_settings_face_enroll_faces_container";
+
+ private int mUserId;
+ private byte[] mToken;
+ private SettingsActivity mActivity;
+ private Button mButton;
+
+ public FaceSettingsEnrollButtonPreferenceController(Context context) {
+ this(context, KEY);
+ }
+
+ public FaceSettingsEnrollButtonPreferenceController(Context context,
+ String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+
+ mButton = ((LayoutPreference) preference)
+ .findViewById(R.id.security_settings_face_settings_enroll_button);
+ mButton.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ final Intent intent = new Intent();
+ intent.setClassName("com.android.settings", FaceEnrollIntroduction.class.getName());
+ intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken);
+ mContext.startActivity(intent);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ public void setUserId(int userId) {
+ mUserId = userId;
+ }
+
+ public void setToken(byte[] token) {
+ mToken = token;
+ }
+
+ public void setActivity(SettingsActivity activity) {
+ mActivity = activity;
+ }
+}
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java
index 3a7865d..92eab85 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java
@@ -20,6 +20,7 @@
import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.hardware.face.FaceManager;
import android.os.UserHandle;
import android.provider.Settings;
@@ -39,8 +40,11 @@
private static final int OFF = 0;
private static final int DEFAULT = ON; // face unlock is enabled on keyguard by default
+ private FaceManager mFaceManager;
+
public FaceSettingsKeyguardPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
+ mFaceManager = context.getSystemService(FaceManager.class);
}
public FaceSettingsKeyguardPreferenceController(Context context) {
@@ -76,6 +80,8 @@
preference.setEnabled(false);
} else if (adminDisabled()) {
preference.setEnabled(false);
+ } else if (!mFaceManager.hasEnrolledTemplates(getUserId())) {
+ preference.setEnabled(false);
} else {
preference.setEnabled(true);
}
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
index 600ea37..68ca259 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
@@ -24,7 +24,6 @@
import android.hardware.face.Face;
import android.hardware.face.FaceManager;
import android.os.Bundle;
-import android.os.UserHandle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
@@ -48,7 +47,7 @@
implements View.OnClickListener {
private static final String TAG = "FaceSettings/Remove";
- private static final String KEY = "security_settings_face_delete_faces_container";
+ static final String KEY = "security_settings_face_delete_faces_container";
public static class ConfirmRemoveDialog extends InstrumentedDialogFragment {
@@ -85,6 +84,7 @@
private Listener mListener;
private SettingsActivity mActivity;
private int mUserId;
+ private boolean mRemoving;
private final Context mContext;
private final FaceManager mFaceManager;
@@ -103,6 +103,7 @@
if (!faces.isEmpty()) {
mButton.setEnabled(true);
} else {
+ mRemoving = false;
mListener.onRemoved();
}
} else {
@@ -154,6 +155,12 @@
mButton = ((LayoutPreference) preference)
.findViewById(R.id.security_settings_face_settings_remove_button);
mButton.setOnClickListener(this);
+
+ if (!FaceSettings.isAvailable(mContext)) {
+ mButton.setEnabled(false);
+ } else {
+ mButton.setEnabled(!mRemoving);
+ }
}
@Override
@@ -169,6 +176,7 @@
@Override
public void onClick(View v) {
if (v == mButton) {
+ mRemoving = true;
mButton.setEnabled(false);
ConfirmRemoveDialog dialog = new ConfirmRemoveDialog();
dialog.setOnClickListener(mOnClickListener);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
index 5589592..733fb3f 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
@@ -147,7 +147,7 @@
getSupportFragmentManager().beginTransaction().remove(mSidecar).
commitAllowingStateLoss();
mSidecar = null;
- startActivityForResult(getFingerprintEnrollingIntent(), ENROLLING);
+ startActivityForResult(getFingerprintEnrollingIntent(), ENROLL_REQUEST);
}
}
@@ -162,7 +162,7 @@
} else {
finish();
}
- } else if (requestCode == ENROLLING) {
+ } else if (requestCode == ENROLL_REQUEST) {
if (resultCode == RESULT_FINISHED) {
setResult(RESULT_FINISHED);
finish();
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
index 0e935c0..31055cc 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
@@ -109,6 +109,10 @@
* Force to update the list of bluetooth devices
*/
public void forceUpdate() {
+ if (mLocalManager == null) {
+ Log.e(TAG, "forceUpdate() Bluetooth is not supported on this device");
+ return;
+ }
if (BluetoothAdapter.getDefaultAdapter().isEnabled()) {
final Collection<CachedBluetoothDevice> cachedDevices =
mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
@@ -121,6 +125,10 @@
}
public void removeAllDevicesFromPreference() {
+ if (mLocalManager == null) {
+ Log.e(TAG, "removeAllDevicesFromPreference() BT is not supported on this device");
+ return;
+ }
final Collection<CachedBluetoothDevice> cachedDevices =
mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
for (CachedBluetoothDevice cachedBluetoothDevice : cachedDevices) {
diff --git a/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java b/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java
index be82284..cac46b0 100644
--- a/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java
+++ b/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java
@@ -83,9 +83,11 @@
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
+
+ mPreferenceGroup = screen.findPreference(KEY);
+ mPreferenceGroup.setVisible(false);
+
if (isAvailable()) {
- mPreferenceGroup = screen.findPreference(KEY);
- mPreferenceGroup.setVisible(false);
updateTitle();
mBluetoothDeviceUpdater.setPrefContext(screen.getContext());
mBluetoothDeviceUpdater.forceUpdate();
diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java b/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java
index aa83e67..957737a 100644
--- a/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java
+++ b/src/com/android/settings/connecteddevice/ConnectedDeviceGroupController.java
@@ -73,10 +73,11 @@
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- if (isAvailable()) {
- mPreferenceGroup = screen.findPreference(KEY);
- mPreferenceGroup.setVisible(false);
+ mPreferenceGroup = screen.findPreference(KEY);
+ mPreferenceGroup.setVisible(false);
+
+ if (isAvailable()) {
final Context context = screen.getContext();
mBluetoothDeviceUpdater.setPrefContext(context);
mBluetoothDeviceUpdater.forceUpdate();
@@ -88,7 +89,11 @@
@Override
public int getAvailabilityStatus() {
- return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
+ final PackageManager packageManager = mContext.getPackageManager();
+ return (packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
+ || packageManager.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY)
+ || packageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)
+ || mConnectedDockUpdater != null)
? AVAILABLE_UNSEARCHABLE
: UNSUPPORTED_ON_DEVICE;
}
diff --git a/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java b/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java
index 45f128d..5b23d69 100644
--- a/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java
@@ -52,7 +52,8 @@
@Override
public int getAvailabilityStatus() {
- return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
+ return (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
+ || mSavedDockUpdater != null)
? AVAILABLE
: CONDITIONALLY_UNAVAILABLE;
}
diff --git a/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java b/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java
index e1dc750..062fa2d 100644
--- a/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java
+++ b/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java
@@ -73,10 +73,10 @@
@Override
public void displayPreference(PreferenceScreen screen) {
- if (isAvailable()) {
- mPreferenceGroup = screen.findPreference(KEY);
- mPreferenceGroup.setVisible(false);
+ mPreferenceGroup = screen.findPreference(KEY);
+ mPreferenceGroup.setVisible(false);
+ if (isAvailable()) {
final Context context = screen.getContext();
mBluetoothDeviceUpdater.setPrefContext(context);
mBluetoothDeviceUpdater.forceUpdate();
@@ -87,7 +87,8 @@
@Override
public int getAvailabilityStatus() {
- return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
+ return (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
+ || mSavedDockUpdater != null)
? AVAILABLE
: UNSUPPORTED_ON_DEVICE;
}
diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java
index 9c00831..fee9c42 100644
--- a/src/com/android/settings/core/FeatureFlags.java
+++ b/src/com/android/settings/core/FeatureFlags.java
@@ -25,7 +25,6 @@
public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
public static final String MOBILE_NETWORK_V2 = "settings_mobile_network_v2";
public static final String NETWORK_INTERNET_V2 = "settings_network_and_internet_v2";
- public static final String SLICE_INJECTION = "settings_slice_injection";
public static final String WIFI_DETAILS_DATAUSAGE_HEADER =
"settings_wifi_details_datausage_header";
}
diff --git a/src/com/android/settings/development/SystemServerHeapDumpPreferenceController.java b/src/com/android/settings/development/SystemServerHeapDumpPreferenceController.java
index 599162e..e6701ce 100644
--- a/src/com/android/settings/development/SystemServerHeapDumpPreferenceController.java
+++ b/src/com/android/settings/development/SystemServerHeapDumpPreferenceController.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.os.Build;
import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.UserManager;
import android.util.Log;
@@ -47,7 +48,7 @@
super(context);
mUserManager = context.getSystemService(UserManager.class);
- mHandler = new Handler();
+ mHandler = new Handler(Looper.getMainLooper());
}
@Override
diff --git a/src/com/android/settings/gestures/GesturePreferenceController.java b/src/com/android/settings/gestures/GesturePreferenceController.java
index 97de95d..d7b386a 100644
--- a/src/com/android/settings/gestures/GesturePreferenceController.java
+++ b/src/com/android/settings/gestures/GesturePreferenceController.java
@@ -23,6 +23,7 @@
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
+import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.widget.VideoPreference;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -64,6 +65,12 @@
}
@Override
+ public CharSequence getSummary() {
+ return mContext.getText(
+ isChecked() ? R.string.gesture_setting_on : R.string.gesture_setting_off);
+ }
+
+ @Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) {
mVideoPaused = savedInstanceState.getBoolean(KEY_VIDEO_PAUSED, false);
diff --git a/src/com/android/settings/gestures/SystemNavigationPreferenceController.java b/src/com/android/settings/gestures/SystemNavigationPreferenceController.java
index 5f58fcf..f2c8252 100644
--- a/src/com/android/settings/gestures/SystemNavigationPreferenceController.java
+++ b/src/com/android/settings/gestures/SystemNavigationPreferenceController.java
@@ -139,12 +139,11 @@
* Enables the specified overlay package.
*/
static void setNavBarInteractionMode(IOverlayManager overlayManager, String overlayPackage) {
- setOverlayEnabled(overlayManager, NAV_BAR_MODE_3BUTTON_OVERLAY,
- overlayPackage == NAV_BAR_MODE_3BUTTON_OVERLAY);
- setOverlayEnabled(overlayManager, NAV_BAR_MODE_2BUTTON_OVERLAY,
- overlayPackage == NAV_BAR_MODE_2BUTTON_OVERLAY);
- setOverlayEnabled(overlayManager, NAV_BAR_MODE_GESTURAL_OVERLAY,
- overlayPackage == NAV_BAR_MODE_GESTURAL_OVERLAY);
+ try {
+ overlayManager.setEnabledExclusiveInCategory(overlayPackage, USER_CURRENT);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
static boolean isSwipeUpEnabled(Context context) {
@@ -159,12 +158,4 @@
return NAV_BAR_MODE_GESTURAL == context.getResources().getInteger(
com.android.internal.R.integer.config_navBarInteractionMode);
}
-
- static void setOverlayEnabled(IOverlayManager overlayManager, String pkg, boolean enabled) {
- try {
- overlayManager.setEnabled(pkg, enabled, USER_CURRENT);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCard.java b/src/com/android/settings/homepage/contextualcards/ContextualCard.java
index ede12fb..ccfb22d 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCard.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCard.java
@@ -72,6 +72,7 @@
@LayoutRes
private final int mViewType;
private final boolean mIsPendingDismiss;
+ private final boolean mHasInlineAction;
public String getName() {
return mName;
@@ -161,6 +162,10 @@
return mIsPendingDismiss;
}
+ public boolean hasInlineAction() {
+ return mHasInlineAction;
+ }
+
public Builder mutate() {
return mBuilder;
}
@@ -187,6 +192,7 @@
mIsLargeCard = builder.mIsLargeCard;
mViewType = builder.mViewType;
mIsPendingDismiss = builder.mIsPendingDismiss;
+ mHasInlineAction = builder.mHasInlineAction;
}
ContextualCard(Cursor c) {
@@ -234,6 +240,8 @@
mBuilder.setViewType(mViewType);
mIsPendingDismiss = false;
mBuilder.setIsPendingDismiss(mIsPendingDismiss);
+ mHasInlineAction = false;
+ mBuilder.setHasInlineAction(mHasInlineAction);
}
@Override
@@ -286,6 +294,7 @@
@LayoutRes
private int mViewType;
private boolean mIsPendingDismiss;
+ private boolean mHasInlineAction;
public Builder setName(String name) {
mName = name;
@@ -387,6 +396,11 @@
return this;
}
+ public Builder setHasInlineAction(boolean hasInlineAction) {
+ mHasInlineAction = hasInlineAction;
+ return this;
+ }
+
public ContextualCard build() {
return new ContextualCard(this);
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardsDiffCallback.java b/src/com/android/settings/homepage/contextualcards/ContextualCardsDiffCallback.java
index d1623cd..58d6a41 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardsDiffCallback.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardsDiffCallback.java
@@ -20,7 +20,6 @@
import java.util.List;
-//TODO(b/117816826): add test cases for DiffUtil.
/**
* A DiffCallback to calculate the difference between old and new {@link ContextualCard} List.
*/
@@ -53,6 +52,11 @@
@Override
public boolean areContentsTheSame(int oldCardPosition, int newCardPosition) {
+ // Slices with toggles needs to be updated continuously, which means their contents may
+ // change. So here we assume the content will always be different to force view rebinding.
+ if (mNewCards.get(newCardPosition).hasInlineAction()) {
+ return false;
+ }
return mOldCards.get(oldCardPosition).equals(mNewCards.get(newCardPosition));
}
}
\ No newline at end of file
diff --git a/src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java b/src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java
index 811aaa2..8558ee7 100644
--- a/src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java
+++ b/src/com/android/settings/homepage/contextualcards/EligibleCardChecker.java
@@ -26,11 +26,14 @@
import androidx.annotation.VisibleForTesting;
import androidx.slice.Slice;
+import androidx.slice.SliceMetadata;
import androidx.slice.SliceViewManager;
+import androidx.slice.core.SliceAction;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -41,7 +44,9 @@
private static final long LATCH_TIMEOUT_MS = 200;
private final Context mContext;
- private final ContextualCard mCard;
+
+ @VisibleForTesting
+ ContextualCard mCard;
EligibleCardChecker(Context context, ContextualCard card) {
mContext = context;
@@ -93,6 +98,11 @@
}
final Slice slice = bindSlice(uri);
+
+ if (isSliceToggleable(slice)) {
+ mCard = card.mutate().setHasInlineAction(true).build();
+ }
+
if (slice == null || slice.hasHint(HINT_ERROR)) {
Log.w(TAG, "Failed to bind slice, not eligible for display " + uri);
return false;
@@ -133,4 +143,12 @@
}
return returnSlice[0];
}
+
+ @VisibleForTesting
+ boolean isSliceToggleable(Slice slice) {
+ final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
+ final List<SliceAction> toggles = metadata.getToggles();
+
+ return !toggles.isEmpty();
+ }
}
diff --git a/src/com/android/settings/media/MediaOutputIndicatorSlice.java b/src/com/android/settings/media/MediaOutputIndicatorSlice.java
index 0023e3f..fe59d75 100644
--- a/src/com/android/settings/media/MediaOutputIndicatorSlice.java
+++ b/src/com/android/settings/media/MediaOutputIndicatorSlice.java
@@ -114,29 +114,29 @@
private boolean isVisible() {
// To decide Slice's visibility.
// return true if device is connected or previously connected, false for other cases.
- return !CollectionUtils.isEmpty(getConnectableA2dpDevices())
- || !CollectionUtils.isEmpty(getConnectableHearingAidDevices());
+ return !CollectionUtils.isEmpty(getConnectedA2dpDevices())
+ || !CollectionUtils.isEmpty(getConnectedHearingAidDevices());
}
- private List<BluetoothDevice> getConnectableA2dpDevices() {
- // Get A2dp devices on all states
- // (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTING)
+ private List<BluetoothDevice> getConnectedA2dpDevices() {
+ // Get A2dp devices on states
+ // (STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTING)
final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
if (a2dpProfile == null) {
return new ArrayList<>();
}
- return a2dpProfile.getConnectableDevices();
+ return a2dpProfile.getConnectedDevices();
}
- private List<BluetoothDevice> getConnectableHearingAidDevices() {
- // Get hearing aid profile devices on all states
- // (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTING)
+ private List<BluetoothDevice> getConnectedHearingAidDevices() {
+ // Get hearing aid profile devices on states
+ // (STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTING)
final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
if (hapProfile == null) {
return new ArrayList<>();
}
- return hapProfile.getConnectableDevices();
+ return hapProfile.getConnectedDevices();
}
private CharSequence findActiveDeviceName() {
diff --git a/src/com/android/settings/network/MobileDataContentObserver.java b/src/com/android/settings/network/MobileDataContentObserver.java
new file mode 100644
index 0000000..b8a1c8c
--- /dev/null
+++ b/src/com/android/settings/network/MobileDataContentObserver.java
@@ -0,0 +1,72 @@
+/*
+ * 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.settings.network;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+
+/**
+ * {@link ContentObserver} to listen to update of mobile data change
+ */
+public class MobileDataContentObserver extends ContentObserver {
+ private OnMobileDataChangedListener mListener;
+
+ public MobileDataContentObserver(Handler handler) {
+ super(handler);
+ }
+
+ public static Uri getObservableUri(int subId) {
+ Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA);
+ if (TelephonyManager.getDefault().getSimCount() != 1) {
+ uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + subId);
+ }
+ return uri;
+ }
+
+ public void setOnMobileDataChangedListener(OnMobileDataChangedListener lsn) {
+ mListener = lsn;
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ if (mListener != null) {
+ mListener.onMobileDataChanged();
+ }
+ }
+
+ public void register(Context context, int subId) {
+ final Uri uri = getObservableUri(subId);
+ context.getContentResolver().registerContentObserver(uri, false, this);
+
+ }
+
+ public void unRegister(Context context) {
+ context.getContentResolver().unregisterContentObserver(this);
+ }
+
+ /**
+ * Listener for update of mobile data(ON vs OFF)
+ */
+ public interface OnMobileDataChangedListener {
+ void onMobileDataChanged();
+ }
+}
diff --git a/src/com/android/settings/network/MobileNetworkListController.java b/src/com/android/settings/network/MobileNetworkListController.java
index a2e4116..d0e14ce 100644
--- a/src/com/android/settings/network/MobileNetworkListController.java
+++ b/src/com/android/settings/network/MobileNetworkListController.java
@@ -98,7 +98,7 @@
mPreferences = new ArrayMap<>();
final List<SubscriptionInfo> subscriptions = SubscriptionUtil.getAvailableSubscriptions(
- mSubscriptionManager);
+ mContext);
for (SubscriptionInfo info : subscriptions) {
final int subId = info.getSubscriptionId();
Preference pref = existingPreferences.remove(subId);
diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.java b/src/com/android/settings/network/MobileNetworkSummaryController.java
index ae115eb..9498c4e 100644
--- a/src/com/android/settings/network/MobileNetworkSummaryController.java
+++ b/src/com/android/settings/network/MobileNetworkSummaryController.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.Intent;
import android.os.UserManager;
+import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.euicc.EuiccManager;
@@ -99,7 +100,7 @@
@Override
public CharSequence getSummary() {
final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
- mSubscriptionManager);
+ mContext);
if (subs.isEmpty()) {
if (MobileNetworkUtils.showEuiccSettings(mContext)) {
return mContext.getResources().getString(
@@ -132,7 +133,7 @@
mPreference.setEnabled(!mChangeListener.isAirplaneModeOn());
final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
- mSubscriptionManager);
+ mContext);
if (subs.isEmpty()) {
if (MobileNetworkUtils.showEuiccSettings(mContext)) {
@@ -154,6 +155,7 @@
if (subs.size() == 1) {
mPreference.setOnPreferenceClickListener((Preference pref) -> {
final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
+ intent.putExtra(Settings.EXTRA_SUB_ID, subs.get(0).getSubscriptionId());
mContext.startActivity(intent);
return true;
});
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index 5f1beca..86655d4 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -16,8 +16,15 @@
package com.android.settings.network;
+import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT;
+
+import static com.android.internal.util.CollectionUtils.emptyIfNull;
+
+import android.content.Context;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.UiccSlotInfo;
import android.text.TextUtils;
import androidx.annotation.VisibleForTesting;
@@ -27,6 +34,7 @@
import java.util.List;
public class SubscriptionUtil {
+ private static final String TAG = "SubscriptionUtil";
private static List<SubscriptionInfo> sAvailableResultsForTesting;
private static List<SubscriptionInfo> sActiveResultsForTesting;
@@ -44,21 +52,56 @@
if (sActiveResultsForTesting != null) {
return sActiveResultsForTesting;
}
- List<SubscriptionInfo> subscriptions = manager.getActiveSubscriptionInfoList(true);
+ final List<SubscriptionInfo> subscriptions = manager.getActiveSubscriptionInfoList(true);
if (subscriptions == null) {
return new ArrayList<>();
}
return subscriptions;
}
- public static List<SubscriptionInfo> getAvailableSubscriptions(SubscriptionManager manager) {
+ private static boolean isInactiveInsertedPSim(UiccSlotInfo slotInfo) {
+ return !slotInfo.getIsEuicc() && !slotInfo.getIsActive() &&
+ slotInfo.getCardStateInfo() == CARD_STATE_INFO_PRESENT;
+ }
+
+ public static List<SubscriptionInfo> getAvailableSubscriptions(Context context) {
if (sAvailableResultsForTesting != null) {
return sAvailableResultsForTesting;
}
- List<SubscriptionInfo> subscriptions = manager.getSelectableSubscriptionInfoList();
- if (subscriptions == null) {
- subscriptions = new ArrayList<>();
+ final SubscriptionManager subMgr = context.getSystemService(SubscriptionManager.class);
+ final TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
+
+ List<SubscriptionInfo> subscriptions =
+ new ArrayList<>(emptyIfNull(subMgr.getSelectableSubscriptionInfoList()));
+
+ // Look for inactive but present physical SIMs that are missing from the selectable list.
+ final List<UiccSlotInfo> missing = new ArrayList<>();
+ UiccSlotInfo[] slotsInfo = telMgr.getUiccSlotsInfo();
+ for (int i = 0; slotsInfo != null && i < slotsInfo.length; i++) {
+ final UiccSlotInfo slotInfo = slotsInfo[i];
+ if (isInactiveInsertedPSim(slotInfo)) {
+ final int index = slotInfo.getLogicalSlotIdx();
+ final String cardId = slotInfo.getCardId();
+
+ final boolean found = subscriptions.stream().anyMatch(info ->
+ index == info.getSimSlotIndex() && cardId.equals(info.getCardString()));
+ if (!found) {
+ missing.add(slotInfo);
+ }
+ }
}
+ if (!missing.isEmpty()) {
+ for (SubscriptionInfo info : subMgr.getAllSubscriptionInfoList()) {
+ for (UiccSlotInfo slotInfo : missing) {
+ if (info.getSimSlotIndex() == slotInfo.getLogicalSlotIdx() &&
+ info.getCardString().equals(slotInfo.getCardId())) {
+ subscriptions.add(info);
+ break;
+ }
+ }
+ }
+ }
+
// With some carriers such as Google Fi which provide a sort of virtual service that spans
// across multiple underlying networks, we end up with subscription entries for the
// underlying networks that need to be hidden from the user in the UI.
diff --git a/src/com/android/settings/network/telephony/MmsMessagePreferenceController.java b/src/com/android/settings/network/telephony/MmsMessagePreferenceController.java
new file mode 100644
index 0000000..b8d2081
--- /dev/null
+++ b/src/com/android/settings/network/telephony/MmsMessagePreferenceController.java
@@ -0,0 +1,106 @@
+/*
+ * 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.settings.network.telephony;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.network.MobileDataContentObserver;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+/**
+ * Preference controller for "Mobile data"
+ */
+public class MmsMessagePreferenceController extends TelephonyTogglePreferenceController implements
+ LifecycleObserver, OnStart, OnStop {
+ private TelephonyManager mTelephonyManager;
+ private SubscriptionManager mSubscriptionManager;
+ private MobileDataContentObserver mMobileDataContentObserver;
+ private SwitchPreference mPreference;
+
+ public MmsMessagePreferenceController(Context context, String key) {
+ super(context, key);
+ mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
+ mMobileDataContentObserver = new MobileDataContentObserver(
+ new Handler(Looper.getMainLooper()));
+ mMobileDataContentObserver.setOnMobileDataChangedListener(()->updateState(mPreference));
+ }
+
+ @Override
+ public int getAvailabilityStatus(int subId) {
+ final TelephonyManager telephonyManager = TelephonyManager
+ .from(mContext).createForSubscriptionId(subId);
+ return (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID
+ && !telephonyManager.isDataEnabled()
+ && telephonyManager.isApnMetered(ApnSetting.TYPE_MMS))
+ ? AVAILABLE
+ : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public void onStart() {
+ if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ mMobileDataContentObserver.register(mContext, mSubId);
+ }
+ }
+
+ @Override
+ public void onStop() {
+ if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ mMobileDataContentObserver.unRegister(mContext);
+ }
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ preference.setVisible(isAvailable());
+ ((SwitchPreference) preference).setChecked(isChecked());
+ }
+
+ public void init(int subId) {
+ mSubId = subId;
+ mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId);
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ return mSubscriptionManager.setAlwaysAllowMmsData(mSubId, isChecked);
+ }
+
+ @Override
+ public boolean isChecked() {
+ return mTelephonyManager.isDataEnabledForApn(ApnSetting.TYPE_MMS);
+ }
+}
diff --git a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
index de54879..a0e50fc 100644
--- a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
+++ b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
@@ -27,6 +27,7 @@
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import com.android.settings.network.MobileDataContentObserver;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
@@ -48,7 +49,7 @@
private SwitchPreference mPreference;
private TelephonyManager mTelephonyManager;
private SubscriptionManager mSubscriptionManager;
- private DataContentObserver mDataContentObserver;
+ private MobileDataContentObserver mDataContentObserver;
private FragmentManager mFragmentManager;
@VisibleForTesting
int mDialogType;
@@ -58,7 +59,8 @@
public MobileDataPreferenceController(Context context, String key) {
super(context, key);
mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
- mDataContentObserver = new DataContentObserver(new Handler(Looper.getMainLooper()));
+ mDataContentObserver = new MobileDataContentObserver(new Handler(Looper.getMainLooper()));
+ mDataContentObserver.setOnMobileDataChangedListener(()-> updateState(mPreference));
}
@Override
@@ -129,14 +131,6 @@
return info != null && info.isOpportunistic();
}
- public static Uri getObservableUri(int subId) {
- Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA);
- if (TelephonyManager.getDefault().getSimCount() != 1) {
- uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + subId);
- }
- return uri;
- }
-
public void init(FragmentManager fragmentManager, int subId) {
mFragmentManager = fragmentManager;
mSubId = subId;
@@ -170,30 +164,4 @@
mSubId);
dialogFragment.show(mFragmentManager, DIALOG_TAG);
}
-
- /**
- * Listener that listens mobile data state change.
- */
- public class DataContentObserver extends ContentObserver {
-
- public DataContentObserver(Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
- updateState(mPreference);
- }
-
- public void register(Context context, int subId) {
- final Uri uri = getObservableUri(subId);
- context.getContentResolver().registerContentObserver(uri, false, this);
-
- }
-
- public void unRegister(Context context) {
- context.getContentResolver().unregisterContentObserver(this);
- }
- }
}
diff --git a/src/com/android/settings/network/telephony/MobileDataSlice.java b/src/com/android/settings/network/telephony/MobileDataSlice.java
index 28cb11e..bf9fc04 100644
--- a/src/com/android/settings/network/telephony/MobileDataSlice.java
+++ b/src/com/android/settings/network/telephony/MobileDataSlice.java
@@ -39,6 +39,7 @@
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.network.AirplaneModePreferenceController;
+import com.android.settings.network.MobileDataContentObserver;
import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.slices.CustomSliceable;
import com.android.settings.slices.SliceBackgroundWorker;
@@ -267,7 +268,7 @@
}
public void register(Context context, int subId) {
- final Uri uri = MobileDataPreferenceController.getObservableUri(subId);
+ final Uri uri = MobileDataContentObserver.getObservableUri(subId);
context.getContentResolver().registerContentObserver(uri, false, this);
}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkActivity.java b/src/com/android/settings/network/telephony/MobileNetworkActivity.java
index 47eb66b..b8ed31f 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkActivity.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkActivity.java
@@ -40,6 +40,7 @@
import com.android.settings.core.FeatureFlags;
import com.android.settings.core.SettingsBaseActivity;
import com.android.settings.development.featureflags.FeatureFlagPersistent;
+import com.android.settings.network.SubscriptionUtil;
import com.google.android.material.bottomnavigation.BottomNavigationView;
@@ -165,7 +166,7 @@
final int subId = intent.getIntExtra(Settings.EXTRA_SUB_ID, SUB_ID_NULL);
if (subId != SUB_ID_NULL) {
for (SubscriptionInfo subscription :
- mSubscriptionManager.getSelectableSubscriptionInfoList()) {
+ SubscriptionUtil.getAvailableSubscriptions(this)) {
if (subscription.getSubscriptionId() == subId) {
return subscription;
}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index 3578792..db99258 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -136,6 +136,7 @@
use(MobileNetworkSwitchController.class).init(getLifecycle(), mSubId);
use(CarrierSettingsVersionPreferenceController.class).init(mSubId);
use(BillingCyclePreferenceController.class).init(mSubId);
+ use(MmsMessagePreferenceController.class).init(mSubId);
}
use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId);
use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId);
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java
index fd296ec..2037adc 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java
@@ -94,8 +94,9 @@
return;
}
final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
- mSubscriptionManager);
- if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID || subs.size() < 2) {
+ mContext);
+ if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID ||
+ mSubscriptionManager.isSubscriptionEnabled(mSubId) && subs.size() < 2) {
mSwitchBar.hide();
return;
}
diff --git a/src/com/android/settings/notification/ConfigureNotificationSettings.java b/src/com/android/settings/notification/ConfigureNotificationSettings.java
index 73f6e06..d9d2b9b 100644
--- a/src/com/android/settings/notification/ConfigureNotificationSettings.java
+++ b/src/com/android/settings/notification/ConfigureNotificationSettings.java
@@ -16,6 +16,8 @@
package com.android.settings.notification;
+import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
+
import android.app.Activity;
import android.app.Application;
import android.app.settings.SettingsEnums;
@@ -24,10 +26,13 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.SearchIndexableResource;
+import android.text.TextUtils;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.RingtonePreference;
@@ -62,10 +67,11 @@
static final String KEY_NOTIFICATION_ASSISTANT = "notification_assistant";
private static final String KEY_NOTI_DEFAULT_RINGTONE = "notification_default_ringtone";
-
- private RingtonePreference mRequestPreference;
private static final int REQUEST_CODE = 200;
private static final String SELECTED_PREFERENCE_KEY = "selected_preference";
+ private static final String KEY_ADVANCED_CATEGORY = "configure_notifications_advanced";
+
+ private RingtonePreference mRequestPreference;
@Override
public int getMetricsCategory() {
@@ -119,6 +125,27 @@
}
@Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ final PreferenceScreen screen = getPreferenceScreen();
+ final Bundle arguments = getArguments();
+
+ if (screen == null) {
+ return;
+ }
+ if (arguments != null) {
+ final String highlightKey = arguments.getString(EXTRA_FRAGMENT_ARG_KEY);
+ if (!TextUtils.isEmpty(highlightKey)) {
+ final PreferenceCategory advancedCategory =
+ screen.findPreference(KEY_ADVANCED_CATEGORY);
+ // Has highlight row - expand everything
+ advancedCategory.setInitialExpandedChildrenCount(Integer.MAX_VALUE);
+ scrollToPreference(advancedCategory);
+ }
+ }
+ }
+
+ @Override
public boolean onPreferenceTreeClick(Preference preference) {
if (preference instanceof RingtonePreference) {
mRequestPreference = (RingtonePreference) preference;
diff --git a/src/com/android/settings/sim/CallsSimListDialogFragment.java b/src/com/android/settings/sim/CallsSimListDialogFragment.java
index bb5a003..7d3de44 100644
--- a/src/com/android/settings/sim/CallsSimListDialogFragment.java
+++ b/src/com/android/settings/sim/CallsSimListDialogFragment.java
@@ -16,6 +16,7 @@
package com.android.settings.sim;
+import android.app.settings.SettingsEnums;
import android.content.Context;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
@@ -56,4 +57,9 @@
}
return result;
}
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.DIALOG_CALL_SIM_LIST;
+ }
}
diff --git a/src/com/android/settings/sim/PreferredSimDialogFragment.java b/src/com/android/settings/sim/PreferredSimDialogFragment.java
index 5b81e62..29f4c65 100644
--- a/src/com/android/settings/sim/PreferredSimDialogFragment.java
+++ b/src/com/android/settings/sim/PreferredSimDialogFragment.java
@@ -18,6 +18,7 @@
import android.app.Activity;
import android.app.Dialog;
+import android.app.settings.SettingsEnums;
import android.content.DialogInterface;
import android.os.Bundle;
import android.telephony.SubscriptionInfo;
@@ -98,4 +99,9 @@
protected SubscriptionManager getSubscriptionManager() {
return getContext().getSystemService(SubscriptionManager.class);
}
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.DIALOG_PREFERRED_SIM_PICKER;
+ }
}
diff --git a/src/com/android/settings/sim/SimDialogFragment.java b/src/com/android/settings/sim/SimDialogFragment.java
index 10815fd..de991ec 100644
--- a/src/com/android/settings/sim/SimDialogFragment.java
+++ b/src/com/android/settings/sim/SimDialogFragment.java
@@ -20,10 +20,11 @@
import android.os.Bundle;
import androidx.annotation.NonNull;
-import androidx.fragment.app.DialogFragment;
+
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
/** Common functionality for showing a dialog in SimDialogActivity. */
-public abstract class SimDialogFragment extends DialogFragment {
+public abstract class SimDialogFragment extends InstrumentedDialogFragment {
private static final String TAG = "SimDialogFragment";
private static final String KEY_TITLE_ID = "title_id";
diff --git a/src/com/android/settings/sim/SimListDialogFragment.java b/src/com/android/settings/sim/SimListDialogFragment.java
index f78c4e7..1802d65 100644
--- a/src/com/android/settings/sim/SimListDialogFragment.java
+++ b/src/com/android/settings/sim/SimListDialogFragment.java
@@ -17,6 +17,7 @@
package com.android.settings.sim;
import android.app.Dialog;
+import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
@@ -50,7 +51,7 @@
protected SelectSubscriptionAdapter mAdapter;
@VisibleForTesting
- List<SubscriptionInfo> mSubscriptions;
+ List<SubscriptionInfo> mSubscriptions;
public static SimListDialogFragment newInstance(int dialogType, int titleResId,
boolean includeAskEveryTime) {
@@ -122,6 +123,11 @@
builder.setAdapter(mAdapter, this);
}
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.DIALOG_SIM_LIST;
+ }
+
private static class SelectSubscriptionAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater mInflater;
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 56e4c30..4d3f230 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -469,13 +469,12 @@
return;
}
- // "forget" for normal saved network. And "disconnect" for ephemeral network because we
- // could only disconnect it and put it in blacklists so it won't be used again.
- if (mSelectedAccessPoint.isEphemeral()) {
- menu.add(Menu.NONE, MENU_ID_FORGET, 0 /* order */,
- R.string.wifi_disconnect_button_text);
- } else if (mSelectedAccessPoint.isSaved()) {
- menu.add(Menu.NONE, MENU_ID_FORGET, 0 /* order */, R.string.forget);
+ // "forget" for normal saved network. And "disconnect" for ephemeral network because it
+ // could only be disconnected and be put in blacklists so it won't be used again.
+ if (mSelectedAccessPoint.isSaved() || mSelectedAccessPoint.isEphemeral()) {
+ final int stringId = mSelectedAccessPoint.isEphemeral() ?
+ R.string.wifi_disconnect_button_text : R.string.forget;
+ menu.add(Menu.NONE, MENU_ID_FORGET, 0 /* order */, stringId);
}
if (mSelectedAccessPoint.isSaved() && !mSelectedAccessPoint.isActive()) {
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index ae96ed3..f98dc58 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -146,7 +146,8 @@
private static final long TIMEOUT = Duration.ofSeconds(10).toMillis();
// Be static to avoid too much object not be reset.
- private static CountDownTimer mTimer;
+ @VisibleForTesting
+ static CountDownTimer mTimer;
private AccessPoint mAccessPoint;
private final ConnectivityManager mConnectivityManager;
@@ -256,20 +257,15 @@
@Override
public void onLost(Network network) {
- final boolean lostCurrentNetwork = network.equals(mNetwork);
- if (lostCurrentNetwork) {
- // Should update as disconnect but not exit. Except for ephemeral network which
- // should not show on saved network list.
- if (!mIsEphemeral) {
- return;
- }
-
+ // Ephemeral network not a saved network, leave detail page once disconnected
+ if (mIsEphemeral && network.equals(mNetwork)) {
exitActivity();
}
}
};
- private final WifiTracker.WifiListener mWifiListener = new WifiTracker.WifiListener() {
+ @VisibleForTesting
+ final WifiTracker.WifiListener mWifiListener = new WifiTracker.WifiListener() {
/** Called when the state of Wifi has changed. */
public void onWifiStateChanged(int state) {
Log.d(TAG, "onWifiStateChanged(" + state + ")");
@@ -284,16 +280,7 @@
/** Called when the connection state of wifi has changed. */
public void onConnectedChanged() {
- updateAccessPointFromScannedList();
- if (mConnected != mAccessPoint.isActive()) {
- Log.d(TAG, "Connection state changed!");
- mConnected = mAccessPoint.isActive();
- if (mAccessPoint.isActive()) {
- updateConnectingState(STATE_CONNECTED);
- } else {
- updateConnectingState(STATE_DISCONNECTED);
- }
- }
+ refreshPage();
}
/**
@@ -516,42 +503,41 @@
refreshMacAddress();
}
- private boolean updateAccessPoint() {
+ @VisibleForTesting
+ boolean updateAccessPoint() {
boolean changed = false;
- if (mWifiTracker != null) {
- // remember mIsOutOfRange as old before updated
- boolean oldState = mIsOutOfRange;
- updateAccessPointFromScannedList();
- // refresh UI if signal level changed for disconnect network.
- changed = mRssiSignalLevel != mAccessPoint.getLevel();
- changed |= oldState != mIsOutOfRange;
- }
+ // remember mIsOutOfRange as old before updated
+ boolean oldState = mIsOutOfRange;
+ updateAccessPointFromScannedList();
if (mAccessPoint.isActive()) {
- // Sometimes {@link WifiManager#getCurrentNetwork()} return null after connected,
- // refresh it if needed.
- if (mNetwork == null) {
- updateNetworkInfo();
- }
+ updateNetworkInfo();
mNetworkInfo = mConnectivityManager.getNetworkInfo(mNetwork);
mWifiInfo = mWifiManager.getConnectionInfo();
if (mNetwork == null || mNetworkInfo == null || mWifiInfo == null) {
- // Once connected, can't get mNetworkInfo immediately, return false and wait for
- // next time to update UI.
+ // Once connected, can't get mNetwork immediately, return false and wait for
+ // next time to update UI. also reset {@code mIsOutOfRange}
+ mIsOutOfRange = oldState;
return false;
}
-
changed |= mAccessPoint.update(mWifiConfig, mWifiInfo, mNetworkInfo);
- // If feature for saved network not enabled, always return true.
- return mWifiTracker == null || changed;
+ }
+
+ // signal level changed
+ changed |= mRssiSignalLevel != mAccessPoint.getLevel();
+ // In/Out of range changed
+ changed |= oldState != mIsOutOfRange;
+ // connect state changed
+ if (mConnected != mAccessPoint.isActive()) {
+ mConnected = mAccessPoint.isActive();
+ changed = true;
+ updateConnectingState(mAccessPoint.isActive() ? STATE_CONNECTED : STATE_DISCONNECTED);
}
return changed;
}
private void updateAccessPointFromScannedList() {
- if (mWifiTracker == null) return;
-
mIsOutOfRange = true;
for (AccessPoint ap : mWifiTracker.getAccessPoints()) {
@@ -899,13 +885,19 @@
/**
* Show QR code to share the network represented by this preference.
*/
- public void launchWifiDppConfiguratorActivity() {
+ private void launchWifiDppConfiguratorActivity() {
final Intent intent = WifiDppUtils.getConfiguratorQrCodeGeneratorIntentOrNull(mContext,
mWifiManager, mAccessPoint);
if (intent == null) {
Log.e(TAG, "Launch Wi-Fi DPP QR code generator with a wrong Wi-Fi network!");
} else {
+ mMetricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN,
+ SettingsEnums.ACTION_SETTINGS_SHARE_WIFI_QR_CODE,
+ SettingsEnums.SETTINGS_WIFI_DPP_CONFIGURATOR,
+ /* key */ null,
+ /* value */ Integer.MIN_VALUE);
+
mContext.startActivity(intent);
}
}
@@ -967,7 +959,8 @@
return FeatureFlagUtils.isEnabled(context, FeatureFlags.WIFI_DETAILS_DATAUSAGE_HEADER);
}
- private void connectNetwork() {
+ @VisibleForTesting
+ void connectNetwork() {
final Activity activity = mFragment.getActivity();
// error handling, connected/saved network should have mWifiConfig.
if (mWifiConfig == null) {
@@ -1045,7 +1038,6 @@
mAccessPoint.getTitle()),
Toast.LENGTH_SHORT).show();
- updateNetworkInfo();
refreshPage();
} else if (state == STATE_NOT_IN_RANGE) {
Log.d(TAG, "AP not in range");
@@ -1084,7 +1076,11 @@
.setButton3Enabled(false);
break;
case STATE_CONNECTED:
- mButtonsPref.setButton3Visible(false);
+ // init button state and set as invisible
+ mButtonsPref.setButton3Text(R.string.wifi_connect)
+ .setButton3Icon(R.drawable.ic_settings_wireless)
+ .setButton3Enabled(true)
+ .setButton3Visible(false);
break;
case STATE_DISCONNECTED:
case STATE_NOT_IN_RANGE:
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
index d0322b7..0cd7f09 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
@@ -193,6 +193,13 @@
return;
}
+ mMetricsFeatureProvider.action(
+ mMetricsFeatureProvider.getAttribution(getActivity()),
+ SettingsEnums.ACTION_SETTINGS_ENROLL_WIFI_QR_CODE,
+ SettingsEnums.SETTINGS_WIFI_DPP_ENROLLEE,
+ /* key */ null,
+ /* value */ Integer.MIN_VALUE);
+
notifyUserForQrCodeRecognition();
break;
diff --git a/src/com/android/settings/wifi/slice/ConnectToWifiHandler.java b/src/com/android/settings/wifi/slice/ConnectToWifiHandler.java
index ee15820..f1b0b6f 100644
--- a/src/com/android/settings/wifi/slice/ConnectToWifiHandler.java
+++ b/src/com/android/settings/wifi/slice/ConnectToWifiHandler.java
@@ -43,17 +43,21 @@
WifiDialogActivity.KEY_ACCESS_POINT_STATE);
if (network != null) {
+ WifiScanWorker.clearClickedWifi();
final ConnectivityManager cm = getSystemService(ConnectivityManager.class);
// start captive portal app to sign in to network
cm.startCaptivePortalApp(network);
} else if (accessPointState != null) {
connect(new AccessPoint(this, accessPointState));
}
+
finish();
}
@VisibleForTesting
void connect(AccessPoint accessPoint) {
+ WifiScanWorker.saveClickedWifi(accessPoint);
+
final WifiConnectListener connectListener = new WifiConnectListener(this);
switch (WifiUtils.getConnectingType(accessPoint)) {
case WifiUtils.CONNECT_TYPE_OSU_PROVISION:
diff --git a/src/com/android/settings/wifi/slice/WifiScanWorker.java b/src/com/android/settings/wifi/slice/WifiScanWorker.java
index b846228..e438443 100644
--- a/src/com/android/settings/wifi/slice/WifiScanWorker.java
+++ b/src/com/android/settings/wifi/slice/WifiScanWorker.java
@@ -20,6 +20,7 @@
import static com.android.settings.wifi.slice.WifiSlice.DEFAULT_EXPANDED_ROW_COUNT;
import android.content.Context;
+import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
@@ -27,9 +28,12 @@
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.Uri;
+import android.net.wifi.WifiInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -55,22 +59,21 @@
CaptivePortalNetworkCallback mCaptivePortalNetworkCallback;
private final Context mContext;
+ private final ConnectivityManager mConnectivityManager;
+ private final WifiTracker mWifiTracker;
- private WifiTracker mWifiTracker;
- private ConnectivityManager mConnectivityManager;
+ private static String sClickedWifiSsid;
public WifiScanWorker(Context context, Uri uri) {
super(context, uri);
mContext = context;
mConnectivityManager = context.getSystemService(ConnectivityManager.class);
+ mWifiTracker = new WifiTracker(mContext, this /* wifiListener */,
+ true /* includeSaved */, true /* includeScans */);
}
@Override
protected void onSlicePinned() {
- if (mWifiTracker == null) {
- mWifiTracker = new WifiTracker(mContext, this /* wifiListener */,
- true /* includeSaved */, true /* includeScans */);
- }
mWifiTracker.onStart();
onAccessPointsChanged();
}
@@ -79,6 +82,7 @@
protected void onSliceUnpinned() {
mWifiTracker.onStop();
unregisterCaptivePortalNetworkCallback();
+ clearClickedWifi();
}
@Override
@@ -146,6 +150,19 @@
return null;
}
+ static void saveClickedWifi(AccessPoint accessPoint) {
+ sClickedWifiSsid = accessPoint.getSsidStr();
+ }
+
+ static void clearClickedWifi() {
+ sClickedWifiSsid = null;
+ }
+
+ static boolean isWifiClicked(WifiInfo info) {
+ final String ssid = WifiInfo.removeDoubleQuotes(info.getSSID());
+ return !TextUtils.isEmpty(ssid) && TextUtils.equals(ssid, sClickedWifiSsid);
+ }
+
public void registerCaptivePortalNetworkCallback(Network wifiNetwork) {
if (wifiNetwork == null) {
return;
@@ -191,7 +208,7 @@
@Override
public void onCapabilitiesChanged(Network network,
NetworkCapabilities networkCapabilities) {
- if (!mNetwork.equals(network)) {
+ if (!isSameNetwork(network)) {
return;
}
@@ -202,6 +219,19 @@
mIsCaptivePortal = isCaptivePortal;
notifySliceChange();
+
+ // Automatically start captive portal
+ if (mIsCaptivePortal) {
+ if (!isWifiClicked(mWifiTracker.getManager().getConnectionInfo())) {
+ return;
+ }
+
+ final Intent intent = new Intent(mContext, ConnectToWifiHandler.class)
+ .putExtra(ConnectivityManager.EXTRA_NETWORK, network)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ // Starting activity in the system process needs to specify a user
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ }
}
/**
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
index b7ddcae..1197db4 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSSIDPreferenceController.java
@@ -16,6 +16,7 @@
package com.android.settings.wifi.tether;
+import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiConfiguration;
@@ -27,9 +28,12 @@
import androidx.preference.Preference;
import com.android.settings.R;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.ValidatedEditTextPreference;
import com.android.settings.wifi.dpp.WifiDppUtils;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
public class WifiTetherSSIDPreferenceController extends WifiTetherBasePreferenceController
implements ValidatedEditTextPreference.Validator {
@@ -41,10 +45,14 @@
private String mSSID;
private WifiDeviceNameTextValidator mWifiDeviceNameTextValidator;
+ private final MetricsFeatureProvider mMetricsFeatureProvider;
+
public WifiTetherSSIDPreferenceController(Context context,
OnTetherConfigUpdateListener listener) {
super(context, listener);
+
mWifiDeviceNameTextValidator = new WifiDeviceNameTextValidator();
+ mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
}
@Override
@@ -104,7 +112,15 @@
}
private void shareHotspotNetwork(Intent intent) {
- WifiDppUtils.showLockScreen(mContext, () -> mContext.startActivity(intent));
+ WifiDppUtils.showLockScreen(mContext, () -> {
+ mMetricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN,
+ SettingsEnums.ACTION_SETTINGS_SHARE_WIFI_HOTSPOT_QR_CODE,
+ SettingsEnums.SETTINGS_WIFI_DPP_CONFIGURATOR,
+ /* key */ null,
+ /* value */ Integer.MIN_VALUE);
+
+ mContext.startActivity(intent);
+ });
}
@VisibleForTesting
diff --git a/tests/robotests/assets/grandfather_slice_controller_not_in_xml b/tests/robotests/assets/grandfather_slice_controller_not_in_xml
index d2274e6..4bc4339 100644
--- a/tests/robotests/assets/grandfather_slice_controller_not_in_xml
+++ b/tests/robotests/assets/grandfather_slice_controller_not_in_xml
@@ -2,3 +2,4 @@
com.android.settings.testutils.FakeSliderController
com.android.settings.core.TogglePreferenceControllerTest$FakeToggle
com.android.settings.accessibility.AccessibilitySlicePreferenceController
+com.android.settings.network.telephony.MmsMessagePreferenceController
diff --git a/tests/robotests/res/values/overlayable_icons_test.xml b/tests/robotests/res/values/overlayable_icons_test.xml
new file mode 100644
index 0000000..575f798
--- /dev/null
+++ b/tests/robotests/res/values/overlayable_icons_test.xml
@@ -0,0 +1,88 @@
+<!--
+ 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.
+-->
+<resources>
+ <!-- overlayable_icons references all of the drawables in this package
+ that are being overlayed by resource overlays. If you remove/rename
+ any of these resources, you must also change the resource overlay icons.-->
+ <array name="overlayable_icons">
+ <item>@drawable/drag_handle</item>
+ <item>@drawable/ic_add_24dp</item>
+ <item>@drawable/ic_airplanemode_active</item>
+ <item>@drawable/ic_android</item>
+ <item>@drawable/ic_apps</item>
+ <item>@drawable/ic_arrow_back</item>
+ <item>@drawable/ic_battery_charging_full</item>
+ <item>@drawable/ic_battery_saver_accent_24dp</item>
+ <item>@drawable/ic_battery_status_bad_24dp</item>
+ <item>@drawable/ic_battery_status_good_24dp</item>
+ <item>@drawable/ic_battery_status_maybe_24dp</item>
+ <item>@drawable/ic_call_24dp</item>
+ <item>@drawable/ic_cancel</item>
+ <item>@drawable/ic_cast_24dp</item>
+ <item>@drawable/ic_cellular_off</item>
+ <item>@drawable/ic_content_copy_grey600_24dp</item>
+ <item>@drawable/ic_data_saver</item>
+ <item>@drawable/ic_delete</item>
+ <item>@drawable/ic_delete_accent</item>
+ <item>@drawable/ic_devices_other</item>
+ <item>@drawable/ic_devices_other_opaque_black</item>
+ <item>@drawable/ic_do_not_disturb_on_24dp</item>
+ <item>@drawable/ic_eject_24dp</item>
+ <item>@drawable/ic_expand_less</item>
+ <item>@drawable/ic_expand_more_inverse</item>
+ <item>@drawable/ic_folder_vd_theme_24</item>
+ <item>@drawable/ic_friction_lock_closed</item>
+ <item>@drawable/ic_gray_scale_24dp</item>
+ <item>@drawable/ic_headset_24dp</item>
+ <item>@drawable/ic_help</item>
+ <item>@drawable/ic_homepage_search</item>
+ <item>@drawable/ic_local_movies</item>
+ <item>@drawable/ic_local_phone_24_lib</item>
+ <item>@drawable/ic_lock</item>
+ <item>@drawable/ic_media_stream</item>
+ <item>@drawable/ic_media_stream_off</item>
+ <item>@drawable/ic_network_cell</item>
+ <item>@drawable/ic_notifications</item>
+ <item>@drawable/ic_notifications_off_24dp</item>
+ <item>@drawable/ic_phone_info</item>
+ <item>@drawable/ic_photo_library</item>
+ <item>@drawable/ic_settings_accessibility</item>
+ <item>@drawable/ic_settings_accounts</item>
+ <item>@drawable/ic_settings_battery_white</item>
+ <item>@drawable/ic_settings_data_usage</item>
+ <item>@drawable/ic_settings_date_time</item>
+ <item>@drawable/ic_settings_delete</item>
+ <item>@drawable/ic_settings_display_white</item>
+ <item>@drawable/ic_settings_home</item>
+ <item>@drawable/ic_settings_location</item>
+ <item>@drawable/ic_settings_night_display</item>
+ <item>@drawable/ic_settings_open</item>
+ <item>@drawable/ic_settings_print</item>
+ <item>@drawable/ic_settings_privacy</item>
+ <item>@drawable/ic_settings_security_white</item>
+ <item>@drawable/ic_settings_sim</item>
+ <item>@drawable/ic_settings_system_dashboard_white</item>
+ <item>@drawable/ic_settings_wireless</item>
+ <item>@drawable/ic_settings_wireless_white</item>
+ <item>@drawable/ic_storage_white</item>
+ <item>@drawable/ic_suggestion_night_display</item>
+ <item>@drawable/ic_videogame_vd_theme_24</item>
+ <item>@drawable/ic_volume_ringer_vibrate</item>
+ <item>@drawable/ic_volume_up_24dp</item>
+ <item>@drawable/ic_vpn_key</item>
+ <item>@drawable/ic_wifi_tethering</item>
+ </array>
+</resources>
diff --git a/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java
index cf4cb7c..d98d30a 100644
--- a/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java
@@ -144,7 +144,7 @@
}
@Test
- public void onClick_shouldNotStartConfirmDialogWhenModifyAccountsIsDisallowed() {
+ public void onClick_modifyAccountsIsDisallowed_shouldNotStartConfirmDialog() {
when(mFragment.isAdded()).thenReturn(true);
final int userId = UserHandle.myUserId();
@@ -195,7 +195,41 @@
Bundle resultBundle = new Bundle();
resultBundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
when(future.getResult()).thenReturn(resultBundle);
+
callback.run(future);
verify(activity).finish();
}
+
+ @Test
+ @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
+ public void confirmRemove_activityGone_shouldSilentlyRemoveAccount()
+ throws AuthenticatorException, OperationCanceledException, IOException {
+ final Account account = new Account("Account11", "com.acct1");
+ final UserHandle userHandle = new UserHandle(10);
+ final FragmentActivity activity = mock(FragmentActivity.class);
+ when(mFragment.isAdded()).thenReturn(true);
+ when(activity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
+ when(mFragment.getActivity()).thenReturn(activity).thenReturn(null);
+
+ final RemoveAccountPreferenceController.ConfirmRemoveAccountDialog dialog =
+ RemoveAccountPreferenceController.ConfirmRemoveAccountDialog.show(
+ mFragment, account, userHandle);
+ dialog.onCreate(new Bundle());
+ dialog.onClick(null, 0);
+
+ ArgumentCaptor<AccountManagerCallback<Bundle>> callbackCaptor = ArgumentCaptor.forClass(
+ AccountManagerCallback.class);
+ verify(mAccountManager).removeAccountAsUser(eq(account), nullable(Activity.class),
+ callbackCaptor.capture(), nullable(Handler.class), eq(userHandle));
+
+ AccountManagerCallback<Bundle> callback = callbackCaptor.getValue();
+ assertThat(callback).isNotNull();
+ AccountManagerFuture<Bundle> future = mock(AccountManagerFuture.class);
+ Bundle resultBundle = new Bundle();
+ resultBundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+ when(future.getResult()).thenReturn(resultBundle);
+
+ callback.run(future);
+ verify(activity, never()).finish();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java
index 23754a0..946d639 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceGroupControllerTest.java
@@ -88,6 +88,7 @@
mPreferenceGroup = spy(new PreferenceScreen(mContext, null));
when(mPreferenceGroup.getPreferenceManager()).thenReturn(mPreferenceManager);
doReturn(mContext).when(mDashboardFragment).getContext();
+ mPackageManager.setSystemFeature(PackageManager.FEATURE_BLUETOOTH, true);
mConnectedDeviceGroupController = new ConnectedDeviceGroupController(mContext);
mConnectedDeviceGroupController.init(mConnectedBluetoothDeviceUpdater,
@@ -153,8 +154,12 @@
}
@Test
- public void getAvailabilityStatus_noBluetoothFeature_returnUnSupported() {
+ public void getAvailabilityStatus_noBluetoothUsbDockFeature_returnUnSupported() {
mPackageManager.setSystemFeature(PackageManager.FEATURE_BLUETOOTH, false);
+ mPackageManager.setSystemFeature(PackageManager.FEATURE_USB_ACCESSORY, false);
+ mPackageManager.setSystemFeature(PackageManager.FEATURE_USB_HOST, false);
+ mConnectedDeviceGroupController.init(mConnectedBluetoothDeviceUpdater,
+ mConnectedUsbDeviceUpdater, null);
assertThat(mConnectedDeviceGroupController.getAvailabilityStatus()).isEqualTo(
UNSUPPORTED_ON_DEVICE);
@@ -163,8 +168,37 @@
@Test
public void getAvailabilityStatus_BluetoothFeature_returnSupported() {
mPackageManager.setSystemFeature(PackageManager.FEATURE_BLUETOOTH, true);
+ mPackageManager.setSystemFeature(PackageManager.FEATURE_USB_ACCESSORY, false);
+ mPackageManager.setSystemFeature(PackageManager.FEATURE_USB_HOST, false);
+ mConnectedDeviceGroupController.init(mConnectedBluetoothDeviceUpdater,
+ mConnectedUsbDeviceUpdater, null);
assertThat(mConnectedDeviceGroupController.getAvailabilityStatus()).isEqualTo(
AVAILABLE_UNSEARCHABLE);
}
+
+ @Test
+ public void getAvailabilityStatus_haveUsbFeature_returnSupported() {
+ mPackageManager.setSystemFeature(PackageManager.FEATURE_BLUETOOTH, false);
+ mPackageManager.setSystemFeature(PackageManager.FEATURE_USB_ACCESSORY, false);
+ mPackageManager.setSystemFeature(PackageManager.FEATURE_USB_HOST, true);
+ mConnectedDeviceGroupController.init(mConnectedBluetoothDeviceUpdater,
+ mConnectedUsbDeviceUpdater, null);
+
+ assertThat(mConnectedDeviceGroupController.getAvailabilityStatus()).isEqualTo(
+ AVAILABLE_UNSEARCHABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_haveDockFeature_returnSupported() {
+ mPackageManager.setSystemFeature(PackageManager.FEATURE_BLUETOOTH, false);
+ mPackageManager.setSystemFeature(PackageManager.FEATURE_USB_ACCESSORY, false);
+ mPackageManager.setSystemFeature(PackageManager.FEATURE_USB_HOST, false);
+ mConnectedDeviceGroupController.init(mConnectedBluetoothDeviceUpdater,
+ mConnectedUsbDeviceUpdater, mConnectedDockUpdater);
+
+ assertThat(mConnectedDeviceGroupController.getAvailabilityStatus()).isEqualTo(
+ AVAILABLE_UNSEARCHABLE);
+ }
+
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java
index 48f734d..90cbea9 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java
@@ -95,19 +95,32 @@
}
@Test
- public void getAvailabilityStatus_noBluetoothFeature_returnUnSupported() {
+ public void getAvailabilityStatus_noBluetoothDockFeature_returnUnSupported() {
doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
+ mPreConnectedDeviceController.setSavedDockUpdater(null);
+
assertThat(mPreConnectedDeviceController.getAvailabilityStatus()).isEqualTo(
CONDITIONALLY_UNAVAILABLE);
}
+
@Test
public void getAvailabilityStatus_hasBluetoothFeature_returnSupported() {
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
+ mPreConnectedDeviceController.setSavedDockUpdater(null);
+
assertThat(mPreConnectedDeviceController.getAvailabilityStatus()).isEqualTo(
AVAILABLE);
}
@Test
+ public void getAvailabilityStatus_haveDockFeature_returnSupported() {
+ doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
+
+ assertThat(mPreConnectedDeviceController.getAvailabilityStatus()).isEqualTo(
+ AVAILABLE);
+ }
+
+ @Test
public void onDeviceAdded_addDevicePreference_displayIt() {
mPreConnectedDeviceController.onDeviceAdded(new Preference(mContext));
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/SavedDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/SavedDeviceGroupControllerTest.java
index c386719..6c6cf47 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/SavedDeviceGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/SavedDeviceGroupControllerTest.java
@@ -23,6 +23,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -81,6 +82,7 @@
verify(mBluetoothDeviceUpdater).registerCallback();
verify(mSavedDockUpdater).registerCallback();
}
+
@Test
public void testUnregister() {
// unregister the callback in onStop()
@@ -88,16 +90,30 @@
verify(mBluetoothDeviceUpdater).unregisterCallback();
verify(mSavedDockUpdater).unregisterCallback();
}
+
@Test
- public void testGetAvailabilityStatus_noBluetoothFeature_returnUnSupported() {
+ public void testGetAvailabilityStatus_noBluetoothDockFeature_returnUnSupported() {
doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
+ mSavedDeviceGroupController.setSavedDockUpdater(null);
+
assertThat(mSavedDeviceGroupController.getAvailabilityStatus()).isEqualTo(
UNSUPPORTED_ON_DEVICE);
}
+
@Test
public void testGetAvailabilityStatus_BluetoothFeature_returnSupported() {
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
+ mSavedDeviceGroupController.setSavedDockUpdater(null);
+
assertThat(mSavedDeviceGroupController.getAvailabilityStatus()).isEqualTo(
AVAILABLE);
}
+
+ @Test
+ public void getAvailabilityStatus_haveDockFeature_returnSupported() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)).thenReturn(false);
+
+ assertThat(mSavedDeviceGroupController.getAvailabilityStatus()).isEqualTo(
+ AVAILABLE);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/core/codeinspection/CodeInspectionTest.java b/tests/robotests/src/com/android/settings/core/codeinspection/CodeInspectionTest.java
index 5fdadb4..ccc8cbd 100644
--- a/tests/robotests/src/com/android/settings/core/codeinspection/CodeInspectionTest.java
+++ b/tests/robotests/src/com/android/settings/core/codeinspection/CodeInspectionTest.java
@@ -24,12 +24,11 @@
import com.android.settings.slices.SliceControllerInXmlCodeInspector;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
import java.util.List;
-import org.robolectric.RobolectricTestRunner;
/**
* Test suite that scans all classes in app package, and performs different types of code inspection
@@ -47,7 +46,6 @@
}
@Test
- @Ignore("b/130897640")
public void runInstrumentableFragmentCodeInspection() {
new InstrumentableFragmentCodeInspector(mClasses).run();
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
index f025ee8..c2a3aa9 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardLoaderTest.java
@@ -16,8 +16,6 @@
package com.android.settings.homepage.contextualcards;
-import static android.app.slice.Slice.HINT_ERROR;
-
import static com.android.settings.homepage.contextualcards.ContextualCardLoader.DEFAULT_CARD_COUNT;
import static com.google.common.truth.Truth.assertThat;
@@ -34,8 +32,6 @@
import android.content.Context;
import android.net.Uri;
-import androidx.slice.Slice;
-
import com.android.settings.R;
import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.testutils.FakeFeatureFactory;
@@ -53,74 +49,18 @@
@RunWith(RobolectricTestRunner.class)
public class ContextualCardLoaderTest {
- private static final String TEST_SLICE_URI = "content://test/test";
-
private Context mContext;
private ContextualCardLoader mContextualCardLoader;
- private EligibleCardChecker mEligibleCardChecker;
private FakeFeatureFactory mFakeFeatureFactory;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mContextualCardLoader = spy(new ContextualCardLoader(mContext));
- mEligibleCardChecker =
- spy(new EligibleCardChecker(mContext, getContextualCard(TEST_SLICE_URI)));
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
}
@Test
- public void isCardEligibleToDisplay_customCard_returnTrue() {
- final ContextualCard customCard = new ContextualCard.Builder()
- .setName("custom_card")
- .setCardType(ContextualCard.CardType.DEFAULT)
- .setTitleText("custom_title")
- .setSummaryText("custom_summary")
- .build();
-
- assertThat(mEligibleCardChecker.isCardEligibleToDisplay(customCard)).isTrue();
- }
-
- @Test
- public void isCardEligibleToDisplay_invalidScheme_returnFalse() {
- final String sliceUri = "contet://com.android.settings.slices/action/flashlight";
-
- assertThat(mEligibleCardChecker.isCardEligibleToDisplay(getContextualCard(sliceUri)))
- .isFalse();
- }
-
- @Test
- public void isCardEligibleToDisplay_invalidRankingScore_returnFalse() {
- final ContextualCard card = new ContextualCard.Builder()
- .setName("test_card")
- .setCardType(ContextualCard.CardType.SLICE)
- .setSliceUri(CustomSliceRegistry.FLASHLIGHT_SLICE_URI)
- .setRankingScore(-1)
- .build();
-
- assertThat(mEligibleCardChecker.isCardEligibleToDisplay(card))
- .isFalse();
- }
-
- @Test
- public void isCardEligibleToDisplay_nullSlice_returnFalse() {
- doReturn(null).when(mEligibleCardChecker).bindSlice(Uri.parse(TEST_SLICE_URI));
-
- assertThat(mEligibleCardChecker.isCardEligibleToDisplay(getContextualCard(TEST_SLICE_URI)))
- .isFalse();
- }
-
- @Test
- public void isCardEligibleToDisplay_errorSlice_returnFalse() {
- final Slice slice = new Slice.Builder(Uri.parse(TEST_SLICE_URI))
- .addHints(HINT_ERROR).build();
- doReturn(slice).when(mEligibleCardChecker).bindSlice(Uri.parse(TEST_SLICE_URI));
-
- assertThat(mEligibleCardChecker.isCardEligibleToDisplay(getContextualCard(TEST_SLICE_URI)))
- .isFalse();
- }
-
- @Test
public void getDisplayableCards_twoEligibleCards_shouldShowAll() {
final List<ContextualCard> cards = getContextualCardList().stream().limit(2)
.collect(Collectors.toList());
@@ -201,15 +141,6 @@
eq(SettingsEnums.ACTION_CONTEXTUAL_CARD_SHOW), any(String.class));
}
- private ContextualCard getContextualCard(String sliceUri) {
- return new ContextualCard.Builder()
- .setName("test_card")
- .setRankingScore(0.5)
- .setCardType(ContextualCard.CardType.SLICE)
- .setSliceUri(Uri.parse(sliceUri))
- .build();
- }
-
private List<ContextualCard> getContextualCardList() {
final List<ContextualCard> cards = new ArrayList<>();
cards.add(new ContextualCard.Builder()
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardsDiffCallbackTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardsDiffCallbackTest.java
new file mode 100644
index 0000000..eb95f71
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardsDiffCallbackTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.settings.homepage.contextualcards;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.net.Uri;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+public class ContextualCardsDiffCallbackTest {
+
+ private static final Uri TEST_SLICE_URI = Uri.parse("content://test/test");
+
+ private ContextualCardsDiffCallback mDiffCallback;
+ private List<ContextualCard> mOldCards;
+ private List<ContextualCard> mNewCards;
+
+ @Before
+ public void setUp() {
+ mOldCards = new ArrayList<>();
+ mNewCards = new ArrayList<>();
+ mOldCards.add(getContextualCard("test1"));
+ mNewCards.add(getContextualCard("test1"));
+ mNewCards.add(getContextualCard("test2"));
+ mDiffCallback = new ContextualCardsDiffCallback(mOldCards, mNewCards);
+ }
+
+ @Test
+ public void getOldListSize_oneCard_returnOne() {
+ assertThat(mDiffCallback.getOldListSize()).isEqualTo(1);
+ }
+
+ @Test
+ public void getNewListSize_twoCards_returnTwo() {
+ assertThat(mDiffCallback.getNewListSize()).isEqualTo(2);
+ }
+
+ @Test
+ public void areItemsTheSame_sameItems_returnTrue() {
+ assertThat(mDiffCallback.areItemsTheSame(0, 0)).isTrue();
+ }
+
+ @Test
+ public void areItemsTheSame_differentItems_returnFalse() {
+ mOldCards.add(getContextualCard("test3"));
+
+ assertThat(mDiffCallback.areItemsTheSame(1, 1)).isFalse();
+ }
+
+ @Test
+ public void areContentsTheSame_sameContents_returnTrue() {
+ assertThat(mDiffCallback.areContentsTheSame(0, 0)).isTrue();
+ }
+
+ @Test
+ public void areContentsTheSame_sliceWithToggle_returnFalse() {
+ final ContextualCard card = getContextualCard("test1").mutate()
+ .setHasInlineAction(true).build();
+ mNewCards.add(0, card);
+
+ assertThat(mDiffCallback.areContentsTheSame(0, 0)).isFalse();
+ }
+
+ private ContextualCard getContextualCard(String name) {
+ return new ContextualCard.Builder()
+ .setName(name)
+ .setRankingScore(0.5)
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(TEST_SLICE_URI)
+ .build();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/EligibleCardCheckerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/EligibleCardCheckerTest.java
new file mode 100644
index 0000000..7b70dad
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/EligibleCardCheckerTest.java
@@ -0,0 +1,157 @@
+/*
+ * 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.settings.homepage.contextualcards;
+
+import static android.app.slice.Slice.HINT_ERROR;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.net.Uri;
+
+import androidx.slice.Slice;
+import androidx.slice.SliceProvider;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.settings.homepage.contextualcards.deviceinfo.EmergencyInfoSlice;
+import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.wifi.slice.ContextualWifiSlice;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class EligibleCardCheckerTest {
+
+ private static final Uri TEST_SLICE_URI = Uri.parse("content://test/test");
+
+ private Context mContext;
+ private EligibleCardChecker mEligibleCardChecker;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mEligibleCardChecker =
+ spy(new EligibleCardChecker(mContext, getContextualCard(TEST_SLICE_URI)));
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ }
+
+ @Test
+ public void isSliceToggleable_cardWithToggle_returnTrue() {
+ final ContextualWifiSlice wifiSlice = new ContextualWifiSlice(mContext);
+ final Slice slice = wifiSlice.getSlice();
+
+ assertThat(mEligibleCardChecker.isSliceToggleable(slice)).isTrue();
+ }
+
+ @Test
+ public void isSliceToggleable_cardWithoutToggle_returnFalse() {
+ final EmergencyInfoSlice emergencyInfoSlice = new EmergencyInfoSlice(mContext);
+ final Slice slice = emergencyInfoSlice.getSlice();
+
+ assertThat(mEligibleCardChecker.isSliceToggleable(slice)).isFalse();
+ }
+
+ @Test
+ public void isCardEligibleToDisplay_toggleSlice_hasInlineActionShouldBeTrue() {
+ final ContextualWifiSlice wifiSlice = new ContextualWifiSlice(mContext);
+ final Slice slice = wifiSlice.getSlice();
+ doReturn(slice).when(mEligibleCardChecker).bindSlice(any(Uri.class));
+
+ mEligibleCardChecker.isCardEligibleToDisplay(getContextualCard(TEST_SLICE_URI));
+
+ assertThat(mEligibleCardChecker.mCard.hasInlineAction()).isTrue();
+ }
+
+ @Test
+ public void isCardEligibleToDisplay_notToggleSlice_hasInlineActionShouldBeFalse() {
+ final EmergencyInfoSlice emergencyInfoSlice = new EmergencyInfoSlice(mContext);
+ final Slice slice = emergencyInfoSlice.getSlice();
+ doReturn(slice).when(mEligibleCardChecker).bindSlice(any(Uri.class));
+
+ mEligibleCardChecker.isCardEligibleToDisplay(getContextualCard(TEST_SLICE_URI));
+
+ assertThat(mEligibleCardChecker.mCard.hasInlineAction()).isFalse();
+ }
+
+ @Test
+ public void isCardEligibleToDisplay_customCard_returnTrue() {
+ final ContextualCard customCard = new ContextualCard.Builder()
+ .setName("custom_card")
+ .setCardType(ContextualCard.CardType.DEFAULT)
+ .setTitleText("custom_title")
+ .setSummaryText("custom_summary")
+ .build();
+
+ assertThat(mEligibleCardChecker.isCardEligibleToDisplay(customCard)).isTrue();
+ }
+
+ @Test
+ public void isCardEligibleToDisplay_invalidScheme_returnFalse() {
+ final Uri sliceUri = Uri.parse("contet://com.android.settings.slices/action/flashlight");
+
+ assertThat(mEligibleCardChecker.isCardEligibleToDisplay(getContextualCard(sliceUri)))
+ .isFalse();
+ }
+
+ @Test
+ public void isCardEligibleToDisplay_invalidRankingScore_returnFalse() {
+ final ContextualCard card = new ContextualCard.Builder()
+ .setName("test_card")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(CustomSliceRegistry.FLASHLIGHT_SLICE_URI)
+ .setRankingScore(-1)
+ .build();
+
+ assertThat(mEligibleCardChecker.isCardEligibleToDisplay(card))
+ .isFalse();
+ }
+
+ @Test
+ public void isCardEligibleToDisplay_nullSlice_returnFalse() {
+ doReturn(null).when(mEligibleCardChecker).bindSlice(any(Uri.class));
+
+ assertThat(mEligibleCardChecker.isCardEligibleToDisplay(getContextualCard(TEST_SLICE_URI)))
+ .isFalse();
+ }
+
+ @Test
+ public void isCardEligibleToDisplay_errorSlice_returnFalse() {
+ final Slice slice = new Slice.Builder(TEST_SLICE_URI)
+ .addHints(HINT_ERROR).build();
+ doReturn(slice).when(mEligibleCardChecker).bindSlice(any(Uri.class));
+
+ assertThat(mEligibleCardChecker.isCardEligibleToDisplay(getContextualCard(TEST_SLICE_URI)))
+ .isFalse();
+ }
+
+ private ContextualCard getContextualCard(Uri sliceUri) {
+ return new ContextualCard.Builder()
+ .setName("test_card")
+ .setRankingScore(0.5)
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(sliceUri)
+ .build();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java
index b39f77e..1ba1dc9 100644
--- a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java
+++ b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java
@@ -106,9 +106,9 @@
}
@Test
- public void getSlice_noConnectableDevice_returnNull() {
+ public void getSlice_noConnectedDevice_returnNull() {
mDevicesList.clear();
- when(mA2dpProfile.getConnectableDevices()).thenReturn(mDevicesList);
+ when(mA2dpProfile.getConnectedDevices()).thenReturn(mDevicesList);
assertThat(mMediaOutputIndicatorSlice.getSlice()).isNull();
}
@@ -116,7 +116,7 @@
@Test
public void getSlice_noActiveDevice_verifyDefaultName() {
mDevicesList.add(mA2dpDevice);
- when(mA2dpProfile.getConnectableDevices()).thenReturn(mDevicesList);
+ when(mA2dpProfile.getConnectedDevices()).thenReturn(mDevicesList);
when(mA2dpProfile.getActiveDevice()).thenReturn(null);
// Verify slice title and subtitle
@@ -130,7 +130,7 @@
@Test
public void getSlice_A2dpDeviceActive_verifyName() {
mDevicesList.add(mA2dpDevice);
- when(mA2dpProfile.getConnectableDevices()).thenReturn(mDevicesList);
+ when(mA2dpProfile.getConnectedDevices()).thenReturn(mDevicesList);
when(mA2dpProfile.getActiveDevice()).thenReturn(mA2dpDevice);
final Slice mediaSlice = mMediaOutputIndicatorSlice.getSlice();
@@ -142,7 +142,7 @@
@Test
public void getSlice_HADeviceActive_verifyName() {
mDevicesList.add(mHapDevice);
- when(mHearingAidProfile.getConnectableDevices()).thenReturn(mDevicesList);
+ when(mHearingAidProfile.getConnectedDevices()).thenReturn(mDevicesList);
when(mHearingAidProfile.getActiveDevices()).thenReturn(mDevicesList);
// Verify slice title and subtitle
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
index b8ba63c..a623850 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
@@ -34,6 +34,7 @@
import android.os.UserManager;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
@@ -151,8 +152,11 @@
mPreference.getOnPreferenceClickListener().onPreferenceClick(mPreference);
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mContext).startActivity(intentCaptor.capture());
- assertThat(intentCaptor.getValue().getComponent().getClassName()).isEqualTo(
+ Intent intent = intentCaptor.getValue();
+ assertThat(intent.getComponent().getClassName()).isEqualTo(
MobileNetworkActivity.class.getName());
+ assertThat(intent.getIntExtra(Settings.EXTRA_SUB_ID,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID)).isEqualTo(sub1.getSubscriptionId());
}
@Test
diff --git a/tests/robotests/src/com/android/settings/network/SubscriptionUtilTest.java b/tests/robotests/src/com/android/settings/network/SubscriptionUtilTest.java
index c074466..28a390d 100644
--- a/tests/robotests/src/com/android/settings/network/SubscriptionUtilTest.java
+++ b/tests/robotests/src/com/android/settings/network/SubscriptionUtilTest.java
@@ -16,14 +16,21 @@
package com.android.settings.network;
+import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_ABSENT;
+import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.content.Context;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.UiccSlotInfo;
import org.junit.Before;
import org.junit.Test;
@@ -39,17 +46,25 @@
@RunWith(RobolectricTestRunner.class)
public class SubscriptionUtilTest {
@Mock
- private SubscriptionManager mManager;
+ private Context mContext;
+ @Mock
+ private SubscriptionManager mSubMgr;
+ @Mock
+ private TelephonyManager mTelMgr;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ doReturn(mSubMgr).when(mContext).getSystemService(SubscriptionManager.class);
+ doReturn(mTelMgr).when(mContext).getSystemService(TelephonyManager.class);
+ when(mTelMgr.getUiccSlotsInfo()).thenReturn(null);
}
@Test
public void getAvailableSubscriptions_nullInfoFromSubscriptionManager_nonNullResult() {
- when(mManager.getSelectableSubscriptionInfoList()).thenReturn(null);
- final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+ when(mSubMgr.getSelectableSubscriptionInfoList()).thenReturn(null);
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mContext);
assertThat(subs).isNotNull();
assertThat(subs).isEmpty();
}
@@ -58,8 +73,8 @@
public void getAvailableSubscriptions_oneSubscription_oneResult() {
final SubscriptionInfo info = mock(SubscriptionInfo.class);
when(info.getMncString()).thenReturn("fake1234");
- when(mManager.getSelectableSubscriptionInfoList()).thenReturn(Arrays.asList(info));
- final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+ when(mSubMgr.getSelectableSubscriptionInfoList()).thenReturn(Arrays.asList(info));
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mContext);
assertThat(subs).isNotNull();
assertThat(subs).hasSize(1);
}
@@ -70,8 +85,8 @@
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
when(info1.getMncString()).thenReturn("fake1234");
when(info2.getMncString()).thenReturn("fake5678");
- when(mManager.getSelectableSubscriptionInfoList()).thenReturn(Arrays.asList(info1, info2));
- final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+ when(mSubMgr.getSelectableSubscriptionInfoList()).thenReturn(Arrays.asList(info1, info2));
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mContext);
assertThat(subs).isNotNull();
assertThat(subs).hasSize(2);
}
@@ -83,9 +98,9 @@
final SubscriptionInfo info3 = mock(SubscriptionInfo.class);
when(info1.getSubscriptionId()).thenReturn(1);
when(info1.getMncString()).thenReturn("fake1234");
- when(mManager.getSelectableSubscriptionInfoList()).thenReturn(
+ when(mSubMgr.getSelectableSubscriptionInfoList()).thenReturn(
new ArrayList<>(Arrays.asList(info1, info2, info3)));
- final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mContext);
assertThat(subs).isNotNull();
assertThat(subs).hasSize(1);
assertThat(subs.get(0).getSubscriptionId()).isEqualTo(1);
@@ -101,9 +116,9 @@
when(info1.getMncString()).thenReturn("fake1234");
when(info4.getSubscriptionId()).thenReturn(4);
when(info4.getMncString()).thenReturn("fake5678");
- when(mManager.getSelectableSubscriptionInfoList()).thenReturn(new ArrayList<>(
+ when(mSubMgr.getSelectableSubscriptionInfoList()).thenReturn(new ArrayList<>(
Arrays.asList(info1, info2, info3, info4)));
- final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mContext);
assertThat(subs).isNotNull();
assertThat(subs).hasSize(2);
assertThat(subs.get(0).getSubscriptionId()).isEqualTo(1);
@@ -111,9 +126,86 @@
}
@Test
+ public void getAvailableSubscriptions_oneSelectableOneDisabledPSim_twoResults() {
+ final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
+ final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
+
+ when(info1.getSubscriptionId()).thenReturn(111);
+ when(info1.getMncString()).thenReturn("fake111");
+ when(info1.getSimSlotIndex()).thenReturn(-1);
+ when(info1.getCardString()).thenReturn("info1_cardid");
+
+ when(info2.getSubscriptionId()).thenReturn(222);
+ when(info2.getMncString()).thenReturn("fake222");
+ when(info2.getSimSlotIndex()).thenReturn(0);
+ when(info2.getCardString()).thenReturn("info2_cardid");
+
+ when(mSubMgr.getSelectableSubscriptionInfoList()).thenReturn(Arrays.asList(info1));
+ when(mSubMgr.getAllSubscriptionInfoList()).thenReturn(Arrays.asList(info1, info2));
+
+ final UiccSlotInfo info2slot = mock(UiccSlotInfo.class);
+ when(info2slot.getCardStateInfo()).thenReturn(CARD_STATE_INFO_PRESENT);
+ when(info2slot.getLogicalSlotIdx()).thenReturn(0);
+ when(info2slot.getCardId()).thenReturn("info2_cardid");
+
+ final UiccSlotInfo[] slotInfos = {info2slot};
+ when(mTelMgr.getUiccSlotsInfo()).thenReturn(slotInfos);
+
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mContext);
+ assertThat(subs).hasSize(2);
+ assertThat(subs.get(0).getSubscriptionId()).isEqualTo(111);
+ assertThat(subs.get(1).getSubscriptionId()).isEqualTo(222);
+ }
+
+
+ @Test
+ public void getAvailableSubscriptions_oneSelectableTwoDisabledPSimsOneAbsent_twoResults() {
+ final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
+ final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
+ final SubscriptionInfo info3 = mock(SubscriptionInfo.class);
+
+ when(info1.getSubscriptionId()).thenReturn(111);
+ when(info1.getMncString()).thenReturn("fake111");
+ when(info1.getSimSlotIndex()).thenReturn(-1);
+ when(info1.getCardString()).thenReturn("info1_cardid");
+
+ when(info2.getSubscriptionId()).thenReturn(222);
+ when(info2.getMncString()).thenReturn("fake222");
+ when(info2.getSimSlotIndex()).thenReturn(-1);
+ when(info2.getCardString()).thenReturn("info2_cardid");
+
+ when(info3.getSubscriptionId()).thenReturn(333);
+ when(info3.getMncString()).thenReturn("fake333");
+ when(info3.getSimSlotIndex()).thenReturn(0);
+ when(info3.getCardString()).thenReturn("info3_cardid");
+
+ when(mSubMgr.getSelectableSubscriptionInfoList()).thenReturn(Arrays.asList(info1));
+ when(mSubMgr.getAllSubscriptionInfoList()).thenReturn(Arrays.asList(info1, info2, info3));
+
+ final UiccSlotInfo info2slot = mock(UiccSlotInfo.class);
+ final UiccSlotInfo info3slot = mock(UiccSlotInfo.class);
+
+ when(info2slot.getLogicalSlotIdx()).thenReturn(-1);
+ when(info2slot.getCardStateInfo()).thenReturn(CARD_STATE_INFO_ABSENT);
+ when(info2slot.getCardId()).thenReturn("info2_cardid");
+
+ when(info3slot.getLogicalSlotIdx()).thenReturn(0);
+ when(info3slot.getCardStateInfo()).thenReturn(CARD_STATE_INFO_PRESENT);
+ when(info3slot.getCardId()).thenReturn("info3_cardid");
+
+ final UiccSlotInfo[] slotInfos = {info2slot, info3slot};
+ when(mTelMgr.getUiccSlotsInfo()).thenReturn(slotInfos);
+
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mContext);
+ assertThat(subs).hasSize(2);
+ assertThat(subs.get(0).getSubscriptionId()).isEqualTo(111);
+ assertThat(subs.get(1).getSubscriptionId()).isEqualTo(333);
+ }
+
+ @Test
public void getActiveSubscriptions_nullInfoFromSubscriptionManager_nonNullResult() {
- when(mManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(null);
- final List<SubscriptionInfo> subs = SubscriptionUtil.getActiveSubscriptions(mManager);
+ when(mSubMgr.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(null);
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getActiveSubscriptions(mSubMgr);
assertThat(subs).isNotNull();
assertThat(subs).isEmpty();
}
@@ -121,8 +213,8 @@
@Test
public void getActiveSubscriptions_oneSubscription_oneResult() {
final SubscriptionInfo info = mock(SubscriptionInfo.class);
- when(mManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(Arrays.asList(info));
- final List<SubscriptionInfo> subs = SubscriptionUtil.getActiveSubscriptions(mManager);
+ when(mSubMgr.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(Arrays.asList(info));
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getActiveSubscriptions(mSubMgr);
assertThat(subs).isNotNull();
assertThat(subs).hasSize(1);
}
@@ -131,9 +223,9 @@
public void getActiveSubscriptions_twoSubscriptions_twoResults() {
final SubscriptionInfo info1 = mock(SubscriptionInfo.class);
final SubscriptionInfo info2 = mock(SubscriptionInfo.class);
- when(mManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(
+ when(mSubMgr.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(
Arrays.asList(info1, info2));
- final List<SubscriptionInfo> subs = SubscriptionUtil.getActiveSubscriptions(mManager);
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getActiveSubscriptions(mSubMgr);
assertThat(subs).isNotNull();
assertThat(subs).hasSize(2);
}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MmsMessagePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/MmsMessagePreferenceControllerTest.java
new file mode 100644
index 0000000..0263fe9
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/telephony/MmsMessagePreferenceControllerTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.settings.network.telephony;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
+
+import androidx.preference.SwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowSubscriptionManager;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowSubscriptionManager.class)
+public class MmsMessagePreferenceControllerTest {
+ private static final int SUB_ID = 2;
+
+ @Mock
+ private TelephonyManager mTelephonyManager;
+ @Mock
+ private SubscriptionManager mSubscriptionManager;
+
+ private MmsMessagePreferenceController mController;
+ private SwitchPreference mPreference;
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
+ when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
+ when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
+ when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager);
+
+ mPreference = new SwitchPreference(mContext);
+ mController = new MmsMessagePreferenceController(mContext, "mms_message");
+ ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID);
+ mController.init(SUB_ID);
+ mPreference.setKey(mController.getPreferenceKey());
+ }
+
+ @Test
+ public void getAvailabilityStatus_invalidSubscription_returnUnavailable() {
+ mController.init(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_mobileDataOn_returnUnavailable() {
+ when(mTelephonyManager.isDataEnabled()).thenReturn(true);
+
+ assertThat(mController.getAvailabilityStatus(SUB_ID)).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_meteredOff_returnUnavailable() {
+ when(mTelephonyManager.isApnMetered(ApnSetting.TYPE_MMS)).thenReturn(false);
+
+ assertThat(mController.getAvailabilityStatus(SUB_ID)).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_mobileDataOffWithValidSubId_returnAvailable() {
+ mController.init(SUB_ID);
+ when(mTelephonyManager.isDataEnabled()).thenReturn(false);
+ when(mTelephonyManager.isApnMetered(ApnSetting.TYPE_MMS)).thenReturn(true);
+
+ assertThat(mController.getAvailabilityStatus(SUB_ID)).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ public void isChecked_returnDataFromTelephonyManager() {
+ when(mTelephonyManager.isDataEnabledForApn(ApnSetting.TYPE_MMS)).thenReturn(false);
+ assertThat(mController.isChecked()).isFalse();
+
+ when(mTelephonyManager.isDataEnabledForApn(ApnSetting.TYPE_MMS)).thenReturn(true);
+ assertThat(mController.isChecked()).isTrue();
+ }
+
+ @Test
+ public void setChecked_setDataIntoSubscriptionManager() {
+ mController.setChecked(true);
+ verify(mSubscriptionManager).setAlwaysAllowMmsData(SUB_ID, true);
+
+ mController.setChecked(false);
+ verify(mSubscriptionManager).setAlwaysAllowMmsData(SUB_ID, false);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkActivityTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkActivityTest.java
index 68f8c91..f38f2a2 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkActivityTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkActivityTest.java
@@ -33,15 +33,18 @@
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.view.Menu;
import android.view.View;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.view.menu.ContextMenuBuilder;
import com.android.settings.R;
+import com.android.settings.network.SubscriptionUtil;
import com.google.android.material.bottomnavigation.BottomNavigationView;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,6 +55,7 @@
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import androidx.fragment.app.Fragment;
@@ -73,6 +77,8 @@
@Mock
private SubscriptionManager mSubscriptionManager;
@Mock
+ private TelephonyManager mTelephonyManager;
+ @Mock
private SubscriptionInfo mSubscriptionInfo;
@Mock
private SubscriptionInfo mSubscriptionInfo2;
@@ -99,6 +105,8 @@
doReturn(mSubscriptionManager).when(mMobileNetworkActivity).getSystemService(
SubscriptionManager.class);
+ doReturn(mTelephonyManager).when(mMobileNetworkActivity).getSystemService(
+ TelephonyManager.class);
doReturn(mBottomNavigationView).when(mMobileNetworkActivity).findViewById(R.id.bottom_nav);
doReturn(mFragmentManager).when(mMobileNetworkActivity).getSupportFragmentManager();
doReturn(mFragmentTransaction).when(mFragmentManager).beginTransaction();
@@ -108,6 +116,11 @@
MOBILE_SETTINGS_TAG + CURRENT_SUB_ID);
}
+ @After
+ public void tearDown() {
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(null);
+ }
+
@Test
public void updateBottomNavigationView_oneSubscription_shouldBeGone() {
mSubscriptionInfos.add(mSubscriptionInfo);
@@ -169,7 +182,7 @@
doReturn(intent).when(mMobileNetworkActivity).getIntent();
mSubscriptionInfos.add(mSubscriptionInfo);
mSubscriptionInfos.add(mSubscriptionInfo2);
- doReturn(mSubscriptionInfos).when(mSubscriptionManager).getSelectableSubscriptionInfoList();
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(mSubscriptionInfos);
doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(CURRENT_SUB_ID);
assertThat(mMobileNetworkActivity.getSubscriptionId()).isEqualTo(CURRENT_SUB_ID);
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.java
index 6d85826..a10227f 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSwitchControllerTest.java
@@ -20,6 +20,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -99,13 +100,22 @@
}
@Test
- public void displayPreference_onlyOneSubscription_switchBarHidden() {
+ public void displayPreference_oneEnabledSubscription_switchBarHidden() {
+ doReturn(true).when(mSubscriptionManager).isSubscriptionEnabled(mSubId);
SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(mSubscription));
mController.displayPreference(mScreen);
assertThat(mSwitchBar.isShowing()).isFalse();
}
@Test
+ public void displayPreference_oneDisabledSubscription_switchBarNotHidden() {
+ doReturn(false).when(mSubscriptionManager).isSubscriptionEnabled(mSubId);
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(mSubscription));
+ mController.displayPreference(mScreen);
+ assertThat(mSwitchBar.isShowing()).isTrue();
+ }
+
+ @Test
public void displayPreference_subscriptionEnabled_switchIsOn() {
when(mSubscriptionManager.isSubscriptionEnabled(mSubId)).thenReturn(true);
mController.displayPreference(mScreen);
diff --git a/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java b/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
index 793b44d..44dc3bc 100644
--- a/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
@@ -36,20 +36,19 @@
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.android.controller.ActivityController;
@RunWith(RobolectricTestRunner.class)
public class PanelFragmentTest {
private Context mContext;
private PanelFragment mPanelFragment;
+ private FakeSettingsPanelActivity mActivity;
private FakeFeatureFactory mFakeFeatureFactory;
private PanelFeatureProvider mPanelFeatureProvider;
private FakePanelContent mFakePanelContent;
@@ -66,16 +65,12 @@
mFakePanelContent = new FakePanelContent();
doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any(), any());
- ActivityController<FakeSettingsPanelActivity> activityController =
- Robolectric.buildActivity(FakeSettingsPanelActivity.class);
- activityController.setup();
+ mActivity = spy(Robolectric.buildActivity(FakeSettingsPanelActivity.class).setup().get());
mPanelFragment =
spy((PanelFragment)
- activityController
- .get()
- .getSupportFragmentManager()
- .findFragmentById(R.id.main_content));
+ mActivity.getSupportFragmentManager().findFragmentById(R.id.main_content));
+ doReturn(mActivity).when(mPanelFragment).getActivity();
final Bundle bundle = new Bundle();
bundle.putString(SettingsPanelActivity.KEY_PANEL_TYPE_ARGUMENT, FAKE_EXTRA);
@@ -106,23 +101,23 @@
}
@Test
- @Ignore("b/130896218")
public void onDestroy_logCloseEvent() {
- mPanelFragment.onDestroy();
+ mPanelFragment.onDestroyView();
verify(mFakeFeatureFactory.metricsFeatureProvider).action(
0,
- SettingsEnums.PAGE_VISIBLE,
+ SettingsEnums.PAGE_HIDE,
mFakePanelContent.getMetricsCategory(),
- any(String.class),
- 0); }
+ PanelLoggingContract.PanelClosedKeys.KEY_OTHERS,
+ 0);
+ }
@Test
- @Ignore("b/130896218")
public void panelSeeMoreClick_logsCloseEvent() {
final View.OnClickListener listener = mPanelFragment.getSeeMoreListener();
-
listener.onClick(null);
+ verify(mActivity).finish();
+ mPanelFragment.onDestroyView();
verify(mFakeFeatureFactory.metricsFeatureProvider).action(
0,
SettingsEnums.PAGE_HIDE,
@@ -133,12 +128,12 @@
}
@Test
- @Ignore("b/130896218")
public void panelDoneClick_logsCloseEvent() {
final View.OnClickListener listener = mPanelFragment.getCloseListener();
-
listener.onClick(null);
+ verify(mActivity).finish();
+ mPanelFragment.onDestroyView();
verify(mFakeFeatureFactory.metricsFeatureProvider).action(
0,
SettingsEnums.PAGE_HIDE,
diff --git a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
index 4ca6395..8ad2156 100644
--- a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
+++ b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
@@ -35,7 +35,6 @@
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
@@ -52,8 +51,8 @@
@Before
public void setUp() {
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
- mSettingsPanelActivity = Robolectric.buildActivity(FakeSettingsPanelActivity.class)
- .create().get();
+ mSettingsPanelActivity = spy(
+ Robolectric.buildActivity(FakeSettingsPanelActivity.class).create().get());
mPanelFeatureProvider = spy(new PanelFeatureProviderImpl());
mFakeFeatureFactory.panelFeatureProvider = mPanelFeatureProvider;
mFakePanelContent = new FakePanelContent();
@@ -88,21 +87,4 @@
assertThat(activity.mBundle.getString(KEY_PANEL_TYPE_ARGUMENT))
.isEqualTo("com.android.settings.panel.action.MEDIA_OUTPUT");
}
-
- @Test
- @Ignore("b/130896218")
- public void onTouchEvent_outsideAction_logsPanelClosed() {
- final MotionEvent event = mock(MotionEvent.class);
- when(event.getAction()).thenReturn(MotionEvent.ACTION_OUTSIDE);
-
- mSettingsPanelActivity.onTouchEvent(event);
-
- verify(mFakeFeatureFactory.metricsFeatureProvider).action(
- 0,
- SettingsEnums.PAGE_HIDE,
- SettingsEnums.TESTING,
- PanelLoggingContract.PanelClosedKeys.KEY_OTHERS,
- 0
- );
- }
}
diff --git a/tests/robotests/src/com/android/settings/panel/VolumePanelTest.java b/tests/robotests/src/com/android/settings/panel/VolumePanelTest.java
index 154428d..8dd04ce 100644
--- a/tests/robotests/src/com/android/settings/panel/VolumePanelTest.java
+++ b/tests/robotests/src/com/android/settings/panel/VolumePanelTest.java
@@ -18,32 +18,71 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.media.session.ISessionController;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
import android.net.Uri;
+import com.android.settings.notification.RemoteVolumePreferenceController;
import com.android.settings.slices.CustomSliceRegistry;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class VolumePanelTest {
+ @Mock
+ private MediaSessionManager mMediaSessionManager;
+ @Mock
+ private MediaController mMediaController;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private ISessionController mStub;
+
+
private VolumePanel mPanel;
+ private Context mContext;
+
@Before
public void setUp() {
- mPanel = VolumePanel.create(RuntimeEnvironment.application);
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(RuntimeEnvironment.application);
+
+ when(mContext.getApplicationContext()).thenReturn(mContext);
+ when(mContext.getSystemService(MediaSessionManager.class)).thenReturn(mMediaSessionManager);
+
+ mPanel = VolumePanel.create(mContext);
}
@Test
- @Ignore("b/130896218")
- public void getSlices_containsNecessarySlices() {
+ public void getSlices_hasActiveRemoteToken_containsRemoteMediaUri() {
+ List<MediaController> activeSessions = new ArrayList<>();
+ MediaSession.Token token = new MediaSession.Token(mStub);
+ activeSessions.add(mMediaController);
+
+ when(mMediaSessionManager.getActiveSessions(null)).thenReturn(
+ activeSessions);
+ when(mMediaController.getPlaybackInfo()).thenReturn(new MediaController.PlaybackInfo(
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE, 0, 10, 5, null));
+ when(mMediaController.getSessionToken()).thenReturn(new MediaSession.Token(mStub));
+ when(RemoteVolumePreferenceController.getActiveRemoteToken(mContext)).thenReturn(token);
+
final List<Uri> uris = mPanel.getSlices();
assertThat(uris).containsExactly(
@@ -56,6 +95,22 @@
}
@Test
+ public void getSlices_doesNotHaveActiveRemoteToken_doesNotcontainRemoteMediaUri() {
+ final List<Uri> uris = mPanel.getSlices();
+
+ when(RemoteVolumePreferenceController.getActiveRemoteToken(mContext))
+ .thenReturn(null);
+
+ assertThat(uris).doesNotContain(CustomSliceRegistry.VOLUME_REMOTE_MEDIA_URI);
+ assertThat(uris).containsExactly(
+ CustomSliceRegistry.VOLUME_CALL_URI,
+ CustomSliceRegistry.VOLUME_MEDIA_URI,
+ CustomSliceRegistry.MEDIA_OUTPUT_INDICATOR_SLICE_URI,
+ CustomSliceRegistry.VOLUME_RINGER_URI,
+ CustomSliceRegistry.VOLUME_ALARM_URI);
+ }
+
+ @Test
public void getSeeMoreIntent_notNull() {
assertThat(mPanel.getSeeMoreIntent()).isNotNull();
}
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
index 906c55c..d4ce481 100644
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
@@ -35,6 +35,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.content.pm.PackageManager;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
@@ -83,7 +84,6 @@
import com.android.settingslib.wifi.WifiTrackerFactory;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -96,6 +96,7 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowToast;
import java.net.Inet4Address;
import java.net.InetAddress;
@@ -106,7 +107,6 @@
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowDevicePolicyManager.class, ShadowEntityHeaderController.class})
-@Ignore("b/130896210")
public class WifiDetailPreferenceControllerTest {
private static final int LEVEL = 1;
@@ -118,6 +118,7 @@
private static final String RANDOMIZED_MAC_ADDRESS = "RANDOMIZED_MAC_ADDRESS";
private static final String FACTORY_MAC_ADDRESS = "FACTORY_MAC_ADDRESS";
private static final String SECURITY = "None";
+ private static final String FQDN = "fqdn";
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private PreferenceScreen mockScreen;
@@ -299,7 +300,7 @@
list.add(mockAccessPoint);
when(mockWifiTracker.getAccessPoints()).thenReturn(list);
WifiTrackerFactory.setTestingWifiTracker(mockWifiTracker);
- when(mockAccessPoint.matches(any(WifiConfiguration.class))).thenReturn(true);
+ when(mockAccessPoint.matches(any(AccessPoint.class))).thenReturn(true);
when(mockAccessPoint.isReachable()).thenReturn(true);
mController = newWifiDetailPreferenceController();
@@ -311,7 +312,7 @@
list.add(mockAccessPoint);
when(mockWifiTracker.getAccessPoints()).thenReturn(list);
WifiTrackerFactory.setTestingWifiTracker(mockWifiTracker);
- when(mockAccessPoint.matches(any(WifiConfiguration.class))).thenReturn(true);
+ when(mockAccessPoint.matches(any(AccessPoint.class))).thenReturn(true);
when(mockAccessPoint.isReachable()).thenReturn(true);
mController = newWifiDetailPreferenceController();
@@ -323,7 +324,7 @@
list.add(mockAccessPoint);
when(mockWifiTracker.getAccessPoints()).thenReturn(list);
WifiTrackerFactory.setTestingWifiTracker(mockWifiTracker);
- when(mockAccessPoint.matches(any(WifiConfiguration.class))).thenReturn(false);
+ when(mockAccessPoint.matches(any(AccessPoint.class))).thenReturn(false);
when(mockAccessPoint.isReachable()).thenReturn(false);
mController = newWifiDetailPreferenceController();
@@ -1114,12 +1115,13 @@
FeatureFlagPersistent.setEnabled(mContext, FeatureFlags.NETWORK_INTERNET_V2, false);
mockWifiConfig.networkId = 5;
- when(mockWifiConfig.isPasspoint()).thenReturn(true);
+ when(mockAccessPoint.isPasspoint()).thenReturn(true);
+ when(mockAccessPoint.getPasspointFqdn()).thenReturn(FQDN);
mController.displayPreference(mockScreen);
mForgetClickListener.getValue().onClick(null);
- verify(mockWifiManager).removePasspointConfiguration(mockWifiConfig.FQDN);
+ verify(mockWifiManager).removePasspointConfiguration(FQDN);
verify(mockMetricsFeatureProvider)
.action(mockActivity, MetricsProto.MetricsEvent.ACTION_WIFI_FORGET);
}
@@ -1130,13 +1132,14 @@
final WifiDetailPreferenceController spyController = spy(mController);
mockWifiConfig.networkId = 5;
- when(mockWifiConfig.isPasspoint()).thenReturn(true);
+ when(mockAccessPoint.isPasspoint()).thenReturn(true);
+ when(mockAccessPoint.getPasspointFqdn()).thenReturn(FQDN);
spyController.displayPreference(mockScreen);
FeatureFlagPersistent.setEnabled(mContext, FeatureFlags.NETWORK_INTERNET_V2, true);
mForgetClickListener.getValue().onClick(null);
- verify(mockWifiManager, times(0)).removePasspointConfiguration(mockWifiConfig.FQDN);
+ verify(mockWifiManager, times(0)).removePasspointConfiguration(FQDN);
verify(mockMetricsFeatureProvider, times(0))
.action(mockActivity, MetricsProto.MetricsEvent.ACTION_WIFI_FORGET);
verify(spyController).showConfirmForgetDialog();
@@ -1310,6 +1313,406 @@
}
@Test
+ public void testConnectButton_shouldInvisibleForConnectNetwork() {
+ setUpForConnectedNetwork();
+
+ displayAndResume();
+
+ verify(mockButtonsPref, times(1)).setButton3Visible(false);
+ }
+
+ @Test
+ public void testConnectButton_shouldVisibleForDisconnectNetwork() {
+ setUpForDisconnectedNetwork();
+
+ displayAndResume();
+
+ verify(mockButtonsPref, times(1)).setButton3Visible(true);
+ verify(mockButtonsPref, times(1)).setButton3Text(R.string.wifi_connect);
+ }
+
+ private void setUpForToast() {
+ Resources res = mContext.getResources();
+ when(mockActivity.getResources()).thenReturn(res);
+ }
+
+ @Test
+ public void testConnectButton_clickConnect_displayAsSuccess() {
+ setUpForDisconnectedNetwork();
+ when(mockWifiManager.isWifiEnabled()).thenReturn(true);
+ InOrder inOrder = inOrder(mockButtonsPref);
+ String label = "title";
+ when(mockAccessPoint.getTitle()).thenReturn(label);
+ setUpForToast();
+
+ displayAndResume();
+
+ // check connect button exist
+ verifyConnectBtnSetUpAsVisible(inOrder);
+
+ // click connect button
+ mController.connectNetwork();
+
+ // check display button as connecting
+ verify(mockWifiManager, times(1)).connect(anyInt(), any(WifiManager.ActionListener.class));
+ verifyConnectBtnSetUpAsConnecting(inOrder);
+
+ // update as connected
+ when(mockAccessPoint.isActive()).thenReturn(true);
+ mController.updateAccessPoint();
+
+ // check connect button invisible, be init as default state and toast success message
+ verifyConnectBtnBeInitAsDefault(inOrder);
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(false);
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ mContext.getString(R.string.wifi_connected_to_message, label));
+ }
+
+ @Test
+ public void testConnectButton_clickConnectButFailed_displayFailMessage() {
+ setUpForDisconnectedNetwork();
+ ArgumentCaptor<WifiManager.ActionListener> connectListenerCaptor =
+ ArgumentCaptor.forClass(WifiManager.ActionListener.class);
+ when(mockWifiManager.isWifiEnabled()).thenReturn(true);
+ InOrder inOrder = inOrder(mockButtonsPref);
+ setUpForToast();
+
+ displayAndResume();
+
+ // check connect button exist
+ verifyConnectBtnSetUpAsVisible(inOrder);
+
+ // click connect button
+ mController.connectNetwork();
+
+ // check display button as connecting
+ verify(mockWifiManager, times(1)).connect(anyInt(), connectListenerCaptor.capture());
+ verifyConnectBtnSetUpAsConnecting(inOrder);
+
+ // update as failed
+ connectListenerCaptor.getValue().onFailure(-1);
+
+ // check connect button visible, be init as default and toast failed message
+ verifyConnectBtnBeInitAsDefault(inOrder);
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true);
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ mContext.getString(R.string.wifi_failed_connect_message));
+ }
+
+ private void verifyConnectBtnSetUpAsVisible(InOrder inOrder) {
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Text(R.string.wifi_connect);
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Icon(R.drawable.ic_settings_wireless);
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true);
+ }
+
+ private void verifyConnectBtnSetUpAsConnecting(InOrder inOrder) {
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Text(R.string.wifi_connecting);
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Enabled(false);
+ }
+
+ private void verifyConnectBtnBeInitAsDefault(InOrder inOrder) {
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Text(R.string.wifi_connect);
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Icon(R.drawable.ic_settings_wireless);
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Enabled(true);
+ }
+
+ @Test
+ public void testConnectButton_clickConnectButTimeout_displayFailMessage() {
+ setUpForDisconnectedNetwork();
+ when(mockWifiManager.isWifiEnabled()).thenReturn(true);
+ InOrder inOrder = inOrder(mockButtonsPref);
+ setUpForToast();
+
+ displayAndResume();
+
+ // check connect button exist
+ verifyConnectBtnSetUpAsVisible(inOrder);
+
+ // click connect button
+ mController.connectNetwork();
+
+ // check display button as connecting
+ verify(mockWifiManager, times(1)).connect(anyInt(), any(WifiManager.ActionListener.class));
+ verifyConnectBtnSetUpAsConnecting(inOrder);
+
+ // update as failed
+ mController.mTimer.onFinish();
+
+ // check connect button visible, be init as default and toast failed message
+ verifyConnectBtnBeInitAsDefault(inOrder);
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true);
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ mContext.getString(R.string.wifi_failed_connect_message));
+ }
+
+ @Test
+ public void testConnectButton_clickConnectButTimeout_displayNotInRangeMessage() {
+ setUpForNotInRangeNetwork();
+ when(mockWifiManager.isWifiEnabled()).thenReturn(true);
+ InOrder inOrder = inOrder(mockButtonsPref);
+ setUpForToast();
+
+ displayAndResume();
+
+ // check connect button exist
+ verifyConnectBtnSetUpAsVisible(inOrder);
+
+ // click connect button
+ mController.connectNetwork();
+
+ // check display button as connecting
+ verify(mockWifiManager, times(1)).connect(anyInt(), any(WifiManager.ActionListener.class));
+ verifyConnectBtnSetUpAsConnecting(inOrder);
+
+ // update as failed
+ mController.mTimer.onFinish();
+
+ // check connect button visible, be init as default and toast failed message
+ verifyConnectBtnBeInitAsDefault(inOrder);
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true);
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ mContext.getString(R.string.wifi_not_in_range_message));
+ }
+
+ @Test
+ public void testConnectButton_clickConnectWhenWiFiDisabled_displaySuccessMessage() {
+ setUpForDisconnectedNetwork();
+ when(mockWifiManager.isWifiEnabled()).thenReturn(false); // wifi disabled
+ InOrder inOrder = inOrder(mockButtonsPref);
+ String label = "title";
+ when(mockAccessPoint.getTitle()).thenReturn(label);
+ setUpForToast();
+
+ displayAndResume();
+
+ // check connect button exist
+ verifyConnectBtnSetUpAsVisible(inOrder);
+
+ // click connect button
+ mController.connectNetwork();
+
+ // check turn on Wi-Fi, display button as connecting and toast turn on Wi-Fi message
+ verify(mockWifiManager, times(1)).setWifiEnabled(true);
+ verifyConnectBtnSetUpAsConnecting(inOrder);
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ mContext.getString(R.string.wifi_turned_on_message));
+
+ // notify Wi-Fi enabled
+ mController.mWifiListener.onWifiStateChanged(WifiManager.WIFI_STATE_ENABLED);
+
+ // check had connect network and icon display as expected
+ verify(mockWifiManager, times(1)).connect(anyInt(), any(WifiManager.ActionListener.class));
+ verifyConnectBtnSetUpAsConnecting(inOrder);
+
+ // update as connected
+ when(mockAccessPoint.isActive()).thenReturn(true);
+ mController.updateAccessPoint();
+
+ // check connect button invisible, be init as default state and toast success message
+ verifyConnectBtnBeInitAsDefault(inOrder);
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(false);
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ mContext.getString(R.string.wifi_connected_to_message, label));
+ }
+
+ @Test
+ public void testConnectButton_clickConnectWhenWiFiDisabled_failedToConnectWiFi() {
+ setUpForDisconnectedNetwork();
+ when(mockWifiManager.isWifiEnabled()).thenReturn(false); // wifi disabled
+ InOrder inOrder = inOrder(mockButtonsPref);
+ setUpForToast();
+
+ displayAndResume();
+
+ // check connect button exist
+ verifyConnectBtnSetUpAsVisible(inOrder);
+
+ // click connect button
+ mController.connectNetwork();
+
+ // check turn on Wi-Fi, display button as connecting and toast turn on Wi-Fi message
+ verify(mockWifiManager, times(1)).setWifiEnabled(true);
+ verifyConnectBtnSetUpAsConnecting(inOrder);
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ mContext.getString(R.string.wifi_turned_on_message));
+
+ // notify Wi-Fi enabled
+ mController.mWifiListener.onWifiStateChanged(WifiManager.WIFI_STATE_ENABLED);
+
+ // check had connect network and icon display as expected
+ verify(mockWifiManager, times(1)).connect(anyInt(), any(WifiManager.ActionListener.class));
+ verifyConnectBtnSetUpAsConnecting(inOrder);
+
+ // update as failed
+ mController.mTimer.onFinish();
+
+ // check connect button visible, be init as default and toast failed message
+ verifyConnectBtnBeInitAsDefault(inOrder);
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true);
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ mContext.getString(R.string.wifi_failed_connect_message));
+ }
+
+ @Test
+ public void
+ testConnectButton_clickConnectWhenWiFiDisabled_failedToConnectWifiBecauseNotInRange() {
+ setUpForNotInRangeNetwork();
+ when(mockWifiManager.isWifiEnabled()).thenReturn(false); // wifi disabled
+ InOrder inOrder = inOrder(mockButtonsPref);
+ setUpForToast();
+
+ displayAndResume();
+
+ // check connect button exist
+ verifyConnectBtnSetUpAsVisible(inOrder);
+
+ // click connect button
+ mController.connectNetwork();
+
+ // check turn on Wi-Fi, display button as connecting and toast turn on Wi-Fi message
+ verify(mockWifiManager, times(1)).setWifiEnabled(true);
+ verifyConnectBtnSetUpAsConnecting(inOrder);
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ mContext.getString(R.string.wifi_turned_on_message));
+
+ // notify Wi-Fi enabled
+ mController.mWifiListener.onWifiStateChanged(WifiManager.WIFI_STATE_ENABLED);
+
+ // check had connect network and icon display as expected
+ verify(mockWifiManager, times(1)).connect(anyInt(), any(WifiManager.ActionListener.class));
+ verifyConnectBtnSetUpAsConnecting(inOrder);
+
+ // update as failed
+ mController.mTimer.onFinish();
+
+ // check connect button visible, be init as default and toast failed message
+ verifyConnectBtnBeInitAsDefault(inOrder);
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true);
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ mContext.getString(R.string.wifi_not_in_range_message));
+ }
+
+ @Test
+ public void testConnectButton_clickConnectWhenWiFiDisabled_failedToEnableWifi() {
+ setUpForDisconnectedNetwork();
+ when(mockWifiManager.isWifiEnabled()).thenReturn(false); // wifi disabled
+ InOrder inOrder = inOrder(mockButtonsPref);
+ setUpForToast();
+
+ displayAndResume();
+
+ // check connect button exist
+ verifyConnectBtnSetUpAsVisible(inOrder);
+
+ // click connect button
+ mController.connectNetwork();
+
+ // check turn on Wi-Fi, display button as connecting and toast turn on Wi-Fi message
+ verify(mockWifiManager, times(1)).setWifiEnabled(true);
+ verifyConnectBtnSetUpAsConnecting(inOrder);
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ mContext.getString(R.string.wifi_turned_on_message));
+
+ // notify turn on Wi-Fi failed
+ mController.mTimer.onFinish();
+
+ // check connect button visible, be init as default and toast failed message
+ verifyConnectBtnBeInitAsDefault(inOrder);
+ inOrder.verify(mockButtonsPref, times(1)).setButton3Visible(true);
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ mContext.getString(R.string.wifi_failed_connect_message));
+ }
+
+ @Test
+ public void updateAccessPoint_returnFalseForNothingChanged() {
+ setUpForDisconnectedNetwork();
+
+ displayAndResume();
+ boolean changed = mController.updateAccessPoint();
+
+ assertThat(changed).isFalse();
+ }
+
+ @Test
+ public void updateAccessPoint_returnTrueForSignalLevelChanged() {
+ setUpForDisconnectedNetwork();
+
+ displayAndResume();
+
+ // Level changed
+ when(mockAccessPoint.getLevel()).thenReturn(LEVEL + 1);
+ boolean changed = mController.updateAccessPoint();
+
+ assertThat(changed).isTrue();
+ }
+
+ @Test
+ public void updateAccessPoint_returnTrueForChangeAsNotInRange() {
+ setUpForDisconnectedNetwork();
+
+ displayAndResume();
+
+ // change as not in range
+ when(mockAccessPoint.matches(any(AccessPoint.class))).thenReturn(false);
+ boolean changed = mController.updateAccessPoint();
+
+ assertThat(changed).isTrue();
+ }
+
+ @Test
+ public void updateAccessPoint_returnTrueForChangeAsInRange() {
+ setUpForNotInRangeNetwork();
+
+ displayAndResume();
+
+ // change as in range
+ when(mockAccessPoint.matches(any(AccessPoint.class))).thenReturn(true);
+ boolean changed = mController.updateAccessPoint();
+
+ assertThat(changed).isTrue();
+ }
+
+ @Test
+ public void updateAccessPoint_returnTrueForChangeAsConnected() {
+ setUpForDisconnectedNetwork();
+
+ displayAndResume();
+
+ // change as connected
+ when(mockAccessPoint.isActive()).thenReturn(true);
+ boolean changed = mController.updateAccessPoint();
+
+ assertThat(changed).isTrue();
+ }
+
+ @Test
+ public void updateAccessPoint_returnTrueForChangeAsDisconnected() {
+ setUpForConnectedNetwork();
+
+ displayAndResume();
+
+ // change as disconnected
+ when(mockAccessPoint.isActive()).thenReturn(false);
+ boolean changed = mController.updateAccessPoint();
+
+ assertThat(changed).isTrue();
+ }
+
+ @Test
+ public void updateAccessPoint_returnTrueForAccessPointUpdated() {
+ setUpForConnectedNetwork();
+
+ displayAndResume();
+
+ // change as disconnected
+ when(mockAccessPoint.update(mockWifiConfig, mockWifiInfo, mockNetworkInfo))
+ .thenReturn(true);
+ boolean changed = mController.updateAccessPoint();
+
+ assertThat(changed).isTrue();
+ }
+
+ @Test
public void testRefreshRssiViews_shouldNotUpdateIfLevelIsSameForConnectedNetwork() {
setUpForConnectedNetwork();
displayAndResume();
diff --git a/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java b/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java
index b18102d..cea8365 100644
--- a/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java
@@ -27,7 +27,6 @@
import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
import android.net.wifi.WifiManager;
-import com.android.settings.testutils.shadow.ShadowConnectivityManager;
import com.android.settings.testutils.shadow.ShadowWifiManager;
import com.android.settingslib.wifi.AccessPoint;
@@ -41,13 +40,10 @@
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {
- ShadowConnectivityManager.class,
- ShadowWifiManager.class,
-})
+@Config(shadows = ShadowWifiManager.class)
public class ConnectToWifiHandlerTest {
- private static final String AP1_SSID = "\"ap1\"";
+ private static final String AP_SSID = "\"ap\"";
private ConnectToWifiHandler mHandler;
private WifiConfiguration mWifiConfig;
@Mock
@@ -59,7 +55,7 @@
mHandler = Robolectric.setupActivity(ConnectToWifiHandler.class);
mWifiConfig = new WifiConfiguration();
- mWifiConfig.SSID = AP1_SSID;
+ mWifiConfig.SSID = AP_SSID;
doReturn(mWifiConfig).when(mAccessPoint).getConfig();
}
@@ -70,7 +66,7 @@
mHandler.connect(mAccessPoint);
- assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP1_SSID);
+ assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP_SSID);
}
@Test
@@ -91,7 +87,7 @@
mHandler.connect(mAccessPoint);
- assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP1_SSID);
+ assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP_SSID);
}
@Test
@@ -104,7 +100,7 @@
mHandler.connect(mAccessPoint);
- assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP1_SSID);
+ assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP_SSID);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java
index 30e289b..19d3e40 100644
--- a/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java
@@ -20,36 +20,54 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
+import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import android.net.wifi.WifiSsid;
import android.os.Bundle;
+import android.os.UserHandle;
import androidx.slice.SliceProvider;
import androidx.slice.widget.SliceLiveData;
+import com.android.settings.testutils.shadow.ShadowWifiManager;
import com.android.settingslib.wifi.AccessPoint;
+import com.android.settingslib.wifi.WifiTracker;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+ ShadowWifiManager.class,
+ WifiScanWorkerTest.ShadowWifiTracker.class,
+})
public class WifiScanWorkerTest {
private static final String AP_NAME = "ap";
@@ -59,6 +77,7 @@
private WifiManager mWifiManager;
private ConnectivityManager mConnectivityManager;
private WifiScanWorker mWifiScanWorker;
+ private ConnectToWifiHandler mConnectToWifiHandler;
@Before
public void setUp() {
@@ -73,6 +92,12 @@
mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
mWifiScanWorker = new WifiScanWorker(mContext, WIFI_SLICE_URI);
+ mConnectToWifiHandler = Robolectric.setupActivity(ConnectToWifiHandler.class);
+ }
+
+ @After
+ public void tearDown() {
+ mWifiScanWorker.clearClickedWifi();
}
@Test
@@ -131,4 +156,82 @@
verify(mResolver).notifyChange(WIFI_SLICE_URI, null);
}
+
+ private AccessPoint createAccessPoint(String ssid) {
+ final AccessPoint accessPoint = mock(AccessPoint.class);
+ doReturn(ssid).when(accessPoint).getSsidStr();
+ return accessPoint;
+ }
+
+ private void setConnectionInfoSSID(String ssid) {
+ final WifiInfo wifiInfo = new WifiInfo();
+ wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(ssid));
+ ShadowWifiManager.get().setConnectionInfo(wifiInfo);
+ }
+
+ @Test
+ public void NetworkCallback_onCapabilitiesChanged_isClickedWifi_shouldStartActivity() {
+ final AccessPoint accessPoint = createAccessPoint("ap1");
+ setConnectionInfoSSID("ap1");
+ final Network network = mConnectivityManager.getActiveNetwork();
+ mWifiScanWorker.registerCaptivePortalNetworkCallback(network);
+
+ mConnectToWifiHandler.connect(accessPoint);
+ mWifiScanWorker.mCaptivePortalNetworkCallback.onCapabilitiesChanged(network,
+ WifiSliceTest.makeCaptivePortalNetworkCapabilities());
+
+ verify(mContext).startActivityAsUser(any(Intent.class), eq(UserHandle.CURRENT));
+ }
+
+ @Test
+ public void NetworkCallback_onCapabilitiesChanged_isNotClickedWifi_shouldNotStartActivity() {
+ final AccessPoint accessPoint = createAccessPoint("ap1");
+ setConnectionInfoSSID("ap2");
+ final Network network = mConnectivityManager.getActiveNetwork();
+ mWifiScanWorker.registerCaptivePortalNetworkCallback(network);
+
+ mConnectToWifiHandler.connect(accessPoint);
+ mWifiScanWorker.mCaptivePortalNetworkCallback.onCapabilitiesChanged(network,
+ WifiSliceTest.makeCaptivePortalNetworkCapabilities());
+
+ verify(mContext, never()).startActivityAsUser(any(Intent.class), eq(UserHandle.CURRENT));
+ }
+
+ @Test
+ public void NetworkCallback_onCapabilitiesChanged_neverClickWifi_shouldNotStartActivity() {
+ setConnectionInfoSSID("ap1");
+ final Network network = mConnectivityManager.getActiveNetwork();
+ mWifiScanWorker.registerCaptivePortalNetworkCallback(network);
+
+ mWifiScanWorker.mCaptivePortalNetworkCallback.onCapabilitiesChanged(network,
+ WifiSliceTest.makeCaptivePortalNetworkCapabilities());
+
+ verify(mContext, never()).startActivityAsUser(any(Intent.class), eq(UserHandle.CURRENT));
+ }
+
+ @Test
+ public void NetworkCallback_onCapabilitiesChanged_sliceIsUnpinned_shouldNotStartActivity() {
+ final AccessPoint accessPoint = createAccessPoint("ap1");
+ setConnectionInfoSSID("ap1");
+ final Network network = mConnectivityManager.getActiveNetwork();
+ mWifiScanWorker.registerCaptivePortalNetworkCallback(network);
+ final WifiScanWorker.CaptivePortalNetworkCallback callback =
+ mWifiScanWorker.mCaptivePortalNetworkCallback;
+
+ mWifiScanWorker.onSlicePinned();
+ mConnectToWifiHandler.connect(accessPoint);
+ mWifiScanWorker.onSliceUnpinned();
+ callback.onCapabilitiesChanged(network,
+ WifiSliceTest.makeCaptivePortalNetworkCapabilities());
+
+ verify(mContext, never()).startActivityAsUser(any(Intent.class), eq(UserHandle.CURRENT));
+ }
+
+ @Implements(WifiTracker.class)
+ public static class ShadowWifiTracker {
+ @Implementation
+ public void onStart() {
+ // do nothing
+ }
+ }
}