Merge "Fixed AutoDataSwitchPreferenceControllerTest" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index cbc0d8e..11bf4c1 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -818,6 +818,10 @@
android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
android:theme="@style/Theme.AlertDialog.SimConfirmDialog"/>
+ <activity android:name=".network.telephony.EuiccRacConnectivityDialogActivity"
+ android:exported="false"
+ android:theme="@style/Theme.AlertDialog.SimConfirmDialog"/>
+
<activity
android:name="Settings$TetherSettingsActivity"
android:label="@string/tether_settings_title_all"
diff --git a/res/layout/sim_warning_dialog_wifi_connectivity.xml b/res/layout/sim_warning_dialog_wifi_connectivity.xml
new file mode 100644
index 0000000..c6cdbc7
--- /dev/null
+++ b/res/layout/sim_warning_dialog_wifi_connectivity.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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"
+ android:orientation="vertical">
+ <ImageView
+ android:src="@drawable/ic_warning_24dp"
+ android:contentDescription="@null"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:gravity="center"
+ android:tint="?android:attr/textColorSecondary"/>
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingEnd="24dp"
+ android:paddingTop="16dp"
+ android:paddingLeft="24dp"
+ android:gravity="center"
+ style="?android:attr/textAppearanceLarge"/>
+
+ <TextView
+ android:id="@+id/msg"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="24dp"
+ android:paddingTop="16dp"
+ android:paddingStart="24dp"
+ android:paddingBottom="32dp"
+ android:gravity="center"
+ android:textAppearance="@style/TextAppearance.DialogMessage"
+ android:visibility="gone"/>
+</LinearLayout>
diff --git a/res/values/accessibility_shortcut_keys.xml b/res/values/accessibility_shortcut_keys.xml
index 0d409a8..4992a54 100644
--- a/res/values/accessibility_shortcut_keys.xml
+++ b/res/values/accessibility_shortcut_keys.xml
@@ -16,6 +16,7 @@
-->
<resources>
+ <string name="accessibility_shortcut_description_pref" translatable="false">shortcut_description</string>
<string name="accessibility_shortcut_volume_keys_pref" translatable="false">shortcut_volume_keys_pref</string>
<string name="accessibility_shortcut_gesture_pref" translatable="false">shortcut_gesture_pref</string>
<string name="accessibility_shortcut_nav_button_pref" translatable="false">shortcut_nav_button_pref</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 76c7106..73a3b55 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5112,6 +5112,10 @@
<string name="accessibility_shortcut_type_hardware">Hold volume keys</string>
<!-- Summary for accessibility shortcut preference for magnification triple tap shortcut type. [CHAR LIMIT=NONE] -->
<string name="accessibility_shortcut_type_triple_tap">Triple tap screen</string>
+ <!-- Generic title for editing the shortcuts of multiple accessibility features. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_shortcut_edit_screen_title">Edit accessibility shortcuts</string>
+ <!-- Prompt for editing the shortcuts of multiple accessibility features. [CHAR LIMIT=NONE] -->
+ <string name="accessibility_shortcut_edit_screen_prompt">Chose your shortcut for %1$s</string>
<!-- Button text for the accessibility dialog continue to the next screen for hearing aid. [CHAR LIMIT=32] -->
<string name="accessibility_hearingaid_instruction_continue_button">Continue</string>
@@ -11697,6 +11701,16 @@
<!-- Body text of error message indicating the device could not erase the SIM due to an error. [CHAR_LIMIT=NONE] -->
<string name="erase_sim_fail_text">Something went wrong and this eSIM wasn\'t erased.\n\nRestart your device and try again.</string>
+ <!-- Strings for to use Wi-Fi before deleting eUICC subscriptions -->
+ <!-- Title on confirmation dialog asking the user to have Wi-Fi. [CHAR_LIMIT=NONE] -->
+ <string name="wifi_warning_dialog_title">Connect to Wi\u2011Fi before erasing</string>
+ <!-- Body text in confirmation dialog indicating why having Wi-Fi is recommended. [CHAR_LIMIT=NONE] -->
+ <string name="wifi_warning_dialog_text">This makes it easier to use your eSIM again in the future without needing to contact your carrier</string>
+ <!-- Button label to continue with erasing [CHAR_LIMIT=20] -->
+ <string name="wifi_warning_continue_button">Erase anyway</string>
+ <!-- Button label to return to settings [CHAR_LIMIT=20] -->
+ <string name="wifi_warning_return_button">OK</string>
+
<!-- Title for Network connection request Dialog [CHAR LIMIT=60] -->
<string name="network_connection_request_dialog_title">Connect to device</string>
<!-- Summary for Network connection request Dialog [CHAR LIMIT=NONE] -->
diff --git a/res/xml/accessibility_edit_shortcuts.xml b/res/xml/accessibility_edit_shortcuts.xml
index 06cbedd..8be0ee5 100644
--- a/res/xml/accessibility_edit_shortcuts.xml
+++ b/res/xml/accessibility_edit_shortcuts.xml
@@ -18,62 +18,66 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto">
- <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
- android:key="@string/accessibility_shortcut_fab_pref"
- android:persistent="false"
- android:selectable="true"
- settings:allowDividerAbove="false"
- settings:allowDividerBelow="false"
- settings:controller="com.android.settings.accessibility.shortcuts.FloatingButtonShortcutOptionController" />
+ <PreferenceCategory
+ android:key="@string/accessibility_shortcut_description_pref">
- <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
- android:key="@string/accessibility_shortcut_gesture_pref"
- android:persistent="false"
- android:selectable="true"
- settings:allowDividerAbove="false"
- settings:allowDividerBelow="false"
- settings:controller="com.android.settings.accessibility.shortcuts.GestureShortcutOptionController" />
+ <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
+ android:key="@string/accessibility_shortcut_fab_pref"
+ android:persistent="false"
+ android:selectable="true"
+ settings:allowDividerAbove="false"
+ settings:allowDividerBelow="false"
+ settings:controller="com.android.settings.accessibility.shortcuts.FloatingButtonShortcutOptionController" />
- <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
- android:key="@string/accessibility_shortcut_nav_button_pref"
- android:persistent="false"
- android:selectable="true"
- settings:allowDividerAbove="false"
- settings:allowDividerBelow="false"
- settings:controller="com.android.settings.accessibility.shortcuts.NavButtonShortcutOptionController" />
+ <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
+ android:key="@string/accessibility_shortcut_gesture_pref"
+ android:persistent="false"
+ android:selectable="true"
+ settings:allowDividerAbove="false"
+ settings:allowDividerBelow="false"
+ settings:controller="com.android.settings.accessibility.shortcuts.GestureShortcutOptionController" />
- <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
- android:key="@string/accessibility_shortcut_volume_keys_pref"
- android:persistent="false"
- android:selectable="true"
- settings:allowDividerAbove="false"
- settings:allowDividerBelow="false"
- settings:controller="com.android.settings.accessibility.shortcuts.VolumeKeysShortcutOptionController" />
+ <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
+ android:key="@string/accessibility_shortcut_nav_button_pref"
+ android:persistent="false"
+ android:selectable="true"
+ settings:allowDividerAbove="false"
+ settings:allowDividerBelow="false"
+ settings:controller="com.android.settings.accessibility.shortcuts.NavButtonShortcutOptionController" />
- <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
- android:key="@string/accessibility_shortcut_two_fingers_double_tap_pref"
- android:persistent="false"
- android:selectable="true"
- settings:allowDividerAbove="false"
- settings:allowDividerBelow="false"
- settings:controller="com.android.settings.accessibility.shortcuts.TwoFingersDoubleTapShortcutOptionController" />
+ <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
+ android:key="@string/accessibility_shortcut_volume_keys_pref"
+ android:persistent="false"
+ android:selectable="true"
+ settings:allowDividerAbove="false"
+ settings:allowDividerBelow="false"
+ settings:controller="com.android.settings.accessibility.shortcuts.VolumeKeysShortcutOptionController" />
- <Preference
- android:icon="@drawable/ic_keyboard_arrow_down"
- android:key="@string/accessibility_shortcuts_advanced_collapsed"
- android:persistent="false"
- android:selectable="true"
- android:title="@string/accessibility_shortcut_edit_dialog_title_advance"
- settings:allowDividerAbove="false"
- settings:allowDividerBelow="false"
- settings:controller="com.android.settings.accessibility.shortcuts.AdvancedShortcutsPreferenceController" />
+ <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
+ android:key="@string/accessibility_shortcut_two_fingers_double_tap_pref"
+ android:persistent="false"
+ android:selectable="true"
+ settings:allowDividerAbove="false"
+ settings:allowDividerBelow="false"
+ settings:controller="com.android.settings.accessibility.shortcuts.TwoFingersDoubleTapShortcutOptionController" />
- <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
- android:key="@string/accessibility_shortcut_triple_tap_pref"
- android:persistent="false"
- android:selectable="true"
- settings:allowDividerAbove="false"
- settings:allowDividerBelow="false"
- settings:controller="com.android.settings.accessibility.shortcuts.TripleTapShortcutOptionController" />
+ <Preference
+ android:icon="@drawable/ic_keyboard_arrow_down"
+ android:key="@string/accessibility_shortcuts_advanced_collapsed"
+ android:persistent="false"
+ android:selectable="true"
+ android:title="@string/accessibility_shortcut_edit_dialog_title_advance"
+ settings:allowDividerAbove="false"
+ settings:allowDividerBelow="false"
+ settings:controller="com.android.settings.accessibility.shortcuts.AdvancedShortcutsPreferenceController" />
+
+ <com.android.settings.accessibility.shortcuts.ShortcutOptionPreference
+ android:key="@string/accessibility_shortcut_triple_tap_pref"
+ android:persistent="false"
+ android:selectable="true"
+ settings:allowDividerAbove="false"
+ settings:allowDividerBelow="false"
+ settings:controller="com.android.settings.accessibility.shortcuts.TripleTapShortcutOptionController" />
+ </PreferenceCategory>
</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml
index 34a5798..e9ec19e 100644
--- a/res/xml/connected_devices.xml
+++ b/res/xml/connected_devices.xml
@@ -41,8 +41,7 @@
<PreferenceCategory
android:key="available_device_list"
- android:title="@string/connected_device_media_device_title"
- settings:controller="com.android.settings.connecteddevice.AvailableMediaDeviceGroupController" />
+ android:title="@string/connected_device_media_device_title"/>
<PreferenceCategory
android:key="connected_device_list"
diff --git a/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java b/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java
index a3cbb57..5a3b13a 100644
--- a/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java
@@ -27,16 +27,21 @@
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE;
+import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.database.ContentObserver;
+import android.icu.text.ListFormatter;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -48,9 +53,12 @@
import androidx.preference.Preference;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.internal.accessibility.dialog.AccessibilityTarget;
+import com.android.internal.accessibility.dialog.AccessibilityTargetHelper;
import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
import com.android.settings.accessibility.AccessibilitySetupWizardUtils;
+import com.android.settings.accessibility.Flags;
import com.android.settings.accessibility.PreferredShortcuts;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.DashboardFragment;
@@ -60,7 +68,10 @@
import com.google.android.setupcompat.util.WizardManagerHelper;
import com.google.android.setupdesign.GlifPreferenceLayout;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -171,6 +182,36 @@
registerSettingsObserver();
}
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ super.onCreatePreferences(savedInstanceState, rootKey);
+
+ Activity activity = getActivity();
+
+ if (!activity.getIntent().getAction().equals(
+ Settings.ACTION_ACCESSIBILITY_SHORTCUT_SETTINGS)
+ || !Flags.editShortcutsInFullScreen()) {
+ return;
+ }
+
+ // TODO(b/325664350): Implement shortcut type for "all shortcuts"
+ List<AccessibilityTarget> accessibilityTargets =
+ AccessibilityTargetHelper.getInstalledTargets(
+ activity.getBaseContext(), AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY);
+
+ Pair<String, String> titles = getTitlesFromAccessibilityTargetList(
+ mShortcutTargets,
+ accessibilityTargets,
+ activity.getResources()
+ );
+
+ activity.setTitle(titles.first);
+
+ String categoryKey = activity.getResources().getString(
+ R.string.accessibility_shortcut_description_pref);
+ findPreference(categoryKey).setTitle(titles.second);
+ }
+
@NonNull
@Override
public RecyclerView onCreateRecyclerView(
@@ -275,7 +316,6 @@
}
mShortcutTargets = Set.of(targets);
- // TODO(318748373): use 'targets' to populate title when no title is given
}
@Override
@@ -356,4 +396,52 @@
// A11y Nav Button
refreshPreferenceController(NavButtonShortcutOptionController.class);
}
+
+ /**
+ * Generates a title & subtitle pair describing the features whose shortcuts are being edited.
+ *
+ * @param shortcutTargets string list of component names corresponding to
+ * the relevant shortcut targets.
+ * @param accessibilityTargets list of accessibility targets
+ * to try and find corresponding labels in.
+ * @return pair of strings to be used as page title and subtitle.
+ * If there is only one shortcut label, It is displayed in the title and the subtitle is null.
+ * Otherwise, the title is a generic prompt and the subtitle lists all shortcut labels.
+ */
+ @VisibleForTesting
+ static Pair<String, String> getTitlesFromAccessibilityTargetList(
+ Set<String> shortcutTargets,
+ List<AccessibilityTarget> accessibilityTargets,
+ Resources resources) {
+ ArrayList<CharSequence> featureLabels = new ArrayList<>();
+
+ Map<String, CharSequence> accessibilityTargetLabels = new ArrayMap<>();
+ accessibilityTargets.forEach((target) -> accessibilityTargetLabels.put(
+ target.getId(), target.getLabel()));
+
+ for (String target: shortcutTargets) {
+ if (accessibilityTargetLabels.containsKey(target)) {
+ featureLabels.add(accessibilityTargetLabels.get(target));
+ } else {
+ throw new IllegalStateException("Shortcut target does not have a label: " + target);
+ }
+ }
+
+ if (featureLabels.size() == 1) {
+ return new Pair<>(
+ resources.getString(
+ R.string.accessibility_shortcut_title, featureLabels.get(0)),
+ null
+ );
+ } else if (featureLabels.size() == 0) {
+ throw new IllegalStateException("Found no labels for any shortcut targets.");
+ } else {
+ return new Pair<>(
+ resources.getString(R.string.accessibility_shortcut_edit_screen_title),
+ resources.getString(
+ R.string.accessibility_shortcut_edit_screen_prompt,
+ ListFormatter.getInstance().format(featureLabels))
+ );
+ }
+ }
}
diff --git a/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
index 797364b..ae5b62b 100644
--- a/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
+++ b/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java
@@ -29,7 +29,9 @@
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
+import android.window.OnBackInvokedCallback;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -57,9 +59,14 @@
private static final String TAG = "FaceSettings/Remove";
static final String KEY = "security_settings_face_delete_faces_container";
- public static class ConfirmRemoveDialog extends InstrumentedDialogFragment {
+ public static class ConfirmRemoveDialog extends InstrumentedDialogFragment
+ implements OnBackInvokedCallback {
private static final String KEY_IS_CONVENIENCE = "is_convenience";
private DialogInterface.OnClickListener mOnClickListener;
+ @Nullable
+ private AlertDialog mDialog = null;
+ @Nullable
+ private Preference mFaceUnlockPreference = null;
/** Returns the new instance of the class */
public static ConfirmRemoveDialog newInstance(boolean isConvenience) {
@@ -99,14 +106,41 @@
.setMessage(dialogMessageRes)
.setPositiveButton(R.string.delete, mOnClickListener)
.setNegativeButton(R.string.cancel, mOnClickListener);
- AlertDialog dialog = builder.create();
- dialog.setCanceledOnTouchOutside(false);
- return dialog;
+ mDialog = builder.create();
+ mDialog.setCanceledOnTouchOutside(false);
+ mDialog.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(0, this);
+ return mDialog;
}
public void setOnClickListener(DialogInterface.OnClickListener listener) {
mOnClickListener = listener;
}
+
+ public void setPreference(@Nullable Preference preference) {
+ mFaceUnlockPreference = preference;
+ }
+
+ public void unregisterOnBackInvokedCallback() {
+ if (mDialog != null) {
+ mDialog.getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(this);
+ }
+ }
+
+ @Override
+ public void onBackInvoked() {
+ if (mDialog != null) {
+ mDialog.cancel();
+ }
+ unregisterOnBackInvokedCallback();
+
+ if (mFaceUnlockPreference != null) {
+ final Button removeButton = ((LayoutPreference) mFaceUnlockPreference)
+ .findViewById(R.id.security_settings_face_settings_remove_button);
+ if (removeButton != null) {
+ removeButton.setEnabled(true);
+ }
+ }
+ }
}
interface Listener {
@@ -171,6 +205,13 @@
mButton.setEnabled(true);
mRemoving = false;
}
+
+ final ConfirmRemoveDialog removeDialog =
+ (ConfirmRemoveDialog) mActivity.getSupportFragmentManager()
+ .findFragmentByTag(ConfirmRemoveDialog.class.getName());
+ if (removeDialog != null) {
+ removeDialog.unregisterOnBackInvokedCallback();
+ }
}
};
@@ -210,6 +251,7 @@
(ConfirmRemoveDialog) mActivity.getSupportFragmentManager()
.findFragmentByTag(ConfirmRemoveDialog.class.getName());
if (removeDialog != null) {
+ removeDialog.setPreference(mPreference);
mRemoving = true;
removeDialog.setOnClickListener(mOnConfirmDialogClickListener);
}
diff --git a/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java b/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java
index fc3493c..0535d15 100644
--- a/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java
+++ b/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java
@@ -17,18 +17,17 @@
import static com.android.settingslib.Utils.isAudioModeOngoingCall;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothLeBroadcastAssistant;
-import android.bluetooth.BluetoothLeBroadcastMetadata;
-import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.pm.PackageManager;
import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
@@ -38,138 +37,66 @@
import com.android.settings.bluetooth.AvailableMediaBluetoothDeviceUpdater;
import com.android.settings.bluetooth.BluetoothDeviceUpdater;
import com.android.settings.bluetooth.Utils;
-import com.android.settings.connecteddevice.audiosharing.AudioSharingUtils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-import com.android.settingslib.core.lifecycle.events.OnStop;
-
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
+import com.android.settingslib.core.lifecycle.Lifecycle;
/**
* Controller to maintain the {@link androidx.preference.PreferenceGroup} for all available media
* devices. It uses {@link DevicePreferenceCallback} to add/remove {@link Preference}
*/
public class AvailableMediaDeviceGroupController extends BasePreferenceController
- implements LifecycleObserver, OnStart, OnStop, DevicePreferenceCallback, BluetoothCallback {
+ implements DefaultLifecycleObserver, DevicePreferenceCallback, BluetoothCallback {
private static final boolean DEBUG = BluetoothUtils.D;
private static final String TAG = "AvailableMediaDeviceGroupController";
private static final String KEY = "available_device_list";
- @VisibleForTesting PreferenceGroup mPreferenceGroup;
+ @VisibleForTesting @Nullable PreferenceGroup mPreferenceGroup;
@VisibleForTesting LocalBluetoothManager mLocalBluetoothManager;
- private final Executor mExecutor;
- private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
- private FragmentManager mFragmentManager;
- private BluetoothLeBroadcastAssistant.Callback mAssistantCallback =
- new BluetoothLeBroadcastAssistant.Callback() {
- @Override
- public void onSearchStarted(int reason) {}
+ @Nullable private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
+ @Nullable private FragmentManager mFragmentManager;
- @Override
- public void onSearchStartFailed(int reason) {}
-
- @Override
- public void onSearchStopped(int reason) {}
-
- @Override
- public void onSearchStopFailed(int reason) {}
-
- @Override
- public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) {}
-
- @Override
- public void onSourceAdded(@NonNull BluetoothDevice sink, int sourceId, int reason) {
- mBluetoothDeviceUpdater.forceUpdate();
- }
-
- @Override
- public void onSourceAddFailed(
- @NonNull BluetoothDevice sink,
- @NonNull BluetoothLeBroadcastMetadata source,
- int reason) {}
-
- @Override
- public void onSourceModified(
- @NonNull BluetoothDevice sink, int sourceId, int reason) {}
-
- @Override
- public void onSourceModifyFailed(
- @NonNull BluetoothDevice sink, int sourceId, int reason) {}
-
- @Override
- public void onSourceRemoved(
- @NonNull BluetoothDevice sink, int sourceId, int reason) {
- mBluetoothDeviceUpdater.forceUpdate();
- }
-
- @Override
- public void onSourceRemoveFailed(
- @NonNull BluetoothDevice sink, int sourceId, int reason) {}
-
- @Override
- public void onReceiveStateChanged(
- BluetoothDevice sink,
- int sourceId,
- BluetoothLeBroadcastReceiveState state) {}
- };
-
- public AvailableMediaDeviceGroupController(Context context) {
+ public AvailableMediaDeviceGroupController(
+ Context context,
+ @Nullable DashboardFragment fragment,
+ @Nullable Lifecycle lifecycle) {
super(context, KEY);
+ if (fragment != null) {
+ init(fragment);
+ }
+ if (lifecycle != null) {
+ lifecycle.addObserver(this);
+ }
mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
- mExecutor = Executors.newSingleThreadExecutor();
}
@Override
- public void onStart() {
+ public void onStart(@NonNull LifecycleOwner owner) {
if (mLocalBluetoothManager == null) {
Log.e(TAG, "onStart() Bluetooth is not supported on this device");
return;
}
- if (AudioSharingUtils.isFeatureEnabled()) {
- LocalBluetoothLeBroadcastAssistant assistant =
- mLocalBluetoothManager
- .getProfileManager()
- .getLeAudioBroadcastAssistantProfile();
- if (assistant != null) {
- if (DEBUG) {
- Log.d(TAG, "onStart() Register callbacks for assistant.");
- }
- assistant.registerServiceCallBack(mExecutor, mAssistantCallback);
- }
- }
- mBluetoothDeviceUpdater.registerCallback();
mLocalBluetoothManager.getEventManager().registerCallback(this);
- mBluetoothDeviceUpdater.refreshPreference();
+ if (mBluetoothDeviceUpdater != null) {
+ mBluetoothDeviceUpdater.registerCallback();
+ mBluetoothDeviceUpdater.refreshPreference();
+ }
}
@Override
- public void onStop() {
+ public void onStop(@NonNull LifecycleOwner owner) {
if (mLocalBluetoothManager == null) {
Log.e(TAG, "onStop() Bluetooth is not supported on this device");
return;
}
- if (AudioSharingUtils.isFeatureEnabled()) {
- LocalBluetoothLeBroadcastAssistant assistant =
- mLocalBluetoothManager
- .getProfileManager()
- .getLeAudioBroadcastAssistantProfile();
- if (assistant != null) {
- if (DEBUG) {
- Log.d(TAG, "onStop() Register callbacks for assistant.");
- }
- assistant.unregisterServiceCallBack(mAssistantCallback);
- }
+ if (mBluetoothDeviceUpdater != null) {
+ mBluetoothDeviceUpdater.unregisterCallback();
}
- mBluetoothDeviceUpdater.unregisterCallback();
mLocalBluetoothManager.getEventManager().unregisterCallback(this);
}
@@ -178,12 +105,16 @@
super.displayPreference(screen);
mPreferenceGroup = screen.findPreference(KEY);
- mPreferenceGroup.setVisible(false);
+ if (mPreferenceGroup != null) {
+ mPreferenceGroup.setVisible(false);
+ }
if (isAvailable()) {
updateTitle();
- mBluetoothDeviceUpdater.setPrefContext(screen.getContext());
- mBluetoothDeviceUpdater.forceUpdate();
+ if (mBluetoothDeviceUpdater != null) {
+ mBluetoothDeviceUpdater.setPrefContext(screen.getContext());
+ mBluetoothDeviceUpdater.forceUpdate();
+ }
}
}
@@ -201,17 +132,21 @@
@Override
public void onDeviceAdded(Preference preference) {
- if (mPreferenceGroup.getPreferenceCount() == 0) {
- mPreferenceGroup.setVisible(true);
+ if (mPreferenceGroup != null) {
+ if (mPreferenceGroup.getPreferenceCount() == 0) {
+ mPreferenceGroup.setVisible(true);
+ }
+ mPreferenceGroup.addPreference(preference);
}
- mPreferenceGroup.addPreference(preference);
}
@Override
public void onDeviceRemoved(Preference preference) {
- mPreferenceGroup.removePreference(preference);
- if (mPreferenceGroup.getPreferenceCount() == 0) {
- mPreferenceGroup.setVisible(false);
+ if (mPreferenceGroup != null) {
+ mPreferenceGroup.removePreference(preference);
+ if (mPreferenceGroup.getPreferenceCount() == 0) {
+ mPreferenceGroup.setVisible(false);
+ }
}
}
@@ -253,14 +188,16 @@
}
private void updateTitle() {
- if (isAudioModeOngoingCall(mContext)) {
- // in phone call
- mPreferenceGroup.setTitle(
- mContext.getString(R.string.connected_device_call_device_title));
- } else {
- // without phone call
- mPreferenceGroup.setTitle(
- mContext.getString(R.string.connected_device_media_device_title));
+ if (mPreferenceGroup != null) {
+ if (isAudioModeOngoingCall(mContext)) {
+ // in phone call
+ mPreferenceGroup.setTitle(
+ mContext.getString(R.string.connected_device_call_device_title));
+ } else {
+ // without phone call
+ mPreferenceGroup.setTitle(
+ mContext.getString(R.string.connected_device_media_device_title));
+ }
}
}
}
diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
index 2798be4..04ba5d2 100644
--- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
@@ -24,12 +24,10 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import androidx.lifecycle.Lifecycle;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
-import com.android.settings.connecteddevice.audiosharing.AudioSharingUtils;
import com.android.settings.core.SettingsUIDeviceConfig;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory;
@@ -38,6 +36,7 @@
import com.android.settings.slices.SlicePreferenceController;
import com.android.settingslib.bluetooth.HearingAidStatsLogUtils;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
@@ -92,7 +91,6 @@
+ ", action : "
+ action);
}
- use(AvailableMediaDeviceGroupController.class).init(this);
use(ConnectedDeviceGroupController.class).init(this);
use(PreviouslyConnectedDevicePreferenceController.class).init(this);
use(SlicePreferenceController.class)
@@ -124,15 +122,17 @@
@Nullable ConnectedDeviceDashboardFragment fragment,
@Nullable Lifecycle lifecycle) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
- if (AudioSharingUtils.isFeatureEnabled()) {
- AbstractPreferenceController audioSharingController =
- FeatureFactory.getFeatureFactory()
- .getAudioSharingFeatureProvider()
- .createAudioSharingDevicePreferenceController(
- context, fragment, lifecycle);
- if (audioSharingController != null) {
- controllers.add(audioSharingController);
- }
+ AbstractPreferenceController availableMediaController =
+ FeatureFactory.getFeatureFactory()
+ .getAudioSharingFeatureProvider()
+ .createAvailableMediaDeviceGroupController(context, fragment, lifecycle);
+ controllers.add(availableMediaController);
+ AbstractPreferenceController audioSharingController =
+ FeatureFactory.getFeatureFactory()
+ .getAudioSharingFeatureProvider()
+ .createAudioSharingDevicePreferenceController(context, fragment, lifecycle);
+ if (audioSharingController != null) {
+ controllers.add(audioSharingController);
}
return controllers;
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProvider.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProvider.java
index c71a368..9fe4d50 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProvider.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProvider.java
@@ -20,12 +20,12 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.lifecycle.Lifecycle;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
/** Feature provider for the audio sharing related features, */
public interface AudioSharingFeatureProvider {
@@ -37,6 +37,12 @@
@Nullable DashboardFragment fragment,
@Nullable Lifecycle lifecycle);
+ /** Create available media device preference controller. */
+ AbstractPreferenceController createAvailableMediaDeviceGroupController(
+ @NonNull Context context,
+ @Nullable DashboardFragment fragment,
+ @Nullable Lifecycle lifecycle);
+
/**
* Check if the device match the audio sharing filter.
*
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProviderImpl.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProviderImpl.java
index 05a6a63..259ed7a 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProviderImpl.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProviderImpl.java
@@ -20,12 +20,13 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.lifecycle.Lifecycle;
+import com.android.settings.connecteddevice.AvailableMediaDeviceGroupController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
public class AudioSharingFeatureProviderImpl implements AudioSharingFeatureProvider {
@@ -39,6 +40,14 @@
}
@Override
+ public AbstractPreferenceController createAvailableMediaDeviceGroupController(
+ @NonNull Context context,
+ @Nullable DashboardFragment fragment,
+ @Nullable Lifecycle lifecycle) {
+ return new AvailableMediaDeviceGroupController(context, fragment, lifecycle);
+ }
+
+ @Override
public boolean isAudioSharingFilterMatched(
@NonNull CachedBluetoothDevice cachedDevice, LocalBluetoothManager localBtManager) {
return false;
diff --git a/src/com/android/settings/development/ForcePeakRefreshRatePreferenceController.java b/src/com/android/settings/development/ForcePeakRefreshRatePreferenceController.java
index abeb949..455f74f 100644
--- a/src/com/android/settings/development/ForcePeakRefreshRatePreferenceController.java
+++ b/src/com/android/settings/development/ForcePeakRefreshRatePreferenceController.java
@@ -17,6 +17,7 @@
package com.android.settings.development;
import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE;
+import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateAmongAllDisplays;
import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay;
import android.content.Context;
@@ -47,7 +48,9 @@
public ForcePeakRefreshRatePreferenceController(Context context) {
super(context);
- mPeakRefreshRate = findHighestRefreshRateForDefaultDisplay(context);
+ mPeakRefreshRate = Flags.backUpSmoothDisplayAndForcePeakRefreshRate()
+ ? findHighestRefreshRateAmongAllDisplays(context)
+ : findHighestRefreshRateForDefaultDisplay(context);
Log.d(TAG, "DEFAULT_REFRESH_RATE : " + DEFAULT_REFRESH_RATE
+ " mPeakRefreshRate : " + mPeakRefreshRate);
}
diff --git a/src/com/android/settings/development/SensitiveContentProtectionPreferenceController.kt b/src/com/android/settings/development/SensitiveContentProtectionPreferenceController.kt
index e627f81..8acd700 100644
--- a/src/com/android/settings/development/SensitiveContentProtectionPreferenceController.kt
+++ b/src/com/android/settings/development/SensitiveContentProtectionPreferenceController.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.permission.flags.Flags.sensitiveNotificationAppProtection
import android.provider.Settings
+import android.view.flags.Flags.sensitiveContentAppProtection
import androidx.annotation.VisibleForTesting
import androidx.preference.Preference
import androidx.preference.TwoStatePreference
@@ -64,6 +65,7 @@
override fun isAvailable(): Boolean {
return sensitiveNotificationAppProtection() || screenshareNotificationHiding()
+ || sensitiveContentAppProtection()
}
companion object {
diff --git a/src/com/android/settings/display/PeakRefreshRatePreferenceController.java b/src/com/android/settings/display/PeakRefreshRatePreferenceController.java
index 17d763a..261eaf1 100644
--- a/src/com/android/settings/display/PeakRefreshRatePreferenceController.java
+++ b/src/com/android/settings/display/PeakRefreshRatePreferenceController.java
@@ -17,6 +17,7 @@
package com.android.settings.display;
import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE;
+import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateAmongAllDisplays;
import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay;
import android.content.Context;
@@ -66,7 +67,9 @@
updateState(mPreference);
}
};
- mPeakRefreshRate = Math.round(findHighestRefreshRateForDefaultDisplay(context));
+ mPeakRefreshRate = Math.round(Flags.backUpSmoothDisplayAndForcePeakRefreshRate()
+ ? findHighestRefreshRateAmongAllDisplays(context)
+ : findHighestRefreshRateForDefaultDisplay(context));
Log.d(
TAG,
"DEFAULT_REFRESH_RATE : "
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index 84e4e75..2498ec9 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -17,13 +17,15 @@
package com.android.settings.network;
import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
-import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT;
import static android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING;
+import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT;
import static com.android.internal.util.CollectionUtils.emptyIfNull;
import android.content.Context;
import android.content.SharedPreferences;
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
import android.os.ParcelUuid;
import android.provider.Settings;
import android.telephony.PhoneNumberUtils;
@@ -560,6 +562,7 @@
Log.i(TAG, "Unable to delete subscription due to invalid subscription ID.");
return;
}
+ // TODO(b/325693582): Add verification if carrier is RAC and logic for new dialog
context.startActivity(DeleteEuiccSubscriptionDialogActivity.getIntent(context, subId));
}
@@ -832,4 +835,29 @@
}
return true;
}
+
+ /**
+ * Returns {@code true} if device is connected to Wi-Fi or mobile data provided by a different
+ * subId.
+ *
+ * @param context context
+ * @param targetSubId subscription that is going to be deleted
+ */
+ @VisibleForTesting
+ static boolean isConnectedToWifiOrDifferentSubId(@NonNull Context context, int targetSubId) {
+ ConnectivityManager connectivityManager =
+ context.getSystemService(ConnectivityManager.class);
+ NetworkCapabilities capabilities =
+ connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork());
+
+ if (capabilities != null) {
+ if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ // Connected to WiFi
+ return true;
+ } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ return targetSubId != SubscriptionManager.getActiveDataSubscriptionId();
+ }
+ }
+ return false;
+ }
}
diff --git a/src/com/android/settings/network/telephony/EuiccRacConnectivityDialogActivity.java b/src/com/android/settings/network/telephony/EuiccRacConnectivityDialogActivity.java
new file mode 100644
index 0000000..cb4ab18
--- /dev/null
+++ b/src/com/android/settings/network/telephony/EuiccRacConnectivityDialogActivity.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2024 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.content.Intent;
+import android.os.Bundle;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.android.settings.R;
+
+/** This dialog activity advise the user to have connectivity if the eSIM uses a RAC. */
+public class EuiccRacConnectivityDialogActivity extends SubscriptionActionDialogActivity
+ implements WarningDialogFragment.OnConfirmListener {
+
+ private static final String TAG = "EuiccRacConnectivityDialogActivity";
+ // Dialog tags
+ private static final int DIALOG_TAG_ERASE_ANYWAY_CONFIRMATION = 1;
+
+ private int mSubId;
+
+ /**
+ * Returns an intent of EuiccRacConnectivityDialogActivity.
+ *
+ * @param context The context used to start the EuiccRacConnectivityDialogActivity.
+ * @param subId The subscription ID of the subscription needs to be deleted. If the subscription
+ * belongs to a group of subscriptions, all subscriptions from the group will be deleted.
+ */
+ @NonNull
+ public static Intent getIntent(@NonNull Context context, int subId) {
+ Intent intent = new Intent(context, EuiccRacConnectivityDialogActivity.class);
+ intent.putExtra(ARG_SUB_ID, subId);
+ return intent;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Intent intent = getIntent();
+ mSubId = intent.getIntExtra(ARG_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+
+ if (savedInstanceState == null) {
+ showConnectivityWarningDialog();
+ }
+ }
+
+ @Override
+ public void onConfirm(int tag, boolean confirmed) {
+ if (!confirmed) {
+ finish();
+ return;
+ }
+
+ switch (tag) {
+ case DIALOG_TAG_ERASE_ANYWAY_CONFIRMATION:
+ finish();
+ Log.i(TAG, "Show dialogue activity that handles deleting eSIM profiles");
+ startActivity(DeleteEuiccSubscriptionDialogActivity.getIntent(this, mSubId));
+ break;
+ default:
+ Log.e(TAG, "Unrecognized confirmation dialog tag: " + tag);
+ break;
+ }
+ }
+
+ /* Displays warning to have connectivity because subscription is RAC dialog. */
+ private void showConnectivityWarningDialog() {
+ WarningDialogFragment.show(
+ this,
+ WarningDialogFragment.OnConfirmListener.class,
+ DIALOG_TAG_ERASE_ANYWAY_CONFIRMATION,
+ getString(R.string.wifi_warning_dialog_title),
+ getString(R.string.wifi_warning_dialog_text),
+ getString(R.string.wifi_warning_continue_button),
+ getString(R.string.wifi_warning_return_button));
+ }
+}
diff --git a/src/com/android/settings/network/telephony/WarningDialogFragment.java b/src/com/android/settings/network/telephony/WarningDialogFragment.java
new file mode 100644
index 0000000..58bc1da
--- /dev/null
+++ b/src/com/android/settings/network/telephony/WarningDialogFragment.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2024 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.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentActivity;
+
+import com.android.settings.R;
+
+/** Fragment to show a warning dialog. The caller should implement onConfirmListener. */
+public class WarningDialogFragment extends BaseDialogFragment
+ implements DialogInterface.OnClickListener {
+ private static final String TAG = "WarningDialogFragment";
+ private static final String ARG_TITLE = "title";
+ private static final String ARG_MSG = "msg";
+ private static final String ARG_POS_BUTTON_STRING = "pos_button_string";
+ private static final String ARG_NEG_BUTTON_STRING = "neg_button_string";
+
+ /**
+ * Interface defining the method that will be invoked when the user has done with the dialog.
+ */
+ public interface OnConfirmListener {
+ /**
+ * @param tag The tag in the caller.
+ * @param confirmed True if the user has clicked the positive button. False if the user has
+ * clicked the negative button or cancel the dialog.
+ */
+ void onConfirm(int tag, boolean confirmed);
+ }
+
+ /** Displays a confirmation dialog which has confirm and cancel buttons. */
+ static <T> void show(
+ FragmentActivity activity,
+ Class<T> callbackInterfaceClass,
+ int tagInCaller,
+ String title,
+ String msg,
+ String posButtonString,
+ String negButtonString) {
+ WarningDialogFragment fragment = new WarningDialogFragment();
+ Bundle arguments = new Bundle();
+ arguments.putString(ARG_TITLE, title);
+ arguments.putCharSequence(ARG_MSG, msg);
+ arguments.putString(ARG_POS_BUTTON_STRING, posButtonString);
+ arguments.putString(ARG_NEG_BUTTON_STRING, negButtonString);
+ setListener(activity, null, callbackInterfaceClass, tagInCaller, arguments);
+ fragment.setArguments(arguments);
+ fragment.show(activity.getSupportFragmentManager(), TAG);
+ }
+
+ @Override
+ @NonNull
+ public final Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ String title = getArguments().getString(ARG_TITLE);
+ String message = getArguments().getString(ARG_MSG);
+ String leftButton = getArguments().getString(ARG_POS_BUTTON_STRING);
+ String rightButton = getArguments().getString(ARG_NEG_BUTTON_STRING);
+
+ Log.i(TAG, "Showing dialog with title =" + title);
+ AlertDialog.Builder builder =
+ new AlertDialog.Builder(getContext())
+ .setPositiveButton(rightButton, this)
+ .setNegativeButton(leftButton, this);
+
+ View content =
+ LayoutInflater.from(getContext())
+ .inflate(R.layout.sim_warning_dialog_wifi_connectivity, null);
+
+ if (content != null) {
+ TextView dialogTitle = content.findViewById(R.id.title);
+ if (!TextUtils.isEmpty(title) && dialogTitle != null) {
+ dialogTitle.setText(title);
+ dialogTitle.setVisibility(View.VISIBLE);
+ }
+ TextView dialogMessage = content.findViewById(R.id.msg);
+ if (!TextUtils.isEmpty(message) && dialogMessage != null) {
+ dialogMessage.setText(message);
+ dialogMessage.setVisibility(View.VISIBLE);
+ }
+
+ builder.setView(content);
+ } else {
+ if (!TextUtils.isEmpty(title)) {
+ builder.setTitle(title);
+ }
+ if (!TextUtils.isEmpty(message)) {
+ builder.setMessage(message);
+ }
+ }
+
+ AlertDialog dialog = builder.create();
+ dialog.setCanceledOnTouchOutside(false);
+ return dialog;
+ }
+
+ @Override
+ public void onClick(@NonNull DialogInterface dialog, int which) {
+ Log.i(TAG, "dialog onClick =" + which);
+
+ // Positions of the buttons have been switch:
+ // negative button = left button = the button to continue
+ informCaller(which == DialogInterface.BUTTON_NEGATIVE);
+ }
+
+ @Override
+ public void onCancel(@NonNull DialogInterface dialog) {
+ informCaller(false);
+ }
+
+ private void informCaller(boolean confirmed) {
+ OnConfirmListener listener;
+ try {
+ listener = getListener(OnConfirmListener.class);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Do nothing and return.", e);
+ return;
+ }
+ if (listener == null) {
+ return;
+ }
+ listener.onConfirm(getTagInCaller(), confirmed);
+ }
+}
diff --git a/src/com/android/settings/widget/CardPreference.kt b/src/com/android/settings/widget/CardPreference.kt
index 7122ac6..010d7de 100644
--- a/src/com/android/settings/widget/CardPreference.kt
+++ b/src/com/android/settings/widget/CardPreference.kt
@@ -61,6 +61,9 @@
/** The visibility of secondary button on tips card. The default value is `false`. */
var secondaryButtonVisibility: Boolean = false
+ var onClick: (() -> Unit)? = null
+
+ /** The callback for click on card preference itself. */
private var onDismiss: (() -> Unit)? = null
/** Enable the dismiss button on tips card. */
@@ -84,9 +87,10 @@
buttons = listOfNotNull(configPrimaryButton(), configSecondaryButton()),
onDismiss = onDismiss,
imageVector =
- iconResId
- ?.takeIf { it != Resources.ID_NULL }
- ?.let { ImageVector.vectorResource(it) },
+ iconResId
+ ?.takeIf { it != Resources.ID_NULL }
+ ?.let { ImageVector.vectorResource(it) },
+ onClick = onClick,
)
)
}
diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp
index 5648290..1c6794d 100644
--- a/tests/robotests/Android.bp
+++ b/tests/robotests/Android.bp
@@ -71,10 +71,12 @@
"Settings-testutils2",
"notification_flags_lib",
"com_android_server_accessibility_flags_lib",
+ "testables",
],
libs: [
"ims-common",
+ "android.test.mock",
],
java_resource_dirs: [
diff --git a/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java
index 13f0b24..b2ddb6c 100644
--- a/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java
@@ -28,6 +28,9 @@
import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_SETUP_FLOW;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.content.ComponentName;
@@ -35,7 +38,9 @@
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
+import android.util.Pair;
import android.view.accessibility.AccessibilityManager;
import androidx.fragment.app.FragmentActivity;
@@ -46,6 +51,7 @@
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.accessibility.common.ShortcutConstants;
+import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.internal.accessibility.util.ShortcutUtils;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
@@ -60,6 +66,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
@@ -89,6 +96,9 @@
private static final String TARGET = MAGNIFICATION_CONTROLLER_NAME;
private static final Set<String> TARGETS = Set.of(TARGET);
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private final Context mContext = ApplicationProvider.getApplicationContext();
private FragmentActivity mActivity;
private FragmentScenario<EditShortcutsPreferenceFragment> mFragmentScenario;
@@ -414,6 +424,60 @@
}
+ @Test
+ public void findTitles_withSingleTarget_hasNullSubtitle() {
+ final String fake_label = "FAKE";
+ List<AccessibilityTarget> accessibilityTargets = List.of(
+ generateAccessibilityTargetMock(TARGET_FAKE_COMPONENT, fake_label));
+
+ Pair<String, String> titles = EditShortcutsPreferenceFragment
+ .getTitlesFromAccessibilityTargetList(
+ Set.of(TARGET_FAKE_COMPONENT.flattenToString()),
+ accessibilityTargets, mActivity.getResources()
+ );
+
+ assertThat(titles.first).isNotNull();
+ assertThat(titles.first).contains(fake_label);
+ assertThat(titles.second).isNull();
+ }
+
+ @Test
+ public void findTitles_withMoreTargets_hasSubtitle() {
+ final String fake_label = "FAKE";
+ final String magnification_label = "MAGNIFICATION";
+ List<AccessibilityTarget> accessibilityTargets = List.of(
+ generateAccessibilityTargetMock(TARGET_FAKE_COMPONENT, fake_label),
+ generateAccessibilityTargetMock(MAGNIFICATION_COMPONENT_NAME, magnification_label));
+
+ Pair<String, String> titles = EditShortcutsPreferenceFragment
+ .getTitlesFromAccessibilityTargetList(
+ Set.of(TARGET_FAKE_COMPONENT.flattenToString(),
+ MAGNIFICATION_COMPONENT_NAME.flattenToString()),
+ accessibilityTargets, mActivity.getResources()
+ );
+
+ assertThat(titles.first).isNotNull();
+ assertThat(titles.second).isNotNull();
+ assertThat(titles.second).contains(fake_label);
+ assertThat(titles.second).contains(magnification_label);
+ }
+
+ @Test
+ public void findTitles_targetMissing_labelNotInTitles() {
+ final String fake_label = "FAKE";
+ List<AccessibilityTarget> accessibilityTargets = List.of(
+ generateAccessibilityTargetMock(TARGET_FAKE_COMPONENT, fake_label));
+
+ assertThrows(IllegalStateException.class,
+ () -> EditShortcutsPreferenceFragment
+ .getTitlesFromAccessibilityTargetList(
+ Set.of(MAGNIFICATION_COMPONENT_NAME.flattenToString()),
+ accessibilityTargets, mActivity.getResources()
+ ));
+ }
+
+
+
private void assertLaunchSubSettingWithCurrentTargetComponents(
String componentName, boolean isInSuw) {
Intent intent = shadowOf(mActivity.getApplication()).getNextStartedActivity();
@@ -480,4 +544,12 @@
intent.putExtra(EXTRA_IS_DEFERRED_SETUP, isInSuw);
return intent;
}
+
+ private AccessibilityTarget generateAccessibilityTargetMock(
+ ComponentName componentName, String label) {
+ AccessibilityTarget target = mock(AccessibilityTarget.class);
+ when(target.getComponentName()).thenReturn(componentName);
+ when(target.getLabel()).thenReturn(label);
+ return target;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java b/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
index 1d76806..e2c9573 100644
--- a/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
+++ b/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
@@ -41,9 +41,11 @@
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
+import android.platform.test.flag.junit.SetFlagsRule;
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
@@ -85,6 +87,9 @@
@Mock
private PackageManager mPackageManager;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private int mInstalledAppCount = -1;
private ApplicationInfo mApp1;
private ApplicationInfo mApp2;
@@ -218,6 +223,7 @@
eq(MAIN_USER_ID))).thenReturn(Arrays.asList(mApp2));
mFakeFeatureFlags.setFlag(Flags.FLAG_ARCHIVING, false);
+ mSetFlagsRule.disableFlags(com.android.settings.flags.Flags.FLAG_APP_ARCHIVING);
// Count the number of all apps installed, irrespective of install reason.
count(InstalledAppCounter.IGNORE_INSTALL_REASON, mFakeFeatureFlags);
assertThat(mInstalledAppCount).isEqualTo(1);
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
index 4fdf560..46d1cc3 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
@@ -35,6 +35,7 @@
import static org.mockito.Mockito.when;
import android.app.admin.DevicePolicyManager;
+import android.app.ecm.EnhancedConfirmationManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -90,7 +91,8 @@
private DevicePolicyManager mDevicePolicyManager;
@Mock
private PackageManager mPackageManager;
-
+ @Mock
+ private EnhancedConfirmationManager mEcManager;
private AppInfoDashboardFragment mFragment;
private Context mShadowContext;
@@ -102,6 +104,7 @@
doReturn(mActivity).when(mFragment).getActivity();
doReturn(mShadowContext).when(mFragment).getContext();
doReturn(mPackageManager).when(mActivity).getPackageManager();
+ doReturn(mEcManager).when(mActivity).getSystemService(EnhancedConfirmationManager.class);
when(mUserManager.isAdminUser()).thenReturn(true);
ReflectionHelpers.setField(mFragment, "mUserManager", mUserManager);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsControllerTestBase.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsControllerTestBase.java
index 8ba0b44..4edf117 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsControllerTestBase.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsControllerTestBase.java
@@ -43,6 +43,7 @@
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
com.android.settings.testutils.shadow.ShadowFragment.class,
+ com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal.class,
})
public abstract class BluetoothDetailsControllerTestBase {
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
index e5964d0..357420a 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
@@ -22,27 +22,23 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doNothing;
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 static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
-import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.AudioManager;
-import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager;
@@ -51,19 +47,16 @@
import com.android.settings.R;
import com.android.settings.bluetooth.AvailableMediaBluetoothDeviceUpdater;
import com.android.settings.bluetooth.Utils;
-import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowAudioManager;
-import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HearingAidInfo;
-import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Rule;
@@ -76,16 +69,12 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
-import org.robolectric.shadow.api.Shadow;
-
-import java.util.concurrent.Executor;
/** Tests for {@link AvailableMediaDeviceGroupController}. */
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
ShadowAudioManager.class,
- ShadowBluetoothAdapter.class,
ShadowBluetoothUtils.class,
ShadowAlertDialogCompat.class,
})
@@ -105,9 +94,7 @@
@Mock private PackageManager mPackageManager;
@Mock private BluetoothEventManager mEventManager;
@Mock private LocalBluetoothManager mLocalBluetoothManager;
- @Mock private LocalBluetoothProfileManager mLocalBtProfileManager;
@Mock private CachedBluetoothDeviceManager mCachedDeviceManager;
- @Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
@Mock private CachedBluetoothDevice mCachedBluetoothDevice;
private PreferenceGroup mPreferenceGroup;
@@ -115,13 +102,16 @@
private Preference mPreference;
private AvailableMediaDeviceGroupController mAvailableMediaDeviceGroupController;
private AudioManager mAudioManager;
- private ShadowBluetoothAdapter mShadowBluetoothAdapter;
+ private LifecycleOwner mLifecycleOwner;
+ private Lifecycle mLifecycle;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
+ mLifecycleOwner = () -> mLifecycle;
+ mLifecycle = new Lifecycle(mLifecycleOwner);
mPreference = new Preference(mContext);
mPreference.setKey(PREFERENCE_KEY_1);
mPreferenceGroup = spy(new PreferenceScreen(mContext, null));
@@ -130,24 +120,17 @@
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
- mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
- mShadowBluetoothAdapter.setEnabled(true);
- mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
- BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
- mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
- BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
mAudioManager = mContext.getSystemService(AudioManager.class);
doReturn(mEventManager).when(mLocalBluetoothManager).getEventManager();
- when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBtProfileManager);
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
when(mCachedDeviceManager.findDevice(any(BluetoothDevice.class)))
.thenReturn(mCachedBluetoothDevice);
when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
mAvailableMediaDeviceGroupController =
- spy(new AvailableMediaDeviceGroupController(mContext));
+ spy(new AvailableMediaDeviceGroupController(mContext, null, mLifecycle));
mAvailableMediaDeviceGroupController.setBluetoothDeviceUpdater(
mAvailableMediaBluetoothDeviceUpdater);
mAvailableMediaDeviceGroupController.setFragmentManager(
@@ -197,7 +180,7 @@
@Test
public void testRegister() {
// register the callback in onStart()
- mAvailableMediaDeviceGroupController.onStart();
+ mAvailableMediaDeviceGroupController.onStart(mLifecycleOwner);
verify(mAvailableMediaBluetoothDeviceUpdater).registerCallback();
verify(mLocalBluetoothManager.getEventManager())
@@ -206,36 +189,15 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
- public void testRegister_audioSharingOn() {
- setUpBroadcast();
- // register the callback in onStart()
- mAvailableMediaDeviceGroupController.onStart();
- verify(mAssistant)
- .registerServiceCallBack(
- any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
- }
-
- @Test
public void testUnregister() {
// unregister the callback in onStop()
- mAvailableMediaDeviceGroupController.onStop();
+ mAvailableMediaDeviceGroupController.onStop(mLifecycleOwner);
verify(mAvailableMediaBluetoothDeviceUpdater).unregisterCallback();
verify(mLocalBluetoothManager.getEventManager())
.unregisterCallback(any(BluetoothCallback.class));
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
- public void testUnregister_audioSharingOn() {
- setUpBroadcast();
- // unregister the callback in onStop()
- mAvailableMediaDeviceGroupController.onStop();
- verify(mAssistant)
- .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
- }
-
- @Test
public void testGetAvailabilityStatus_noBluetoothFeature_returnUnSupported() {
doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
@@ -274,7 +236,7 @@
mAvailableMediaDeviceGroupController.mLocalBluetoothManager = null;
// Shouldn't crash
- mAvailableMediaDeviceGroupController.onStart();
+ mAvailableMediaDeviceGroupController.onStart(mLifecycleOwner);
}
@Test
@@ -282,7 +244,7 @@
mAvailableMediaDeviceGroupController.mLocalBluetoothManager = null;
// Shouldn't crash
- mAvailableMediaDeviceGroupController.onStop();
+ mAvailableMediaDeviceGroupController.onStop(mLifecycleOwner);
}
@Test
@@ -300,19 +262,4 @@
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog.isShowing()).isTrue();
}
-
- private void setUpBroadcast() {
- mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
- BluetoothStatusCodes.FEATURE_SUPPORTED);
- mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
- BluetoothStatusCodes.FEATURE_SUPPORTED);
- when(mLocalBtProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
- doNothing()
- .when(mAssistant)
- .registerServiceCallBack(
- any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
- doNothing()
- .when(mAssistant)
- .unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
- }
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
index 09f7a38..ee4f952 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
@@ -20,19 +20,25 @@
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 static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.PackageManager;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.SearchIndexableResource;
import com.android.settings.R;
+import com.android.settings.connecteddevice.fastpair.FastPairDeviceUpdater;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerListHelper;
+import com.android.settings.flags.Flags;
import com.android.settings.slices.SlicePreferenceController;
+import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowConnectivityManager;
import com.android.settings.testutils.shadow.ShadowUserManager;
@@ -60,6 +66,8 @@
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final String KEY_NEARBY_DEVICES = "bt_nearby_slice";
private static final String KEY_DISCOVERABLE_FOOTER = "discoverable_footer";
private static final String KEY_SAVED_DEVICE_SEE_ALL = "previously_connected_devices_see_all";
@@ -75,8 +83,11 @@
private static final String TEST_ACTION = "com.testapp.settings.ACTION_START";
@Mock private PackageManager mPackageManager;
+ @Mock private FastPairDeviceUpdater mFastPairDeviceUpdater;
private Context mContext;
private ConnectedDeviceDashboardFragment mFragment;
+ private FakeFeatureFactory mFeatureFactory;
+ private AvailableMediaDeviceGroupController mMediaDeviceGroupController;
@Before
public void setUp() {
@@ -84,6 +95,22 @@
mContext = spy(RuntimeEnvironment.application);
mFragment = new ConnectedDeviceDashboardFragment();
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION);
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
+ when(mFeatureFactory
+ .getFastPairFeatureProvider()
+ .getFastPairDeviceUpdater(
+ any(Context.class), any(DevicePreferenceCallback.class)))
+ .thenReturn(mFastPairDeviceUpdater);
+ when(mFeatureFactory
+ .getAudioSharingFeatureProvider()
+ .createAudioSharingDevicePreferenceController(mContext, null, null))
+ .thenReturn(null);
+ mMediaDeviceGroupController = new AvailableMediaDeviceGroupController(mContext, null, null);
+ when(mFeatureFactory
+ .getAudioSharingFeatureProvider()
+ .createAvailableMediaDeviceGroupController(mContext, null, null))
+ .thenReturn(mMediaDeviceGroupController);
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProviderImplTest.java
index 0edbc77..1965bff 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingFeatureProviderImplTest.java
@@ -22,6 +22,7 @@
import androidx.test.core.app.ApplicationProvider;
+import com.android.settings.connecteddevice.AvailableMediaDeviceGroupController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -60,6 +61,14 @@
}
@Test
+ public void createAvailableMediaDeviceGroupController_returnsNull() {
+ assertThat(
+ mFeatureProvider.createAvailableMediaDeviceGroupController(
+ mContext, /* fragment= */ null, /* lifecycle= */ null))
+ .isInstanceOf(AvailableMediaDeviceGroupController.class);
+ }
+
+ @Test
public void isAudioSharingFilterMatched_returnsFalse() {
assertThat(mFeatureProvider.isAudioSharingFilterMatched(mCachedDevice, mLocalBtManager))
.isFalse();
diff --git a/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java
index 314120a..c7c76b1 100644
--- a/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java
@@ -16,6 +16,8 @@
package com.android.settings.development;
+import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED;
+
import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE;
import static com.android.settings.development.ForcePeakRefreshRatePreferenceController.NO_CONFIG;
@@ -24,15 +26,18 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.content.Context;
+import android.hardware.display.DisplayManager;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
+import android.testing.TestableContext;
+import android.view.Display;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.display.feature.flags.Flags;
@@ -43,7 +48,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@@ -53,17 +57,51 @@
private SwitchPreference mPreference;
@Mock
private PreferenceScreen mScreen;
+ @Mock
+ private DisplayManager mDisplayManagerMock;
+ @Mock
+ private Display mDisplayMock;
+ @Mock
+ private Display mDisplayMock2;
- private Context mContext;
private ForcePeakRefreshRatePreferenceController mController;
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+ @Rule
+ public final TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getContext());
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
+ mContext.addMockSystemService(DisplayManager.class, mDisplayManagerMock);
+
+ Display.Mode[] modes = new Display.Mode[]{
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 60),
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 120),
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 90)
+ };
+ when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
+ when(mDisplayMock.getSupportedModes()).thenReturn(modes);
+
+ Display.Mode[] modes2 = new Display.Mode[]{
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 70),
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 130),
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 80)
+ };
+ when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY + 1)).thenReturn(mDisplayMock2);
+ when(mDisplayMock2.getSupportedModes()).thenReturn(modes2);
+
+ when(mDisplayManagerMock.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED))
+ .thenReturn(new Display[]{ mDisplayMock, mDisplayMock2 });
+
mController = new ForcePeakRefreshRatePreferenceController(mContext);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
when(mPreference.getKey()).thenReturn(mController.getPreferenceKey());
@@ -153,4 +191,16 @@
assertThat(mPreference.isChecked()).isFalse();
assertThat(mPreference.isEnabled()).isFalse();
}
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE)
+ public void peakRefreshRate_highestOfDefaultDisplay_featureFlagOff() {
+ assertThat(mController.mPeakRefreshRate).isEqualTo(120);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE)
+ public void peakRefreshRate_highestOfAllDisplays_featureFlagOn() {
+ assertThat(mController.mPeakRefreshRate).isEqualTo(130);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/display/PeakRefreshRatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/PeakRefreshRatePreferenceControllerTest.java
index cb0963b..f8e91bd 100644
--- a/tests/robotests/src/com/android/settings/display/PeakRefreshRatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/PeakRefreshRatePreferenceControllerTest.java
@@ -16,6 +16,8 @@
package com.android.settings.display;
+import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED;
+
import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
@@ -24,14 +26,17 @@
import static org.mockito.Mockito.when;
-import android.content.Context;
+import android.hardware.display.DisplayManager;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
+import android.testing.TestableContext;
+import android.view.Display;
import androidx.preference.SwitchPreference;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.display.feature.flags.Flags;
@@ -48,21 +53,55 @@
@RunWith(RobolectricTestRunner.class)
public class PeakRefreshRatePreferenceControllerTest {
- private Context mContext;
private PeakRefreshRatePreferenceController mController;
private SwitchPreference mPreference;
@Mock
private PeakRefreshRatePreferenceController.DeviceConfigDisplaySettings
mDeviceConfigDisplaySettings;
+ @Mock
+ private DisplayManager mDisplayManagerMock;
+ @Mock
+ private Display mDisplayMock;
+ @Mock
+ private Display mDisplayMock2;
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+ @Rule
+ public final TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getContext());
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
+ mContext.addMockSystemService(DisplayManager.class, mDisplayManagerMock);
+
+ Display.Mode[] modes = new Display.Mode[]{
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 60),
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 120),
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 90)
+ };
+ when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
+ when(mDisplayMock.getSupportedModes()).thenReturn(modes);
+
+ Display.Mode[] modes2 = new Display.Mode[]{
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 70),
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 130),
+ new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+ /* refreshRate= */ 80)
+ };
+ when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY + 1)).thenReturn(mDisplayMock2);
+ when(mDisplayMock2.getSupportedModes()).thenReturn(modes2);
+
+ when(mDisplayManagerMock.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED))
+ .thenReturn(new Display[]{ mDisplayMock, mDisplayMock2 });
+
mController = new PeakRefreshRatePreferenceController(mContext, "key");
mController.injectDeviceConfigDisplaySettings(mDeviceConfigDisplaySettings);
mPreference = new SwitchPreference(RuntimeEnvironment.application);
@@ -152,4 +191,16 @@
assertThat(mController.isChecked()).isFalse();
}
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE)
+ public void peakRefreshRate_highestOfDefaultDisplay_featureFlagOff() {
+ assertThat(mController.mPeakRefreshRate).isEqualTo(120);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE)
+ public void peakRefreshRate_highestOfAllDisplays_featureFlagOn() {
+ assertThat(mController.mPeakRefreshRate).isEqualTo(130);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/network/SubscriptionUtilRoboTest.java b/tests/robotests/src/com/android/settings/network/SubscriptionUtilRoboTest.java
new file mode 100644
index 0000000..2595510
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/SubscriptionUtilRoboTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2024 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 static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
+import android.telephony.SubscriptionManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
+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.shadows.ShadowSubscriptionManager;
+
+@RunWith(RobolectricTestRunner.class)
+public class SubscriptionUtilRoboTest {
+ private static final int SUBID_1 = 1;
+ private static final int SUBID_2 = 2;
+
+ private Context mContext;
+ private NetworkCapabilities mNetworkCapabilities;
+ private ShadowSubscriptionManager mShadowSubscriptionManager;
+
+ @Mock
+ private ConnectivityManager mConnectivityManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mShadowSubscriptionManager = shadowOf(mContext.getSystemService(SubscriptionManager.class));
+ when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager);
+ }
+
+ @Test
+ public void isConnectedToWifiOrDifferentSubId_hasDataOnSubId2_returnTrue() {
+ addNetworkTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ mShadowSubscriptionManager.setActiveDataSubscriptionId(SUBID_2);
+
+ assertTrue(SubscriptionUtil.isConnectedToWifiOrDifferentSubId(mContext, SUBID_1));
+ }
+
+ @Test
+ public void isConnectedToWifiOrDifferentSubId_hasDataOnSubId1_returnFalse() {
+ addNetworkTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ mShadowSubscriptionManager.setActiveDataSubscriptionId(SUBID_1);
+
+ assertFalse(SubscriptionUtil.isConnectedToWifiOrDifferentSubId(mContext, SUBID_1));
+ }
+
+ private void addNetworkTransportType(int networkType) {
+ mNetworkCapabilities =
+ new NetworkCapabilities.Builder().addTransportType(networkType).build();
+ when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowAudioManager.java
similarity index 92%
rename from tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java
rename to tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowAudioManager.java
index 9c06665..b465a41 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAudioManager.java
+++ b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowAudioManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -38,6 +38,7 @@
import java.util.ArrayList;
import java.util.List;
+/** Robolectric shadow for the AudioManager. */
@Implements(value = AudioManager.class)
public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManager {
private int mRingerMode;
@@ -58,11 +59,13 @@
mRingerMode = mode;
}
+ /** Register audio device callback. */
@Implementation
public void registerAudioDeviceCallback(AudioDeviceCallback callback, Handler handler) {
mDeviceCallbacks.add(callback);
}
+ /** Unregister audio device callback. */
@Implementation
public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
if (mDeviceCallbacks.contains(callback)) {
@@ -79,10 +82,12 @@
return mMusicActiveRemotely;
}
+ /** Set output device. */
public void setOutputDevice(int deviceCodes) {
mDeviceCodes = deviceCodes;
}
+ /** Get devices for stream. */
@Implementation
public int getDevicesForStream(int streamType) {
switch (streamType) {
diff --git a/tests/spa_unit/src/com/android/settings/development/SensitiveContentProtectionPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/development/SensitiveContentProtectionPreferenceControllerTest.kt
index 18acbba..023572b 100644
--- a/tests/spa_unit/src/com/android/settings/development/SensitiveContentProtectionPreferenceControllerTest.kt
+++ b/tests/spa_unit/src/com/android/settings/development/SensitiveContentProtectionPreferenceControllerTest.kt
@@ -22,6 +22,7 @@
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.provider.Settings
import android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS
+import android.view.flags.Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION
import androidx.preference.Preference
import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreference
@@ -132,7 +133,8 @@
@Test
@RequiresFlagsDisabled(
FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION,
- FLAG_SCREENSHARE_NOTIFICATION_HIDING)
+ FLAG_SCREENSHARE_NOTIFICATION_HIDING,
+ FLAG_SENSITIVE_CONTENT_APP_PROTECTION)
fun isAvailable_flagsDisabled_returnFalse() {
assertFalse(controller.isAvailable)
}
@@ -148,4 +150,10 @@
fun isAvailable_screenshareNotificationHidingEnabled_returnTrue() {
assertTrue(controller.isAvailable)
}
-}
\ No newline at end of file
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_SENSITIVE_CONTENT_APP_PROTECTION)
+ fun isAvailable_screenshareSensitiveContentHidingEnabled_returnTrue() {
+ assertTrue(controller.isAvailable)
+ }
+}
diff --git a/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java b/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
index 587e734..3b9ac9d 100644
--- a/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
+++ b/tests/unit/src/com/android/settings/network/SubscriptionUtilTest.java
@@ -18,9 +18,13 @@
import static com.android.settings.network.SubscriptionUtil.KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME;
import static com.android.settings.network.SubscriptionUtil.SUB_ID;
+
import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@@ -30,6 +34,8 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -61,13 +67,15 @@
private static final CharSequence CARRIER_2 = "carrier2";
private Context mContext;
+ private NetworkCapabilities mNetworkCapabilities;
+
@Mock
private SubscriptionManager mSubMgr;
@Mock
private TelephonyManager mTelMgr;
@Mock
private Resources mResources;
-
+ @Mock private ConnectivityManager mConnectivityManager;
@Before
public void setUp() {
@@ -75,6 +83,7 @@
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubMgr);
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelMgr);
+ when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager);
when(mTelMgr.getUiccSlotsInfo()).thenReturn(null);
}
@@ -588,4 +597,24 @@
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse();
}
+
+ @Test
+ public void isConnectedToWifiOrDifferentSubId_hasWiFi_returnTrue() {
+ addNetworkTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+
+ assertTrue(SubscriptionUtil.isConnectedToWifiOrDifferentSubId(mContext, SUBID_1));
+ }
+
+ @Test
+ public void isConnectedToWifiOrDifferentSubId_noData_and_noWiFi_returnFalse() {
+ addNetworkTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH);
+
+ assertFalse(SubscriptionUtil.isConnectedToWifiOrDifferentSubId(mContext, SUBID_1));
+ }
+
+ private void addNetworkTransportType(int networkType) {
+ mNetworkCapabilities =
+ new NetworkCapabilities.Builder().addTransportType(networkType).build();
+ when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
+ }
}