Snap for 11498394 from a6b7dff37b to 24Q2-release

Change-Id: I443b6b37af7a867eeb59890f96f54a515a2b556d
This commit is contained in:
Android Build Coastguard Worker
2024-02-27 02:59:13 +00:00
30 changed files with 1021 additions and 302 deletions

View File

@@ -818,6 +818,10 @@
android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
android:theme="@style/Theme.AlertDialog.SimConfirmDialog"/> android:theme="@style/Theme.AlertDialog.SimConfirmDialog"/>
<activity android:name=".network.telephony.EuiccRacConnectivityDialogActivity"
android:exported="false"
android:theme="@style/Theme.AlertDialog.SimConfirmDialog"/>
<activity <activity
android:name="Settings$TetherSettingsActivity" android:name="Settings$TetherSettingsActivity"
android:label="@string/tether_settings_title_all" android:label="@string/tether_settings_title_all"

View File

@@ -43,28 +43,28 @@
android:src="@drawable/private_space_illustration"/> android:src="@drawable/private_space_illustration"/>
<TextView <TextView
style="@style/PrivateSpaceSetupSubHeaderStyle" style="@style/PrivateSpaceSetupSubHeaderStyle"
android:text="@string/private_space_how_title"/> android:text="@string/private_space_setup_sub_header"/>
<RelativeLayout <RelativeLayout
style="@style/PrivateSpaceSetupBulletPointLayoutStyle"> style="@style/PrivateSpaceSetupBulletPointLayoutStyle">
<ImageView <ImageView
android:id="@+id/lockIcon" android:id="@+id/lockIcon"
style="@style/PrivateSpaceBulletPointIconStyle" style="@style/PrivateSpaceBulletPointIconStyle"
android:src="@drawable/ic_lock_closed" /> android:src="@drawable/counter_1_24dp" />
<TextView <TextView
style="@style/PrivateSpaceBulletPointTextFontStyle" style="@style/PrivateSpaceBulletPointTextFontStyle"
android:layout_toRightOf="@+id/lockIcon" android:layout_toRightOf="@+id/lockIcon"
android:text="@string/private_space_protected_lock_text"/> android:text="@string/private_space_separate_account_text"/>
</RelativeLayout> </RelativeLayout>
<RelativeLayout <RelativeLayout
style="@style/PrivateSpaceSetupBulletPointLayoutStyle"> style="@style/PrivateSpaceSetupBulletPointLayoutStyle">
<ImageView <ImageView
android:id="@+id/bellIcon" android:id="@+id/bellIcon"
style="@style/PrivateSpaceBulletPointIconStyle" style="@style/PrivateSpaceBulletPointIconStyle"
android:src="@drawable/ic_notifications" /> android:src="@drawable/counter_2_24dp" />
<TextView <TextView
style="@style/PrivateSpaceBulletPointTextFontStyle" style="@style/PrivateSpaceBulletPointTextFontStyle"
android:layout_toRightOf="@+id/bellIcon" android:layout_toRightOf="@+id/bellIcon"
android:text="@string/private_space_hidden_notifications_text"/> android:text="@string/private_space_protected_lock_text"/>
</RelativeLayout> </RelativeLayout>
<RelativeLayout <RelativeLayout
style="@style/PrivateSpaceSetupBulletPointLayoutStyle" style="@style/PrivateSpaceSetupBulletPointLayoutStyle"
@@ -73,11 +73,11 @@
<ImageView <ImageView
android:id="@+id/appsIcon" android:id="@+id/appsIcon"
style="@style/PrivateSpaceBulletPointIconStyle" style="@style/PrivateSpaceBulletPointIconStyle"
android:src="@drawable/ic_apps" /> android:src="@drawable/counter_3_24dp" />
<TextView <TextView
style="@style/PrivateSpaceBulletPointTextFontStyle" style="@style/PrivateSpaceBulletPointTextFontStyle"
android:layout_toRightOf="@+id/appsIcon" android:layout_toRightOf="@+id/appsIcon"
android:text="@string/private_space_access_bottom_text"/> android:text="@string/private_space_install_apps_text"/>
</RelativeLayout> </RelativeLayout>
<Space <Space
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@@ -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>

View File

@@ -1313,25 +1313,25 @@
<!-- Label for private space setup button to create private space [CHAR LIMIT=30] --> <!-- Label for private space setup button to create private space [CHAR LIMIT=30] -->
<string name="private_space_setup_button_label">Set up</string> <string name="private_space_setup_button_label">Set up</string>
<!-- Title for Private Space setup education screen. [CHAR LIMIT=50] --> <!-- Title for Private Space setup education screen. [CHAR LIMIT=50] -->
<string name="private_space_setup_title">Set up a private space</string> <string name="private_space_setup_title">Private space</string>
<!-- Summary for the private space setup education screen. [CHAR LIMIT=NONE] --> <!-- Summary for the private space setup education screen. [CHAR LIMIT=NONE] -->
<string name="private_space_hide_apps_summary">Keep private apps in a separate space that you can hide or lock</string> <string name="private_space_hide_apps_summary">Hide or lock private apps in a separate space. Use a dedicated Google Account for extra security.</string>
<!-- Text shown in private space setup screen which explains how the private space works [CHAR LIMIT=50] --> <!-- Text shown in private space setup screen which explains how the private space works [CHAR LIMIT=50] -->
<string name="private_space_how_title">How it works</string> <string name="private_space_setup_sub_header">Set up your private space</string>
<!-- Text shown in private space setup screen which explains private space can be accessed from bottom of all apps list. [CHAR LIMIT=NONE] --> <!-- Text shown in private space setup screen which explains private space can be accessed from bottom of all apps list. [CHAR LIMIT=NONE] -->
<string name="private_space_access_bottom_text">You can access your private space from the bottom of your apps list</string> <string name="private_space_separate_account_text"><b>Choose a Google Account for your space</b>\nUsing a dedicated account helps to stop synced files, photos, and emails appearing outside your space</string>
<!-- Text shown in private space setup screen which explains private space apps are protected by a lock. [CHAR LIMIT=60] --> <!-- Text shown in private space setup screen which explains private space apps are protected by a lock. [CHAR LIMIT=NONE] -->
<string name="private_space_protected_lock_text">Apps in your private space are protected by a lock</string> <string name="private_space_protected_lock_text"><b>Set a lock</b>\nLock your space to stop other people opening it</string>
<!-- Text shown in private space setup screen which explains notifications from private space apps will not be shown when private space is locked. [CHAR LIMIT=NONE] --> <!-- Text shown in private space setup screen which explains notifications from private space apps will not be shown when private space is locked. [CHAR LIMIT=NONE] -->
<string name="private_space_hidden_notifications_text">Notifications from apps in your private space are hidden when it\u2019s locked</string> <string name="private_space_install_apps_text"><b>Install apps</b>\nYour private space has its own Play Store so you can install apps easily.</string>
<!-- This is info text to help explain in private space setup screen that the permissions granted to private space apps will not be shown in settings when private space is locked. [CHAR LIMIT=NONE] --> <!-- This is info text to help explain in private space setup screen that the permissions granted to private space apps will not be shown in settings when private space is locked. [CHAR LIMIT=NONE] -->
<string name="private_space_apps_permission_text">Apps in your private space won\'t appear in permission manager, privacy dashboard, and other settings when your private space is locked.\n\nYour private space can\'t be moved to a new device. You\'ll need to set up another private space if you want to use it on another device.\n\nAnyone that connects your device to a computer or installs harmful apps on your device may be able to access your private space.</string> <string name="private_space_apps_permission_text">Apps in your private space won\'t appear in permission manager, privacy dashboard, and other settings when your private space is locked.\n\nYour private space can\'t be moved to a new device. You\'ll need to set up another private space if you want to use it on another device.\n\nAnyone that connects your device to a computer or installs harmful apps on your device may be able to access your private space.</string>
<!-- Text shown at the bottom in private space auto advancing screens. [CHAR LIMIT=60] --> <!-- Text shown at the bottom in private space auto advancing screens. [CHAR LIMIT=60] -->
<string name="private_space_setting_up_text">Setting up private space\u2026</string> <string name="private_space_setting_up_text">Setting up private space\u2026</string>
<!-- Title for private space setup in auto advancing screen informing private space notifications are hidden when locked. [CHAR LIMIT=NONE] --> <!-- Title for private space setup in auto advancing screen informing private space notifications are hidden when locked. [CHAR LIMIT=NONE] -->
<string name="private_space_notifications_hidden_title">Notifications from private space apps are hidden when it\u2019s locked</string> <string name="private_space_notifications_hidden_title">Notifications from private space apps are hidden when it\u2019s locked</string>
<!-- Title for private space setup in auto advancing screen informing photos/files from private space can be shared when unlocked. [CHAR LIMIT=NONE] --> <!-- Title for private space setup in auto advancing screen informing to explore private space settings for hide and auto lock. [CHAR LIMIT=NONE] -->
<string name="private_space_share_photos_title">Unlock private space to share photos or files</string> <string name="private_space_explore_settings_title">Explore private space settings to hide private space and set up automatic locking</string>
<!-- Title for private space setup in auto advancing screen informing some system apps are already installed in private space. [CHAR LIMIT=NONE] --> <!-- Title for private space setup in auto advancing screen informing some system apps are already installed in private space. [CHAR LIMIT=NONE] -->
<string name="private_space_apps_installed_title">Some apps are already installed in your private space</string> <string name="private_space_apps_installed_title">Some apps are already installed in your private space</string>
<!-- Title for private space creation error screen. [CHAR LIMIT=60] --> <!-- Title for private space creation error screen. [CHAR LIMIT=60] -->
@@ -2836,6 +2836,10 @@
<string name="dark_ui_bedtime_footer_summary">Dark theme is currently following your Bedtime mode schedule</string> <string name="dark_ui_bedtime_footer_summary">Dark theme is currently following your Bedtime mode schedule</string>
<!-- Dark UI screen footer action text shown when the when Dark theme turns on/off automatically according to a user bedtime schedule. [CHAR LIMIT=NONE] --> <!-- Dark UI screen footer action text shown when the when Dark theme turns on/off automatically according to a user bedtime schedule. [CHAR LIMIT=NONE] -->
<string name="dark_ui_bedtime_footer_action">Bedtime mode settings</string> <string name="dark_ui_bedtime_footer_action">Bedtime mode settings</string>
<!-- Even Dimmer setting title. Allows device to reduce brightness even further than standard range. [CHAR LIMIT=NONE] -->
<string name="even_dimmer_display_title">Even Dimmer</string>
<!-- Even Dimmer setting summary. [CHAR LIMIT=NONE] -->
<string name="even_dimmer_display_summary">Allow device to go dimmer than usual</string>
<!-- Sound & display settings screen, setting option name to change screen timeout --> <!-- Sound & display settings screen, setting option name to change screen timeout -->
@@ -11701,6 +11705,16 @@
<!-- Body text of error message indicating the device could not erase the SIM due to an error. [CHAR_LIMIT=NONE] --> <!-- 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> <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] --> <!-- Title for Network connection request Dialog [CHAR LIMIT=60] -->
<string name="network_connection_request_dialog_title">Connect to device</string> <string name="network_connection_request_dialog_title">Connect to device</string>
<!-- Summary for Network connection request Dialog [CHAR LIMIT=NONE] --> <!-- Summary for Network connection request Dialog [CHAR LIMIT=NONE] -->

View File

@@ -966,6 +966,7 @@
<item name="android:paddingTop">20dp</item> <item name="android:paddingTop">20dp</item>
<item name="android:paddingBottom">8dp</item> <item name="android:paddingBottom">8dp</item>
<item name="android:textSize">14sp</item> <item name="android:textSize">14sp</item>
<item name="android:fontFamily">google-sans-medium</item>
</style> </style>
<style name="PrivateSpaceSetupBulletPointLayoutStyle"> <style name="PrivateSpaceSetupBulletPointLayoutStyle">

View File

@@ -41,8 +41,7 @@
<PreferenceCategory <PreferenceCategory
android:key="available_device_list" android:key="available_device_list"
android:title="@string/connected_device_media_device_title" android:title="@string/connected_device_media_device_title"/>
settings:controller="com.android.settings.connecteddevice.AvailableMediaDeviceGroupController" />
<PreferenceCategory <PreferenceCategory
android:key="connected_device_list" android:key="connected_device_list"

View File

@@ -36,6 +36,11 @@
android:title="@string/auto_brightness_title" android:title="@string/auto_brightness_title"
android:fragment="com.android.settings.display.AutoBrightnessSettings" android:fragment="com.android.settings.display.AutoBrightnessSettings"
settings:controller="com.android.settings.display.AutoBrightnessPreferenceController"/> settings:controller="com.android.settings.display.AutoBrightnessPreferenceController"/>
<SwitchPreferenceCompat
android:key="even_dimmer_activated"
android:title="@string/even_dimmer_display_title"
android:summary="@string/even_dimmer_display_summary"
settings:controller="com.android.settings.display.EvenDimmerPreferenceController"/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory

View File

@@ -17,18 +17,17 @@ package com.android.settings.connecteddevice;
import static com.android.settingslib.Utils.isAudioModeOngoingCall; 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.bluetooth.BluetoothProfile;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
@@ -38,138 +37,66 @@ import com.android.settings.accessibility.HearingAidUtils;
import com.android.settings.bluetooth.AvailableMediaBluetoothDeviceUpdater; import com.android.settings.bluetooth.AvailableMediaBluetoothDeviceUpdater;
import com.android.settings.bluetooth.BluetoothDeviceUpdater; import com.android.settings.bluetooth.BluetoothDeviceUpdater;
import com.android.settings.bluetooth.Utils; import com.android.settings.bluetooth.Utils;
import com.android.settings.connecteddevice.audiosharing.AudioSharingUtils;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.Lifecycle;
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;
/** /**
* Controller to maintain the {@link androidx.preference.PreferenceGroup} for all available media * Controller to maintain the {@link androidx.preference.PreferenceGroup} for all available media
* devices. It uses {@link DevicePreferenceCallback} to add/remove {@link Preference} * devices. It uses {@link DevicePreferenceCallback} to add/remove {@link Preference}
*/ */
public class AvailableMediaDeviceGroupController extends BasePreferenceController 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 boolean DEBUG = BluetoothUtils.D;
private static final String TAG = "AvailableMediaDeviceGroupController"; private static final String TAG = "AvailableMediaDeviceGroupController";
private static final String KEY = "available_device_list"; private static final String KEY = "available_device_list";
@VisibleForTesting PreferenceGroup mPreferenceGroup; @VisibleForTesting @Nullable PreferenceGroup mPreferenceGroup;
@VisibleForTesting LocalBluetoothManager mLocalBluetoothManager; @VisibleForTesting LocalBluetoothManager mLocalBluetoothManager;
private final Executor mExecutor; @Nullable private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
private BluetoothDeviceUpdater mBluetoothDeviceUpdater; @Nullable private FragmentManager mFragmentManager;
private FragmentManager mFragmentManager;
private BluetoothLeBroadcastAssistant.Callback mAssistantCallback =
new BluetoothLeBroadcastAssistant.Callback() {
@Override
public void onSearchStarted(int reason) {}
@Override public AvailableMediaDeviceGroupController(
public void onSearchStartFailed(int reason) {} Context context,
@Nullable DashboardFragment fragment,
@Override @Nullable Lifecycle lifecycle) {
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) {
super(context, KEY); super(context, KEY);
if (fragment != null) {
init(fragment);
}
if (lifecycle != null) {
lifecycle.addObserver(this);
}
mLocalBluetoothManager = Utils.getLocalBtManager(mContext); mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
mExecutor = Executors.newSingleThreadExecutor();
} }
@Override @Override
public void onStart() { public void onStart(@NonNull LifecycleOwner owner) {
if (mLocalBluetoothManager == null) { if (mLocalBluetoothManager == null) {
Log.e(TAG, "onStart() Bluetooth is not supported on this device"); Log.e(TAG, "onStart() Bluetooth is not supported on this device");
return; 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); mLocalBluetoothManager.getEventManager().registerCallback(this);
if (mBluetoothDeviceUpdater != null) {
mBluetoothDeviceUpdater.registerCallback();
mBluetoothDeviceUpdater.refreshPreference(); mBluetoothDeviceUpdater.refreshPreference();
} }
}
@Override @Override
public void onStop() { public void onStop(@NonNull LifecycleOwner owner) {
if (mLocalBluetoothManager == null) { if (mLocalBluetoothManager == null) {
Log.e(TAG, "onStop() Bluetooth is not supported on this device"); Log.e(TAG, "onStop() Bluetooth is not supported on this device");
return; return;
} }
if (AudioSharingUtils.isFeatureEnabled()) { if (mBluetoothDeviceUpdater != null) {
LocalBluetoothLeBroadcastAssistant assistant =
mLocalBluetoothManager
.getProfileManager()
.getLeAudioBroadcastAssistantProfile();
if (assistant != null) {
if (DEBUG) {
Log.d(TAG, "onStop() Register callbacks for assistant.");
}
assistant.unregisterServiceCallBack(mAssistantCallback);
}
}
mBluetoothDeviceUpdater.unregisterCallback(); mBluetoothDeviceUpdater.unregisterCallback();
}
mLocalBluetoothManager.getEventManager().unregisterCallback(this); mLocalBluetoothManager.getEventManager().unregisterCallback(this);
} }
@@ -178,14 +105,18 @@ public class AvailableMediaDeviceGroupController extends BasePreferenceControlle
super.displayPreference(screen); super.displayPreference(screen);
mPreferenceGroup = screen.findPreference(KEY); mPreferenceGroup = screen.findPreference(KEY);
if (mPreferenceGroup != null) {
mPreferenceGroup.setVisible(false); mPreferenceGroup.setVisible(false);
}
if (isAvailable()) { if (isAvailable()) {
updateTitle(); updateTitle();
if (mBluetoothDeviceUpdater != null) {
mBluetoothDeviceUpdater.setPrefContext(screen.getContext()); mBluetoothDeviceUpdater.setPrefContext(screen.getContext());
mBluetoothDeviceUpdater.forceUpdate(); mBluetoothDeviceUpdater.forceUpdate();
} }
} }
}
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
@@ -201,19 +132,23 @@ public class AvailableMediaDeviceGroupController extends BasePreferenceControlle
@Override @Override
public void onDeviceAdded(Preference preference) { public void onDeviceAdded(Preference preference) {
if (mPreferenceGroup != null) {
if (mPreferenceGroup.getPreferenceCount() == 0) { if (mPreferenceGroup.getPreferenceCount() == 0) {
mPreferenceGroup.setVisible(true); mPreferenceGroup.setVisible(true);
} }
mPreferenceGroup.addPreference(preference); mPreferenceGroup.addPreference(preference);
} }
}
@Override @Override
public void onDeviceRemoved(Preference preference) { public void onDeviceRemoved(Preference preference) {
if (mPreferenceGroup != null) {
mPreferenceGroup.removePreference(preference); mPreferenceGroup.removePreference(preference);
if (mPreferenceGroup.getPreferenceCount() == 0) { if (mPreferenceGroup.getPreferenceCount() == 0) {
mPreferenceGroup.setVisible(false); mPreferenceGroup.setVisible(false);
} }
} }
}
public void init(DashboardFragment fragment) { public void init(DashboardFragment fragment) {
mFragmentManager = fragment.getParentFragmentManager(); mFragmentManager = fragment.getParentFragmentManager();
@@ -253,6 +188,7 @@ public class AvailableMediaDeviceGroupController extends BasePreferenceControlle
} }
private void updateTitle() { private void updateTitle() {
if (mPreferenceGroup != null) {
if (isAudioModeOngoingCall(mContext)) { if (isAudioModeOngoingCall(mContext)) {
// in phone call // in phone call
mPreferenceGroup.setTitle( mPreferenceGroup.setTitle(
@@ -264,3 +200,4 @@ public class AvailableMediaDeviceGroupController extends BasePreferenceControlle
} }
} }
} }
}

View File

@@ -24,12 +24,10 @@ import android.util.Log;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.connecteddevice.audiosharing.AudioSharingUtils;
import com.android.settings.core.SettingsUIDeviceConfig; import com.android.settings.core.SettingsUIDeviceConfig;
import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
@@ -38,6 +36,7 @@ import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.slices.SlicePreferenceController; import com.android.settings.slices.SlicePreferenceController;
import com.android.settingslib.bluetooth.HearingAidStatsLogUtils; import com.android.settingslib.bluetooth.HearingAidStatsLogUtils;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList; import java.util.ArrayList;
@@ -92,7 +91,6 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {
+ ", action : " + ", action : "
+ action); + action);
} }
use(AvailableMediaDeviceGroupController.class).init(this);
use(ConnectedDeviceGroupController.class).init(this); use(ConnectedDeviceGroupController.class).init(this);
use(PreviouslyConnectedDevicePreferenceController.class).init(this); use(PreviouslyConnectedDevicePreferenceController.class).init(this);
use(SlicePreferenceController.class) use(SlicePreferenceController.class)
@@ -124,16 +122,18 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {
@Nullable ConnectedDeviceDashboardFragment fragment, @Nullable ConnectedDeviceDashboardFragment fragment,
@Nullable Lifecycle lifecycle) { @Nullable Lifecycle lifecycle) {
final List<AbstractPreferenceController> controllers = new ArrayList<>(); final List<AbstractPreferenceController> controllers = new ArrayList<>();
if (AudioSharingUtils.isFeatureEnabled()) { AbstractPreferenceController availableMediaController =
FeatureFactory.getFeatureFactory()
.getAudioSharingFeatureProvider()
.createAvailableMediaDeviceGroupController(context, fragment, lifecycle);
controllers.add(availableMediaController);
AbstractPreferenceController audioSharingController = AbstractPreferenceController audioSharingController =
FeatureFactory.getFeatureFactory() FeatureFactory.getFeatureFactory()
.getAudioSharingFeatureProvider() .getAudioSharingFeatureProvider()
.createAudioSharingDevicePreferenceController( .createAudioSharingDevicePreferenceController(context, fragment, lifecycle);
context, fragment, lifecycle);
if (audioSharingController != null) { if (audioSharingController != null) {
controllers.add(audioSharingController); controllers.add(audioSharingController);
} }
}
return controllers; return controllers;
} }

View File

@@ -20,12 +20,12 @@ import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.lifecycle.Lifecycle;
import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
/** Feature provider for the audio sharing related features, */ /** Feature provider for the audio sharing related features, */
public interface AudioSharingFeatureProvider { public interface AudioSharingFeatureProvider {
@@ -37,6 +37,12 @@ public interface AudioSharingFeatureProvider {
@Nullable DashboardFragment fragment, @Nullable DashboardFragment fragment,
@Nullable Lifecycle lifecycle); @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. * Check if the device match the audio sharing filter.
* *

View File

@@ -20,12 +20,13 @@ import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.lifecycle.Lifecycle;
import com.android.settings.connecteddevice.AvailableMediaDeviceGroupController;
import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class AudioSharingFeatureProviderImpl implements AudioSharingFeatureProvider { public class AudioSharingFeatureProviderImpl implements AudioSharingFeatureProvider {
@@ -38,6 +39,14 @@ public class AudioSharingFeatureProviderImpl implements AudioSharingFeatureProvi
return null; return null;
} }
@Override
public AbstractPreferenceController createAvailableMediaDeviceGroupController(
@NonNull Context context,
@Nullable DashboardFragment fragment,
@Nullable Lifecycle lifecycle) {
return new AvailableMediaDeviceGroupController(context, fragment, lifecycle);
}
@Override @Override
public boolean isAudioSharingFilterMatched( public boolean isAudioSharingFilterMatched(
@NonNull CachedBluetoothDevice cachedDevice, LocalBluetoothManager localBtManager) { @NonNull CachedBluetoothDevice cachedDevice, LocalBluetoothManager localBtManager) {

View File

@@ -0,0 +1,76 @@
/*
* 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.display;
import android.content.Context;
import android.content.res.Resources;
import android.provider.Settings;
import android.util.Log;
import androidx.annotation.NonNull;
import com.android.server.display.feature.flags.Flags;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
/**
* Controller for the settings toggle which allows screen brightness to go even dimmer than usual.
*
*/
public class EvenDimmerPreferenceController extends TogglePreferenceController {
private static final String TAG = "EvenDimmerPreferenceController";
private final Resources mResources;
public EvenDimmerPreferenceController(@NonNull Context context, @NonNull String key) {
super(context, key);
mResources = context.getResources();
}
@Override
public int getAvailabilityStatus() {
// enable based on flag and config.xml
final boolean enabledInConfig = mResources.getBoolean(
com.android.internal.R.bool.config_evenDimmerEnabled);
return (Flags.evenDimmer() && enabledInConfig) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
@Override
public boolean isChecked() {
return getEvenDimmerActivated();
}
@Override
public boolean setChecked(boolean isChecked) {
final float enabled = getAvailabilityStatus() == AVAILABLE && isChecked ? 1 : 0;
Log.i(TAG, "setChecked to : " + enabled);
return Settings.Secure.putFloat(
mContext.getContentResolver(), Settings.Secure.EVEN_DIMMER_ACTIVATED, enabled);
}
@Override
public int getSliceHighlightMenuRes() {
return R.string.menu_key_display;
}
private boolean getEvenDimmerActivated() {
return Settings.Secure.getFloat(mContext.getContentResolver(),
Settings.Secure.EVEN_DIMMER_ACTIVATED, 0) == 1;
}
}

View File

@@ -17,13 +17,15 @@
package com.android.settings.network; package com.android.settings.network;
import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; 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.SubscriptionManager.PROFILE_CLASS_PROVISIONING;
import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT;
import static com.android.internal.util.CollectionUtils.emptyIfNull; import static com.android.internal.util.CollectionUtils.emptyIfNull;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.os.ParcelUuid; import android.os.ParcelUuid;
import android.provider.Settings; import android.provider.Settings;
import android.telephony.PhoneNumberUtils; import android.telephony.PhoneNumberUtils;
@@ -560,6 +562,7 @@ public class SubscriptionUtil {
Log.i(TAG, "Unable to delete subscription due to invalid subscription ID."); Log.i(TAG, "Unable to delete subscription due to invalid subscription ID.");
return; return;
} }
// TODO(b/325693582): Add verification if carrier is RAC and logic for new dialog
context.startActivity(DeleteEuiccSubscriptionDialogActivity.getIntent(context, subId)); context.startActivity(DeleteEuiccSubscriptionDialogActivity.getIntent(context, subId));
} }
@@ -832,4 +835,29 @@ public class SubscriptionUtil {
} }
return true; 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;
}
} }

View File

@@ -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));
}
}

View File

@@ -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);
}
}

View File

@@ -29,8 +29,7 @@ import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import com.android.settings.R import com.android.settings.R
import com.android.settings.network.telephony.ims.ImsMmTelRepository import com.android.settings.network.telephony.wificalling.WifiCallingRepository
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@@ -46,8 +45,8 @@ open class WifiCallingPreferenceController @JvmOverloads constructor(
context: Context, context: Context,
key: String, key: String,
private val callStateFlowFactory: (subId: Int) -> Flow<Int> = context::callStateFlow, private val callStateFlowFactory: (subId: Int) -> Flow<Int> = context::callStateFlow,
private val imsMmTelRepositoryFactory: (subId: Int) -> ImsMmTelRepository = { subId -> private val wifiCallingRepository: (subId: Int) -> WifiCallingRepository = { subId ->
ImsMmTelRepositoryImpl(context, subId) WifiCallingRepository(context, subId)
}, },
) : TelephonyBasePreferenceController(context, key) { ) : TelephonyBasePreferenceController(context, key) {
@@ -123,7 +122,7 @@ open class WifiCallingPreferenceController @JvmOverloads constructor(
} }
private fun getSummaryForWfcMode(): String { private fun getSummaryForWfcMode(): String {
val resId = when (imsMmTelRepositoryFactory(mSubId).getWiFiCallingMode()) { val resId = when (wifiCallingRepository(mSubId).getWiFiCallingMode()) {
ImsMmTelManager.WIFI_MODE_WIFI_ONLY -> ImsMmTelManager.WIFI_MODE_WIFI_ONLY ->
com.android.internal.R.string.wfc_mode_wifi_only_summary com.android.internal.R.string.wfc_mode_wifi_only_summary

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2023 The Android Open Source Project * Copyright (C) 2024 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,9 +17,6 @@
package com.android.settings.network.telephony.ims package com.android.settings.network.telephony.ims
import android.content.Context import android.content.Context
import android.telephony.CarrierConfigManager
import android.telephony.CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL
import android.telephony.TelephonyManager
import android.telephony.ims.ImsManager import android.telephony.ims.ImsManager
import android.telephony.ims.ImsMmTelManager import android.telephony.ims.ImsMmTelManager
import android.telephony.ims.ImsMmTelManager.WiFiCallingMode import android.telephony.ims.ImsMmTelManager.WiFiCallingMode
@@ -27,7 +24,7 @@ import android.util.Log
interface ImsMmTelRepository { interface ImsMmTelRepository {
@WiFiCallingMode @WiFiCallingMode
fun getWiFiCallingMode(): Int fun getWiFiCallingMode(useRoamingMode: Boolean): Int
} }
class ImsMmTelRepositoryImpl( class ImsMmTelRepositoryImpl(
@@ -36,31 +33,18 @@ class ImsMmTelRepositoryImpl(
private val imsMmTelManager: ImsMmTelManager = ImsManager(context).getImsMmTelManager(subId), private val imsMmTelManager: ImsMmTelManager = ImsManager(context).getImsMmTelManager(subId),
) : ImsMmTelRepository { ) : ImsMmTelRepository {
private val telephonyManager = context.getSystemService(TelephonyManager::class.java)!!
.createForSubscriptionId(subId)
private val carrierConfigManager = context.getSystemService(CarrierConfigManager::class.java)!!
@WiFiCallingMode @WiFiCallingMode
override fun getWiFiCallingMode(): Int = try { override fun getWiFiCallingMode(useRoamingMode: Boolean): Int = try {
when { when {
!imsMmTelManager.isVoWiFiSettingEnabled -> ImsMmTelManager.WIFI_MODE_UNKNOWN !imsMmTelManager.isVoWiFiSettingEnabled -> ImsMmTelManager.WIFI_MODE_UNKNOWN
useRoamingMode -> imsMmTelManager.getVoWiFiRoamingModeSetting()
telephonyManager.isNetworkRoaming && !useWfcHomeModeForRoaming() ->
imsMmTelManager.getVoWiFiRoamingModeSetting()
else -> imsMmTelManager.getVoWiFiModeSetting() else -> imsMmTelManager.getVoWiFiModeSetting()
} }
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
Log.w(TAG, "getWiFiCallingMode failed subId=$subId", e) Log.w(TAG, "[$subId] getWiFiCallingMode failed useRoamingMode=$useRoamingMode", e)
ImsMmTelManager.WIFI_MODE_UNKNOWN ImsMmTelManager.WIFI_MODE_UNKNOWN
} }
private fun useWfcHomeModeForRoaming(): Boolean =
carrierConfigManager
.getConfigForSubId(subId, KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)
.getBoolean(KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)
private companion object { private companion object {
private const val TAG = "ImsMmTelRepository" private const val TAG = "ImsMmTelRepository"
} }

View File

@@ -0,0 +1,47 @@
/*
* 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.wificalling
import android.content.Context
import android.telephony.CarrierConfigManager
import android.telephony.CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL
import android.telephony.TelephonyManager
import android.telephony.ims.ImsMmTelManager.WiFiCallingMode
import com.android.settings.network.telephony.ims.ImsMmTelRepository
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
class WifiCallingRepository(
private val context: Context,
private val subId: Int,
private val imsMmTelRepository : ImsMmTelRepository = ImsMmTelRepositoryImpl(context, subId)
) {
private val telephonyManager = context.getSystemService(TelephonyManager::class.java)!!
.createForSubscriptionId(subId)
private val carrierConfigManager = context.getSystemService(CarrierConfigManager::class.java)!!
@WiFiCallingMode
fun getWiFiCallingMode(): Int {
val useRoamingMode = telephonyManager.isNetworkRoaming && !useWfcHomeModeForRoaming()
return imsMmTelRepository.getWiFiCallingMode(useRoamingMode)
}
private fun useWfcHomeModeForRoaming(): Boolean =
carrierConfigManager
.getConfigForSubId(subId, KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)
.getBoolean(KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.privatespace; package com.android.settings.privatespace;
import static android.text.Layout.BREAK_STRATEGY_SIMPLE;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet; import android.animation.AnimatorSet;
@@ -60,10 +62,10 @@ public class AutoAdvanceSetupFragment extends InstrumentedFragment {
ImmutableList.of( ImmutableList.of(
new Pair(R.string.private_space_notifications_hidden_title, new Pair(R.string.private_space_notifications_hidden_title,
R.drawable.private_space_setup_notification_illustration), R.drawable.private_space_setup_notification_illustration),
new Pair(R.string.private_space_share_photos_title,
R.drawable.private_space_setup_sharing_illustration),
new Pair(R.string.private_space_apps_installed_title, new Pair(R.string.private_space_apps_installed_title,
R.drawable.private_space_setup_preinstalled_illustration)); R.drawable.private_space_setup_preinstalled_illustration),
new Pair(R.string.private_space_explore_settings_title,
R.drawable.private_space_setup_sharing_illustration));
private Runnable mUpdateScreenResources = private Runnable mUpdateScreenResources =
new Runnable() { new Runnable() {
@@ -118,6 +120,7 @@ public class AutoAdvanceSetupFragment extends InstrumentedFragment {
(GlifLayout) (GlifLayout)
inflater.inflate(R.layout.private_space_advancing_screen, container, false); inflater.inflate(R.layout.private_space_advancing_screen, container, false);
mRootView.getHeaderTextView().setMaxLines(HEADER_TEXT_MAX_LINES); mRootView.getHeaderTextView().setMaxLines(HEADER_TEXT_MAX_LINES);
mRootView.getHeaderTextView().setBreakStrategy(BREAK_STRATEGY_SIMPLE);
updateHeaderAndImage(); updateHeaderAndImage();
mHandler = new Handler(Looper.getMainLooper()); mHandler = new Handler(Looper.getMainLooper());
mHandler.postDelayed(mUpdateScreenResources, DELAY_BETWEEN_SCREENS); mHandler.postDelayed(mUpdateScreenResources, DELAY_BETWEEN_SCREENS);

View File

@@ -22,27 +22,23 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper; import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.media.AudioManager; import android.media.AudioManager;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
@@ -51,19 +47,16 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.bluetooth.AvailableMediaBluetoothDeviceUpdater; import com.android.settings.bluetooth.AvailableMediaBluetoothDeviceUpdater;
import com.android.settings.bluetooth.Utils; 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.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowAudioManager; import com.android.settings.testutils.shadow.ShadowAudioManager;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.BluetoothEventManager; import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HearingAidInfo; import com.android.settingslib.bluetooth.HearingAidInfo;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager; 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.Before;
import org.junit.Rule; import org.junit.Rule;
@@ -76,16 +69,12 @@ import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import java.util.concurrent.Executor;
/** Tests for {@link AvailableMediaDeviceGroupController}. */ /** Tests for {@link AvailableMediaDeviceGroupController}. */
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config( @Config(
shadows = { shadows = {
ShadowAudioManager.class, ShadowAudioManager.class,
ShadowBluetoothAdapter.class,
ShadowBluetoothUtils.class, ShadowBluetoothUtils.class,
ShadowAlertDialogCompat.class, ShadowAlertDialogCompat.class,
}) })
@@ -105,9 +94,7 @@ public class AvailableMediaDeviceGroupControllerTest {
@Mock private PackageManager mPackageManager; @Mock private PackageManager mPackageManager;
@Mock private BluetoothEventManager mEventManager; @Mock private BluetoothEventManager mEventManager;
@Mock private LocalBluetoothManager mLocalBluetoothManager; @Mock private LocalBluetoothManager mLocalBluetoothManager;
@Mock private LocalBluetoothProfileManager mLocalBtProfileManager;
@Mock private CachedBluetoothDeviceManager mCachedDeviceManager; @Mock private CachedBluetoothDeviceManager mCachedDeviceManager;
@Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
@Mock private CachedBluetoothDevice mCachedBluetoothDevice; @Mock private CachedBluetoothDevice mCachedBluetoothDevice;
private PreferenceGroup mPreferenceGroup; private PreferenceGroup mPreferenceGroup;
@@ -115,13 +102,16 @@ public class AvailableMediaDeviceGroupControllerTest {
private Preference mPreference; private Preference mPreference;
private AvailableMediaDeviceGroupController mAvailableMediaDeviceGroupController; private AvailableMediaDeviceGroupController mAvailableMediaDeviceGroupController;
private AudioManager mAudioManager; private AudioManager mAudioManager;
private ShadowBluetoothAdapter mShadowBluetoothAdapter; private LifecycleOwner mLifecycleOwner;
private Lifecycle mLifecycle;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application);
mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner);
mPreference = new Preference(mContext); mPreference = new Preference(mContext);
mPreference.setKey(PREFERENCE_KEY_1); mPreference.setKey(PREFERENCE_KEY_1);
mPreferenceGroup = spy(new PreferenceScreen(mContext, null)); mPreferenceGroup = spy(new PreferenceScreen(mContext, null));
@@ -130,24 +120,17 @@ public class AvailableMediaDeviceGroupControllerTest {
doReturn(mPackageManager).when(mContext).getPackageManager(); doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH); 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; ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
mLocalBluetoothManager = Utils.getLocalBtManager(mContext); mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
mAudioManager = mContext.getSystemService(AudioManager.class); mAudioManager = mContext.getSystemService(AudioManager.class);
doReturn(mEventManager).when(mLocalBluetoothManager).getEventManager(); doReturn(mEventManager).when(mLocalBluetoothManager).getEventManager();
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBtProfileManager);
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager); when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
when(mCachedDeviceManager.findDevice(any(BluetoothDevice.class))) when(mCachedDeviceManager.findDevice(any(BluetoothDevice.class)))
.thenReturn(mCachedBluetoothDevice); .thenReturn(mCachedBluetoothDevice);
when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS); when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
mAvailableMediaDeviceGroupController = mAvailableMediaDeviceGroupController =
spy(new AvailableMediaDeviceGroupController(mContext)); spy(new AvailableMediaDeviceGroupController(mContext, null, mLifecycle));
mAvailableMediaDeviceGroupController.setBluetoothDeviceUpdater( mAvailableMediaDeviceGroupController.setBluetoothDeviceUpdater(
mAvailableMediaBluetoothDeviceUpdater); mAvailableMediaBluetoothDeviceUpdater);
mAvailableMediaDeviceGroupController.setFragmentManager( mAvailableMediaDeviceGroupController.setFragmentManager(
@@ -197,7 +180,7 @@ public class AvailableMediaDeviceGroupControllerTest {
@Test @Test
public void testRegister() { public void testRegister() {
// register the callback in onStart() // register the callback in onStart()
mAvailableMediaDeviceGroupController.onStart(); mAvailableMediaDeviceGroupController.onStart(mLifecycleOwner);
verify(mAvailableMediaBluetoothDeviceUpdater).registerCallback(); verify(mAvailableMediaBluetoothDeviceUpdater).registerCallback();
verify(mLocalBluetoothManager.getEventManager()) verify(mLocalBluetoothManager.getEventManager())
@@ -205,36 +188,15 @@ public class AvailableMediaDeviceGroupControllerTest {
verify(mAvailableMediaBluetoothDeviceUpdater).refreshPreference(); verify(mAvailableMediaBluetoothDeviceUpdater).refreshPreference();
} }
@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 @Test
public void testUnregister() { public void testUnregister() {
// unregister the callback in onStop() // unregister the callback in onStop()
mAvailableMediaDeviceGroupController.onStop(); mAvailableMediaDeviceGroupController.onStop(mLifecycleOwner);
verify(mAvailableMediaBluetoothDeviceUpdater).unregisterCallback(); verify(mAvailableMediaBluetoothDeviceUpdater).unregisterCallback();
verify(mLocalBluetoothManager.getEventManager()) verify(mLocalBluetoothManager.getEventManager())
.unregisterCallback(any(BluetoothCallback.class)); .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 @Test
public void testGetAvailabilityStatus_noBluetoothFeature_returnUnSupported() { public void testGetAvailabilityStatus_noBluetoothFeature_returnUnSupported() {
doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH); doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
@@ -274,7 +236,7 @@ public class AvailableMediaDeviceGroupControllerTest {
mAvailableMediaDeviceGroupController.mLocalBluetoothManager = null; mAvailableMediaDeviceGroupController.mLocalBluetoothManager = null;
// Shouldn't crash // Shouldn't crash
mAvailableMediaDeviceGroupController.onStart(); mAvailableMediaDeviceGroupController.onStart(mLifecycleOwner);
} }
@Test @Test
@@ -282,7 +244,7 @@ public class AvailableMediaDeviceGroupControllerTest {
mAvailableMediaDeviceGroupController.mLocalBluetoothManager = null; mAvailableMediaDeviceGroupController.mLocalBluetoothManager = null;
// Shouldn't crash // Shouldn't crash
mAvailableMediaDeviceGroupController.onStop(); mAvailableMediaDeviceGroupController.onStop(mLifecycleOwner);
} }
@Test @Test
@@ -300,19 +262,4 @@ public class AvailableMediaDeviceGroupControllerTest {
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog.isShowing()).isTrue(); 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));
}
} }

View File

@@ -20,19 +20,25 @@ import static com.android.settings.connecteddevice.ConnectedDeviceDashboardFragm
import static com.google.common.truth.Truth.assertThat; 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.doReturn;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.connecteddevice.fastpair.FastPairDeviceUpdater;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerListHelper; import com.android.settings.core.PreferenceControllerListHelper;
import com.android.settings.flags.Flags;
import com.android.settings.slices.SlicePreferenceController; 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.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowConnectivityManager; import com.android.settings.testutils.shadow.ShadowConnectivityManager;
import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settings.testutils.shadow.ShadowUserManager;
@@ -60,6 +66,8 @@ public class ConnectedDeviceDashboardFragmentTest {
@Rule @Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 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_NEARBY_DEVICES = "bt_nearby_slice";
private static final String KEY_DISCOVERABLE_FOOTER = "discoverable_footer"; private static final String KEY_DISCOVERABLE_FOOTER = "discoverable_footer";
private static final String KEY_SAVED_DEVICE_SEE_ALL = "previously_connected_devices_see_all"; private static final String KEY_SAVED_DEVICE_SEE_ALL = "previously_connected_devices_see_all";
@@ -75,8 +83,11 @@ public class ConnectedDeviceDashboardFragmentTest {
private static final String TEST_ACTION = "com.testapp.settings.ACTION_START"; private static final String TEST_ACTION = "com.testapp.settings.ACTION_START";
@Mock private PackageManager mPackageManager; @Mock private PackageManager mPackageManager;
@Mock private FastPairDeviceUpdater mFastPairDeviceUpdater;
private Context mContext; private Context mContext;
private ConnectedDeviceDashboardFragment mFragment; private ConnectedDeviceDashboardFragment mFragment;
private FakeFeatureFactory mFeatureFactory;
private AvailableMediaDeviceGroupController mMediaDeviceGroupController;
@Before @Before
public void setUp() { public void setUp() {
@@ -84,6 +95,22 @@ public class ConnectedDeviceDashboardFragmentTest {
mContext = spy(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application);
mFragment = new ConnectedDeviceDashboardFragment(); 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(mPackageManager).when(mContext).getPackageManager();
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH); doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
} }

View File

@@ -22,6 +22,7 @@ import android.content.Context;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import com.android.settings.connecteddevice.AvailableMediaDeviceGroupController;
import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -59,6 +60,14 @@ public class AudioSharingFeatureProviderImplTest {
.isNull(); .isNull();
} }
@Test
public void createAvailableMediaDeviceGroupController_returnsNull() {
assertThat(
mFeatureProvider.createAvailableMediaDeviceGroupController(
mContext, /* fragment= */ null, /* lifecycle= */ null))
.isInstanceOf(AvailableMediaDeviceGroupController.class);
}
@Test @Test
public void isAudioSharingFilterMatched_returnsFalse() { public void isAudioSharingFilterMatched_returnsFalse() {
assertThat(mFeatureProvider.isAudioSharingFilterMatched(mCachedDevice, mLocalBtManager)) assertThat(mFeatureProvider.isAudioSharingFilterMatched(mCachedDevice, mLocalBtManager))

View File

@@ -0,0 +1,114 @@
/*
* 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.display;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
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 com.android.server.display.feature.flags.Flags;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class EvenDimmerPreferenceControllerTest {
private EvenDimmerPreferenceController mController;
@Mock
private Context mContext;
@Mock
private Resources mResources;
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getResources()).thenReturn(mResources);
mController = new EvenDimmerPreferenceController(mContext, "key");
}
@RequiresFlagsDisabled(Flags.FLAG_EVEN_DIMMER)
@Test
public void testGetAvailabilityStatus_flagOffconfigTrue() {
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getBoolean(
com.android.internal.R.bool.config_evenDimmerEnabled)).thenReturn(true);
// setup
mController = new EvenDimmerPreferenceController(mContext, "key");
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@RequiresFlagsDisabled(Flags.FLAG_EVEN_DIMMER)
@Test
public void testGetCheckedStatus_setTrue() throws Settings.SettingNotFoundException {
// setup
mController = new EvenDimmerPreferenceController(mContext, "key");
mController.setChecked(true);
assertThat(Settings.Secure.getFloat(mContext.getContentResolver(),
Settings.Secure.EVEN_DIMMER_ACTIVATED)).isEqualTo(0.0f); // false
}
@RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
@Test
public void testGetAvailabilityStatus_flagOnConfigTrue() {
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getBoolean(
com.android.internal.R.bool.config_evenDimmerEnabled)).thenReturn(true);
// setup
mController = new EvenDimmerPreferenceController(mContext, "key");
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
public void testSetChecked_enable() throws Settings.SettingNotFoundException {
mController.setChecked(true);
assertThat(Settings.Secure.getFloat(mContext.getContentResolver(),
Settings.Secure.EVEN_DIMMER_ACTIVATED)).isEqualTo(1.0f); // true
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
public void testSetChecked_disable() throws Settings.SettingNotFoundException {
mController.setChecked(false);
assertThat(Settings.Secure.getFloat(mContext.getContentResolver(),
Settings.Secure.EVEN_DIMMER_ACTIVATED)).isEqualTo(0.0f); // false
}
}

View File

@@ -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);
}
}

View File

@@ -30,12 +30,19 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
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.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference; import androidx.preference.SwitchPreference;
import com.android.settings.flags.Flags;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
@@ -52,6 +59,9 @@ public class AutoDataSwitchPreferenceControllerTest {
private static final int SUB_ID_1 = 111; private static final int SUB_ID_1 = 111;
private static final int SUB_ID_2 = 222; private static final int SUB_ID_2 = 222;
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock @Mock
private TelephonyManager mTelephonyManager; private TelephonyManager mTelephonyManager;
@Mock @Mock
@@ -79,6 +89,7 @@ public class AutoDataSwitchPreferenceControllerTest {
} }
@Test @Test
@RequiresFlagsDisabled(Flags.FLAG_IS_DUAL_SIM_ONBOARDING_ENABLED)
public void getAvailabilityStatus_noInit_notAvailable() { public void getAvailabilityStatus_noInit_notAvailable() {
ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1); ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
AutoDataSwitchPreferenceController controller = AutoDataSwitchPreferenceController controller =
@@ -90,6 +101,7 @@ public class AutoDataSwitchPreferenceControllerTest {
} }
@Test @Test
@RequiresFlagsDisabled(Flags.FLAG_IS_DUAL_SIM_ONBOARDING_ENABLED)
public void displayPreference_defaultForData_notAvailable() { public void displayPreference_defaultForData_notAvailable() {
ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1); ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
@@ -100,6 +112,7 @@ public class AutoDataSwitchPreferenceControllerTest {
} }
@Test @Test
@RequiresFlagsDisabled(Flags.FLAG_IS_DUAL_SIM_ONBOARDING_ENABLED)
public void displayPreference_notDefaultForData_available() { public void displayPreference_notDefaultForData_available() {
ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2); ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2);
@@ -110,6 +123,7 @@ public class AutoDataSwitchPreferenceControllerTest {
} }
@Test @Test
@RequiresFlagsDisabled(Flags.FLAG_IS_DUAL_SIM_ONBOARDING_ENABLED)
public void onSubscriptionsChanged_becomesDefaultForData_notAvailable() { public void onSubscriptionsChanged_becomesDefaultForData_notAvailable() {
ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2); ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_2);
@@ -122,6 +136,7 @@ public class AutoDataSwitchPreferenceControllerTest {
} }
@Test @Test
@RequiresFlagsDisabled(Flags.FLAG_IS_DUAL_SIM_ONBOARDING_ENABLED)
public void onSubscriptionsChanged_noLongerDefaultForData_available() { public void onSubscriptionsChanged_noLongerDefaultForData_available() {
ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1); ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
@@ -134,6 +149,7 @@ public class AutoDataSwitchPreferenceControllerTest {
} }
@Test @Test
@RequiresFlagsDisabled(Flags.FLAG_IS_DUAL_SIM_ONBOARDING_ENABLED)
public void getAvailabilityStatus_mobileDataChangWithDefaultDataSubId_returnUnavailable() { public void getAvailabilityStatus_mobileDataChangWithDefaultDataSubId_returnUnavailable() {
ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1); ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
@@ -144,6 +160,7 @@ public class AutoDataSwitchPreferenceControllerTest {
} }
@Test @Test
@RequiresFlagsDisabled(Flags.FLAG_IS_DUAL_SIM_ONBOARDING_ENABLED)
public void getAvailabilityStatus_mobileDataChangWithoutDefaultDataSubId_returnAvailable() { public void getAvailabilityStatus_mobileDataChangWithoutDefaultDataSubId_returnAvailable() {
ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1); ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
@@ -152,4 +169,16 @@ public class AutoDataSwitchPreferenceControllerTest {
assertThat(mController.getAvailabilityStatus(SUB_ID_2)).isEqualTo(AVAILABLE); assertThat(mController.getAvailabilityStatus(SUB_ID_2)).isEqualTo(AVAILABLE);
} }
@Test
@RequiresFlagsEnabled(Flags.FLAG_IS_DUAL_SIM_ONBOARDING_ENABLED)
public void getAvailabilityStatus_flagIsDualSimOnboardingEnabledOn_returnUnavailable() {
ShadowSubscriptionManager.setDefaultDataSubscriptionId(SUB_ID_1);
mController.displayPreference(mPreferenceScreen);
mController.refreshPreference();
assertThat(mController.getAvailabilityStatus(SUB_ID_1))
.isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
} }

View File

@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -38,6 +38,7 @@ import org.robolectric.shadow.api.Shadow;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** Robolectric shadow for the AudioManager. */
@Implements(value = AudioManager.class) @Implements(value = AudioManager.class)
public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManager { public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManager {
private int mRingerMode; private int mRingerMode;
@@ -58,11 +59,13 @@ public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManag
mRingerMode = mode; mRingerMode = mode;
} }
/** Register audio device callback. */
@Implementation @Implementation
public void registerAudioDeviceCallback(AudioDeviceCallback callback, Handler handler) { public void registerAudioDeviceCallback(AudioDeviceCallback callback, Handler handler) {
mDeviceCallbacks.add(callback); mDeviceCallbacks.add(callback);
} }
/** Unregister audio device callback. */
@Implementation @Implementation
public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) { public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
if (mDeviceCallbacks.contains(callback)) { if (mDeviceCallbacks.contains(callback)) {
@@ -79,10 +82,12 @@ public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManag
return mMusicActiveRemotely; return mMusicActiveRemotely;
} }
/** Set output device. */
public void setOutputDevice(int deviceCodes) { public void setOutputDevice(int deviceCodes) {
mDeviceCodes = deviceCodes; mDeviceCodes = deviceCodes;
} }
/** Get devices for stream. */
@Implementation @Implementation
public int getDevicesForStream(int streamType) { public int getDevicesForStream(int streamType) {
switch (streamType) { switch (streamType) {

View File

@@ -29,7 +29,7 @@ import androidx.preference.Preference
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.network.telephony.ims.ImsMmTelRepository import com.android.settings.network.telephony.wificalling.WifiCallingRepository
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
@@ -60,9 +60,8 @@ class WifiCallingPreferenceControllerTest {
private var callState = TelephonyManager.CALL_STATE_IDLE private var callState = TelephonyManager.CALL_STATE_IDLE
private object FakeImsMmTelRepository : ImsMmTelRepository { private val mockWifiCallingRepository = mock<WifiCallingRepository> {
var wiFiMode = ImsMmTelManager.WIFI_MODE_UNKNOWN on { getWiFiCallingMode() } doReturn ImsMmTelManager.WIFI_MODE_UNKNOWN
override fun getWiFiCallingMode() = wiFiMode
} }
private val callingPreferenceCategoryController = private val callingPreferenceCategoryController =
@@ -72,7 +71,7 @@ class WifiCallingPreferenceControllerTest {
context = context, context = context,
key = TEST_KEY, key = TEST_KEY,
callStateFlowFactory = { flowOf(callState) }, callStateFlowFactory = { flowOf(callState) },
imsMmTelRepositoryFactory = { FakeImsMmTelRepository }, wifiCallingRepository = { mockWifiCallingRepository },
).init(subId = SUB_ID, callingPreferenceCategoryController) ).init(subId = SUB_ID, callingPreferenceCategoryController)
@Before @Before
@@ -86,7 +85,9 @@ class WifiCallingPreferenceControllerTest {
mockTelecomManager.stub { mockTelecomManager.stub {
on { getSimCallManagerForSubscription(SUB_ID) } doReturn null on { getSimCallManagerForSubscription(SUB_ID) } doReturn null
} }
FakeImsMmTelRepository.wiFiMode = ImsMmTelManager.WIFI_MODE_WIFI_ONLY mockWifiCallingRepository.stub {
on { getWiFiCallingMode() } doReturn ImsMmTelManager.WIFI_MODE_WIFI_ONLY
}
controller.onViewCreated(TestLifecycleOwner()) controller.onViewCreated(TestLifecycleOwner())
delay(100) delay(100)

View File

@@ -17,11 +17,7 @@
package com.android.settings.network.telephony.ims package com.android.settings.network.telephony.ims
import android.content.Context import android.content.Context
import android.telephony.CarrierConfigManager
import android.telephony.CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL
import android.telephony.TelephonyManager
import android.telephony.ims.ImsMmTelManager import android.telephony.ims.ImsMmTelManager
import androidx.core.os.persistableBundleOf
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
@@ -30,21 +26,11 @@ import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn import org.mockito.kotlin.doReturn
import org.mockito.kotlin.doThrow import org.mockito.kotlin.doThrow
import org.mockito.kotlin.mock import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.stub import org.mockito.kotlin.stub
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class ImsMmTelRepositoryTest { class ImsMmTelRepositoryTest {
private val mockTelephonyManager = mock<TelephonyManager> { private val context: Context = ApplicationProvider.getApplicationContext()
on { createForSubscriptionId(SUB_ID) } doReturn mock
}
private val mockCarrierConfigManager = mock<CarrierConfigManager>()
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
on { getSystemService(CarrierConfigManager::class.java) } doReturn mockCarrierConfigManager
}
private val mockImsMmTelManager = mock<ImsMmTelManager> { private val mockImsMmTelManager = mock<ImsMmTelManager> {
on { isVoWiFiSettingEnabled } doReturn true on { isVoWiFiSettingEnabled } doReturn true
@@ -60,42 +46,21 @@ class ImsMmTelRepositoryTest {
on { isVoWiFiSettingEnabled } doReturn false on { isVoWiFiSettingEnabled } doReturn false
} }
val wiFiCallingMode = repository.getWiFiCallingMode() val wiFiCallingMode = repository.getWiFiCallingMode(false)
assertThat(wiFiCallingMode).isEqualTo(ImsMmTelManager.WIFI_MODE_UNKNOWN) assertThat(wiFiCallingMode).isEqualTo(ImsMmTelManager.WIFI_MODE_UNKNOWN)
} }
@Test @Test
fun getWiFiCallingMode_roamingAndNotUseWfcHomeModeForRoaming_returnRoamingSetting() { fun getWiFiCallingMode_useRoamingMode_returnRoamingSetting() {
mockTelephonyManager.stub { val wiFiCallingMode = repository.getWiFiCallingMode(true)
on { isNetworkRoaming } doReturn true
}
mockUseWfcHomeModeForRoaming(false)
val wiFiCallingMode = repository.getWiFiCallingMode()
assertThat(wiFiCallingMode).isEqualTo(mockImsMmTelManager.getVoWiFiRoamingModeSetting()) assertThat(wiFiCallingMode).isEqualTo(mockImsMmTelManager.getVoWiFiRoamingModeSetting())
} }
@Test @Test
fun getWiFiCallingMode_roamingAndUseWfcHomeModeForRoaming_returnHomeSetting() { fun getWiFiCallingMode_notSseRoamingMode_returnHomeSetting() {
mockTelephonyManager.stub { val wiFiCallingMode = repository.getWiFiCallingMode(false)
on { isNetworkRoaming } doReturn true
}
mockUseWfcHomeModeForRoaming(true)
val wiFiCallingMode = repository.getWiFiCallingMode()
assertThat(wiFiCallingMode).isEqualTo(mockImsMmTelManager.getVoWiFiModeSetting())
}
@Test
fun getWiFiCallingMode_notRoaming_returnHomeSetting() {
mockTelephonyManager.stub {
on { isNetworkRoaming } doReturn false
}
val wiFiCallingMode = repository.getWiFiCallingMode()
assertThat(wiFiCallingMode).isEqualTo(mockImsMmTelManager.getVoWiFiModeSetting()) assertThat(wiFiCallingMode).isEqualTo(mockImsMmTelManager.getVoWiFiModeSetting())
} }
@@ -106,21 +71,11 @@ class ImsMmTelRepositoryTest {
on { isVoWiFiSettingEnabled } doThrow IllegalArgumentException() on { isVoWiFiSettingEnabled } doThrow IllegalArgumentException()
} }
val wiFiCallingMode = repository.getWiFiCallingMode() val wiFiCallingMode = repository.getWiFiCallingMode(false)
assertThat(wiFiCallingMode).isEqualTo(ImsMmTelManager.WIFI_MODE_UNKNOWN) assertThat(wiFiCallingMode).isEqualTo(ImsMmTelManager.WIFI_MODE_UNKNOWN)
} }
private fun mockUseWfcHomeModeForRoaming(config: Boolean) {
mockCarrierConfigManager.stub {
on {
getConfigForSubId(SUB_ID, KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)
} doReturn persistableBundleOf(
KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL to config,
)
}
}
private companion object { private companion object {
const val SUB_ID = 1 const val SUB_ID = 1
} }

View File

@@ -0,0 +1,114 @@
/*
* 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.wificalling
import android.content.Context
import android.telephony.CarrierConfigManager
import android.telephony.CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL
import android.telephony.TelephonyManager
import android.telephony.ims.ImsMmTelManager
import androidx.core.os.persistableBundleOf
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.network.telephony.ims.ImsMmTelRepository
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.stub
@RunWith(AndroidJUnit4::class)
class WifiCallingRepositoryTest {
private val mockTelephonyManager = mock<TelephonyManager> {
on { createForSubscriptionId(SUB_ID) } doReturn mock
}
private val mockCarrierConfigManager = mock<CarrierConfigManager>()
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
on { getSystemService(CarrierConfigManager::class.java) } doReturn mockCarrierConfigManager
}
private val mockImsMmTelRepository = mock<ImsMmTelRepository> {
on { getWiFiCallingMode(any()) } doReturn ImsMmTelManager.WIFI_MODE_UNKNOWN
}
private val repository = WifiCallingRepository(context, SUB_ID, mockImsMmTelRepository)
@Test
fun getWiFiCallingMode_roamingAndNotUseWfcHomeModeForRoaming_returnRoamingSetting() {
mockTelephonyManager.stub {
on { isNetworkRoaming } doReturn true
}
mockUseWfcHomeModeForRoaming(false)
mockImsMmTelRepository.stub {
on { getWiFiCallingMode(true) } doReturn ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED
}
val wiFiCallingMode = repository.getWiFiCallingMode()
assertThat(wiFiCallingMode).isEqualTo(ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED)
}
@Test
fun getWiFiCallingMode_roamingAndUseWfcHomeModeForRoaming_returnHomeSetting() {
mockTelephonyManager.stub {
on { isNetworkRoaming } doReturn true
}
mockUseWfcHomeModeForRoaming(true)
mockImsMmTelRepository.stub {
on { getWiFiCallingMode(false) } doReturn ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED
}
val wiFiCallingMode = repository.getWiFiCallingMode()
assertThat(wiFiCallingMode).isEqualTo(ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED)
}
@Test
fun getWiFiCallingMode_notRoaming_returnHomeSetting() {
mockTelephonyManager.stub {
on { isNetworkRoaming } doReturn false
}
mockImsMmTelRepository.stub {
on { getWiFiCallingMode(false) } doReturn ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED
}
val wiFiCallingMode = repository.getWiFiCallingMode()
assertThat(wiFiCallingMode).isEqualTo(ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED)
}
private fun mockUseWfcHomeModeForRoaming(config: Boolean) {
mockCarrierConfigManager.stub {
on {
getConfigForSubId(SUB_ID, KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)
} doReturn persistableBundleOf(
KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL to config,
)
}
}
private companion object {
const val SUB_ID = 1
}
}

View File

@@ -18,9 +18,13 @@ package com.android.settings.network;
import static com.android.settings.network.SubscriptionUtil.KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME; import static com.android.settings.network.SubscriptionUtil.KEY_UNIQUE_SUBSCRIPTION_DISPLAYNAME;
import static com.android.settings.network.SubscriptionUtil.SUB_ID; import static com.android.settings.network.SubscriptionUtil.SUB_ID;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@@ -30,6 +34,8 @@ import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Resources; import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
@@ -61,13 +67,15 @@ public class SubscriptionUtilTest {
private static final CharSequence CARRIER_2 = "carrier2"; private static final CharSequence CARRIER_2 = "carrier2";
private Context mContext; private Context mContext;
private NetworkCapabilities mNetworkCapabilities;
@Mock @Mock
private SubscriptionManager mSubMgr; private SubscriptionManager mSubMgr;
@Mock @Mock
private TelephonyManager mTelMgr; private TelephonyManager mTelMgr;
@Mock @Mock
private Resources mResources; private Resources mResources;
@Mock private ConnectivityManager mConnectivityManager;
@Before @Before
public void setUp() { public void setUp() {
@@ -75,6 +83,7 @@ public class SubscriptionUtilTest {
mContext = spy(ApplicationProvider.getApplicationContext()); mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubMgr); when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubMgr);
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelMgr); when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelMgr);
when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager);
when(mTelMgr.getUiccSlotsInfo()).thenReturn(null); when(mTelMgr.getUiccSlotsInfo()).thenReturn(null);
} }
@@ -588,4 +597,24 @@ public class SubscriptionUtilTest {
assertThat(SubscriptionUtil.isValidCachedDisplayName(cacheString, originalName)).isFalse(); 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);
}
} }