diff --git a/AndroidManifest.xml b/AndroidManifest.xml index b956f679199..d51dfdc5f5c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -627,6 +627,27 @@ android:value="true" /> + + + + + + + + + + + + + + + + android:value="true" /> + + + diff --git a/res/drawable/ic_check_circle_24px.xml b/res/drawable/ic_check_circle_24px.xml new file mode 100644 index 00000000000..c0fdefbee19 --- /dev/null +++ b/res/drawable/ic_check_circle_24px.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/drawable/ic_satellite_alt_24px.xml b/res/drawable/ic_satellite_alt_24px.xml new file mode 100644 index 00000000000..f9ca7dc6679 --- /dev/null +++ b/res/drawable/ic_satellite_alt_24px.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/drawable/ic_signal_cellular_nodata_24px.xml b/res/drawable/ic_signal_cellular_nodata_24px.xml new file mode 100644 index 00000000000..9b9f3918d14 --- /dev/null +++ b/res/drawable/ic_signal_cellular_nodata_24px.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/drawable/satellite_more_information_background_outline.xml b/res/drawable/satellite_more_information_background_outline.xml new file mode 100644 index 00000000000..b11ef07507d --- /dev/null +++ b/res/drawable/satellite_more_information_background_outline.xml @@ -0,0 +1,24 @@ + + + + + + + diff --git a/res/layout/satellite_setting_more_information_layout.xml b/res/layout/satellite_setting_more_information_layout.xml new file mode 100644 index 00000000000..ce2fabe23d2 --- /dev/null +++ b/res/layout/satellite_setting_more_information_layout.xml @@ -0,0 +1,50 @@ + + + + + + + + + + diff --git a/res/navigation/privatespace_main_context_nav.xml b/res/navigation/privatespace_main_context_nav.xml index 78494581ec2..f76afac4df1 100644 --- a/res/navigation/privatespace_main_context_nav.xml +++ b/res/navigation/privatespace_main_context_nav.xml @@ -52,6 +52,9 @@ + com.android.avatarpicker.FULL_SCREEN_ACTIVITY + + + com.android.avatarpicker + com.android.settings diff --git a/res/values/strings.xml b/res/values/strings.xml index 18a4aec027f..01979b24691 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1341,10 +1341,14 @@ Done Scroll down to find private space - - Sign in to set up a private space + + Sign in - You need to sign in to an account to set up a private space + Sign in to an account to use with your private space + + Not now + + Continue Choose a lock for your private space @@ -3256,6 +3260,10 @@ Communal settings + + + Satellite Messaging + APNs @@ -3370,7 +3378,7 @@ Erase eSIMs - This won’t cancel any mobile service plans. To download replacement SIMs, contact your carrier. + This won’t cancel your mobile service plan. To get a replacement SIM, contact your carrier. Reset settings @@ -3387,9 +3395,9 @@ Network settings have been reset - Can\u2019t erase SIMs + Can\u2019t erase eSIMs - eSIMs can\u2019t be erased due to an error.\n\nRestart your device and try again. + Something went wrong and your eSIMs weren\u2019t erased.\n\nRestart your device and try again. @@ -3405,7 +3413,7 @@ All of your personal information and downloaded apps will be deleted. You can\u2019t undo this action. - All of your personal information, including downloaded apps & SIMs, will be deleted. You can\u2019t undo this action. + All of your personal information, including downloaded apps & eSIMs, will be deleted. You can\u2019t undo this action. Erase all data? @@ -11362,7 +11370,7 @@ - Erase SIM + Erase eSIM Preferred network type @@ -11407,6 +11415,43 @@ App data usage Invalid Network Mode %1$d. Ignore. + + Satellite messaging + + Send and receive text messages by satellite. Included with your account. + + Send and receive text messages by satellite. Non included with your account. + + Satellite messaging + + About satellite messaging + + You can send and receive text messages by satellite as part of an eligible %1$s account + + Your %1$s plan + + Satellite messaging is included with your account + + Satellite messaging isn\u2019t included with your account + + Add satellite messaging + + How it works + + When you don\u2019t have a mobile network + + Your phone will auto-connect to a satellite. For the best connection, keep a clear view of the sky. + + After your phone connects to a satellite + + You can text anyone, including emergency services. Your phone will reconnect to a mobile network when available. + + Satellite messaging may take longer and is available only in some areas, Weather and certain structures may affect your satellite connection. Calling by satellite isn\u2019t available.\n\nIt may take some time for changes to your account to show in Settings. Contact %1$s for details. + + More about satellite messaging + + + Access Point Names @@ -11430,11 +11475,11 @@ Use %1$s? - Only one SIM can be active at a time.\n\nSwitching to %1$s won\u2019t cancel your %2$s service. - - Only 1 eSIM can be active at a time.\n\nSwitching to %1$s won\u2019t cancel your %2$s service. + Only 1 SIM can be on at a time.\n\nSwitching to %1$s won\u2019t cancel your %2$s service. + + Only 1 eSIM can be on at a time.\n\nSwitching to %1$s won\u2019t cancel your %2$s service. - Only one SIM can be active at a time.\n\nSwitching won\u2019t cancel your %1$s service. + Only 1 SIM can be on at a time.\n\nSwitching won\u2019t cancel your %1$s service. You can use 2 SIMs at a time. To use %1$s, turn off another SIM. @@ -11585,15 +11630,15 @@ Erase this eSIM? - Erasing this SIM removes %1$s service from this device.\n\nService for %1$s won\'t be canceled. + This removes %1$s service from this device, but your %1$s plan won\'t be canceled. Erase - Erasing SIM… + Erasing eSIM… - Can\'t erase SIM + Can\'t erase eSIM - This SIM can\'t be erased due to an error.\n\nRestart your device and try again. + Something went wrong and this eSIM wasn\'t erased.\n\nRestart your device and try again. Connect to device @@ -11998,9 +12043,9 @@ eSIMs - Active + On - Inactive + Off \u0020/ Default for %1$s diff --git a/res/xml/mobile_network_settings.xml b/res/xml/mobile_network_settings.xml index 038688e390c..b5d0c5939ed 100644 --- a/res/xml/mobile_network_settings.xml +++ b/res/xml/mobile_network_settings.xml @@ -208,6 +208,7 @@ + + @@ -249,7 +257,7 @@ android:title="@string/require_cellular_encryption_title" android:summary="@string/require_cellular_encryption_summary" settings:controller= - "com.android.settings.network.telephony.NullAlgorithmsPreferenceController" /> + "com.android.settings.network.telephony.NullAlgorithmsPreferenceController"/> + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 52f5e5b1ad9..2275c6de80a 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -345,6 +345,7 @@ public class Settings extends SettingsActivity { /* empty */ } + public static class SatelliteSettingActivity extends SettingsActivity { /* empty */ } public static class ApnSettingsActivity extends SettingsActivity { /* empty */ } public static class WifiCallingSettingsActivity extends SettingsActivity { /* empty */ } public static class MemorySettingsActivity extends SettingsActivity { /* empty */ } diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 25fd3a20f68..108e331a090 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -54,7 +54,9 @@ import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.VectorDrawable; +import android.hardware.face.Face; import android.hardware.face.FaceManager; +import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.net.ConnectivityManager; import android.net.LinkAddress; @@ -1333,4 +1335,64 @@ public final class Utils extends com.android.settingslib.Utils { return dreamsSupported && (!dreamsOnlyEnabledForDockUser || canCurrentUserDream(context)); } + + /** + * Removes fingerprint templates enrolled for a given user. + * + * @param context application context. + * @param userId the id of the relevant user + */ + public static void removeEnrolledFingerprintForUser(Context context, int userId) { + FingerprintManager fingerprintManager = getFingerprintManagerOrNull(context); + if (fingerprintManager != null && fingerprintManager.hasEnrolledTemplates(userId)) { + fingerprintManager.removeAll(userId, + fingerprintManagerRemovalCallback(userId)); + } + } + + /** + * Removes face templates enrolled for a given user. + * + * @param context application context. + * @param userId the id of the relevant user + */ + public static void removeEnrolledFaceForUser(Context context, int userId) { + FaceManager faceManager = getFaceManagerOrNull(context); + if (faceManager != null && faceManager.hasEnrolledTemplates(userId)) { + faceManager.removeAll(userId, faceManagerRemovalCallback(userId)); + } + } + + private static FaceManager.RemovalCallback faceManagerRemovalCallback(int userId) { + return new FaceManager.RemovalCallback() { + @Override + public void onRemovalError(@Nullable Face face, int errMsgId, CharSequence err) { + Log.e(TAG, "Unable to remove face template for user " + userId + ", error: " + err); + } + + @Override + public void onRemovalSucceeded(Face face, int remaining) { + if (remaining == 0) { + Log.d(TAG, "Enrolled face templates removed for user " + userId); + } + } + }; + } + + private static FingerprintManager.RemovalCallback fingerprintManagerRemovalCallback( + int userId) { + return new FingerprintManager.RemovalCallback() { + @Override + public void onRemovalError(@Nullable Fingerprint fp, int errMsgId, CharSequence err) { + Log.e(TAG, "Unable to remove fingerprint for user " + userId + " , error: " + err); + } + + @Override + public void onRemovalSucceeded(Fingerprint fp, int remaining) { + if (remaining == 0) { + Log.d(TAG, "Enrolled fingerprints removed for user " + userId); + } + } + }; + } } diff --git a/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java b/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java index 7a2ae04f3e1..33f8b735588 100644 --- a/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java +++ b/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java @@ -17,6 +17,7 @@ package com.android.settings.connecteddevice; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -36,13 +37,16 @@ import com.android.settings.bluetooth.SavedBluetoothDeviceUpdater; import com.android.settings.connecteddevice.dock.DockUpdater; import com.android.settings.core.BasePreferenceController; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.flags.Flags; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class PreviouslyConnectedDevicePreferenceController extends BasePreferenceController implements LifecycleObserver, OnStart, OnStop, DevicePreferenceCallback { @@ -56,11 +60,12 @@ public class PreviouslyConnectedDevicePreferenceController extends BasePreferenc private final List mDevicesList = new ArrayList<>(); private final List mDockDevicesList = new ArrayList<>(); + private final Map mDevicePreferenceMap = new HashMap<>(); + private final BluetoothAdapter mBluetoothAdapter; private PreferenceGroup mPreferenceGroup; private BluetoothDeviceUpdater mBluetoothDeviceUpdater; private DockUpdater mSavedDockUpdater; - private BluetoothAdapter mBluetoothAdapter; @VisibleForTesting Preference mSeeAllPreference; @@ -81,7 +86,11 @@ public class PreviouslyConnectedDevicePreferenceController extends BasePreferenc mSavedDockUpdater = FeatureFactory.getFeatureFactory().getDockUpdaterFeatureProvider() .getSavedDockUpdater(context, this); mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); - mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + if (Flags.enableSavedDevicesOrderByRecency()) { + mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter(); + } else { + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + } } @Override @@ -114,6 +123,9 @@ public class PreviouslyConnectedDevicePreferenceController extends BasePreferenc mContext.registerReceiver(mReceiver, mIntentFilter, Context.RECEIVER_EXPORTED_UNAUDITED); mBluetoothDeviceUpdater.refreshPreference(); + if (Flags.enableSavedDevicesOrderByRecency()) { + updatePreferenceGroup(); + } } @Override @@ -131,19 +143,37 @@ public class PreviouslyConnectedDevicePreferenceController extends BasePreferenc @Override public void onDeviceAdded(Preference preference) { - final List bluetoothDevices = - mBluetoothAdapter.getMostRecentlyConnectedDevices(); - final int index = preference instanceof BluetoothDevicePreference - ? bluetoothDevices.indexOf(((BluetoothDevicePreference) preference) - .getBluetoothDevice().getDevice()) : DOCK_DEVICE_INDEX; - if (DEBUG) { - Log.d(TAG, "onDeviceAdded() " + preference.getTitle() + ", index of : " + index); - for (BluetoothDevice device : bluetoothDevices) { - Log.d(TAG, "onDeviceAdded() most recently device : " + device.getName()); + if (Flags.enableSavedDevicesOrderByRecency()) { + if (preference instanceof BluetoothDevicePreference) { + mDevicePreferenceMap.put( + ((BluetoothDevicePreference) preference).getBluetoothDevice().getDevice(), + preference); + } else { + mDockDevicesList.add(preference); } + if (DEBUG) { + Log.d(TAG, "onDeviceAdded() " + preference.getTitle()); + } + updatePreferenceGroup(); + } else { + final List bluetoothDevices = + mBluetoothAdapter.getMostRecentlyConnectedDevices(); + final int index = + preference instanceof BluetoothDevicePreference + ? bluetoothDevices.indexOf( + ((BluetoothDevicePreference) preference) + .getBluetoothDevice() + .getDevice()) + : DOCK_DEVICE_INDEX; + if (DEBUG) { + Log.d(TAG, "onDeviceAdded() " + preference.getTitle() + ", index of : " + index); + for (BluetoothDevice device : bluetoothDevices) { + Log.d(TAG, "onDeviceAdded() most recently device : " + device.getName()); + } + } + addPreference(index, preference); + updatePreferenceVisibility(); } - addPreference(index, preference); - updatePreferenceVisibility(); } private void addPreference(int index, Preference preference) { @@ -194,13 +224,57 @@ public class PreviouslyConnectedDevicePreferenceController extends BasePreferenc @Override public void onDeviceRemoved(Preference preference) { - if (preference instanceof BluetoothDevicePreference) { - mDevicesList.remove(preference); + if (Flags.enableSavedDevicesOrderByRecency()) { + if (preference instanceof BluetoothDevicePreference) { + mDevicePreferenceMap.remove( + ((BluetoothDevicePreference) preference).getBluetoothDevice().getDevice(), + preference); + } else { + mDockDevicesList.remove(preference); + } + if (DEBUG) { + Log.d(TAG, "onDeviceRemoved() " + preference.getTitle()); + } + updatePreferenceGroup(); } else { - mDockDevicesList.remove(preference); - } + if (preference instanceof BluetoothDevicePreference) { + mDevicesList.remove(preference); + } else { + mDockDevicesList.remove(preference); + } - addPreference(); + addPreference(); + updatePreferenceVisibility(); + } + } + + /** Sort the preferenceGroup by most recently used. */ + public void updatePreferenceGroup() { + mPreferenceGroup.removeAll(); + mPreferenceGroup.addPreference(mSeeAllPreference); + if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) { + // Bluetooth is supported + int order = 0; + for (BluetoothDevice device : mBluetoothAdapter.getMostRecentlyConnectedDevices()) { + Preference preference = mDevicePreferenceMap.getOrDefault(device, null); + if (preference != null) { + preference.setOrder(order); + mPreferenceGroup.addPreference(preference); + order += 1; + } + if (order == MAX_DEVICE_NUM) { + break; + } + } + for (Preference preference : mDockDevicesList) { + if (order == MAX_DEVICE_NUM) { + break; + } + preference.setOrder(order); + mPreferenceGroup.addPreference(preference); + order += 1; + } + } updatePreferenceVisibility(); } diff --git a/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java b/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java index fb35dd9f58c..c73481d3cd3 100644 --- a/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java +++ b/src/com/android/settings/connecteddevice/SavedDeviceGroupController.java @@ -15,6 +15,9 @@ */ package com.android.settings.connecteddevice; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; import android.content.Context; import android.content.pm.PackageManager; @@ -23,18 +26,25 @@ import androidx.preference.Preference; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; +import com.android.settings.bluetooth.BluetoothDevicePreference; import com.android.settings.bluetooth.BluetoothDeviceUpdater; import com.android.settings.bluetooth.SavedBluetoothDeviceUpdater; import com.android.settings.connecteddevice.dock.DockUpdater; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.flags.Flags; import com.android.settings.overlay.DockUpdaterFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * Controller to maintain the {@link PreferenceGroup} for all * saved devices. It uses {@link DevicePreferenceCallback} to add/remove {@link Preference} @@ -45,6 +55,10 @@ public class SavedDeviceGroupController extends BasePreferenceController private static final String KEY = "saved_device_list"; + private final Map mDevicePreferenceMap = new HashMap<>(); + private final List mDockDevicesList = new ArrayList<>(); + private final BluetoothAdapter mBluetoothAdapter; + @VisibleForTesting PreferenceGroup mPreferenceGroup; private BluetoothDeviceUpdater mBluetoothDeviceUpdater; @@ -57,6 +71,7 @@ public class SavedDeviceGroupController extends BasePreferenceController FeatureFactory.getFeatureFactory().getDockUpdaterFeatureProvider(); mSavedDockUpdater = dockUpdaterFeatureProvider.getSavedDockUpdater(context, this); + mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter(); } @Override @@ -64,6 +79,9 @@ public class SavedDeviceGroupController extends BasePreferenceController mBluetoothDeviceUpdater.registerCallback(); mSavedDockUpdater.registerCallback(); mBluetoothDeviceUpdater.refreshPreference(); + if (Flags.enableSavedDevicesOrderByRecency()) { + updatePreferenceGroup(); + } } @Override @@ -101,17 +119,63 @@ public class SavedDeviceGroupController extends BasePreferenceController @Override public void onDeviceAdded(Preference preference) { - if (mPreferenceGroup.getPreferenceCount() == 0) { - mPreferenceGroup.setVisible(true); + if (Flags.enableSavedDevicesOrderByRecency()) { + mPreferenceGroup.addPreference(preference); + if (preference instanceof BluetoothDevicePreference) { + mDevicePreferenceMap.put( + ((BluetoothDevicePreference) preference).getBluetoothDevice().getDevice(), + preference); + } else { + mDockDevicesList.add(preference); + } + updatePreferenceGroup(); + } else { + if (mPreferenceGroup.getPreferenceCount() == 0) { + mPreferenceGroup.setVisible(true); + } + mPreferenceGroup.addPreference(preference); } - mPreferenceGroup.addPreference(preference); } @Override public void onDeviceRemoved(Preference preference) { - mPreferenceGroup.removePreference(preference); - if (mPreferenceGroup.getPreferenceCount() == 0) { + if (Flags.enableSavedDevicesOrderByRecency()) { + mPreferenceGroup.removePreference(preference); + if (preference instanceof BluetoothDevicePreference) { + mDevicePreferenceMap.remove( + ((BluetoothDevicePreference) preference).getBluetoothDevice().getDevice(), + preference); + } else { + mDockDevicesList.remove(preference); + } + updatePreferenceGroup(); + } else { + mPreferenceGroup.removePreference(preference); + if (mPreferenceGroup.getPreferenceCount() == 0) { + mPreferenceGroup.setVisible(false); + } + } + } + + /** Sort the preferenceGroup by most recently used. */ + public void updatePreferenceGroup() { + if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { + // Bluetooth is unsupported or disabled mPreferenceGroup.setVisible(false); + } else { + mPreferenceGroup.setVisible(true); + int order = 0; + for (BluetoothDevice device : mBluetoothAdapter.getMostRecentlyConnectedDevices()) { + Preference preference = mDevicePreferenceMap.getOrDefault(device, null); + if (preference != null) { + preference.setOrder(order); + order += 1; + } + } + for (Preference preference : mDockDevicesList) { + preference.setOrder(order); + order += 1; + } } } @@ -130,4 +194,9 @@ public class SavedDeviceGroupController extends BasePreferenceController public void setSavedDockUpdater(DockUpdater savedDockUpdater) { mSavedDockUpdater = savedDockUpdater; } + + @VisibleForTesting + void setPreferenceGroup(PreferenceGroup preferenceGroup) { + mPreferenceGroup = preferenceGroup; + } } diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index b40b6bf898d..395003192aa 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -144,6 +144,7 @@ import com.android.settings.network.apn.ApnEditor; import com.android.settings.network.apn.ApnSettings; import com.android.settings.network.telephony.MobileNetworkSettings; import com.android.settings.network.telephony.NetworkSelectSettings; +import com.android.settings.network.telephony.SatelliteSetting; import com.android.settings.network.tether.TetherSettings; import com.android.settings.nfc.PaymentSettings; import com.android.settings.notification.ConfigureNotificationSettings; @@ -301,6 +302,7 @@ public class SettingsGateway { AppNotificationSettings.class.getName(), NotificationAssistantPicker.class.getName(), ChannelNotificationSettings.class.getName(), + SatelliteSetting.class.getName(), ApnSettings.class.getName(), ApnEditor.class.getName(), WifiCallingSettings.class.getName(), diff --git a/src/com/android/settings/network/NetworkProviderCallsSmsController.kt b/src/com/android/settings/network/NetworkProviderCallsSmsController.kt index 7346e236f68..67247c11936 100644 --- a/src/com/android/settings/network/NetworkProviderCallsSmsController.kt +++ b/src/com/android/settings/network/NetworkProviderCallsSmsController.kt @@ -28,6 +28,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.preference.PreferenceScreen import com.android.settings.R import com.android.settings.core.BasePreferenceController +import com.android.settings.flags.Flags import com.android.settingslib.RestrictedPreference import com.android.settingslib.Utils import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle @@ -62,6 +63,7 @@ open class NetworkProviderCallsSmsController @JvmOverloads constructor( } override fun getAvailabilityStatus() = when { + Flags.isDualSimOnboardingEnabled() -> UNSUPPORTED_ON_DEVICE !SubscriptionUtil.isSimHardwareVisible(mContext) -> UNSUPPORTED_ON_DEVICE !mContext.userManager.isAdminUser -> DISABLED_FOR_USER else -> AVAILABLE diff --git a/src/com/android/settings/network/NetworkProviderCallsSmsFragment.java b/src/com/android/settings/network/NetworkProviderCallsSmsFragment.java index b5ad65a7a97..ffe5b052a2f 100644 --- a/src/com/android/settings/network/NetworkProviderCallsSmsFragment.java +++ b/src/com/android/settings/network/NetworkProviderCallsSmsFragment.java @@ -24,6 +24,7 @@ import androidx.annotation.VisibleForTesting; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.flags.Flags; import com.android.settings.network.telephony.CallsDefaultSubscriptionController; import com.android.settings.network.telephony.NetworkProviderWifiCallingPreferenceController; import com.android.settings.network.telephony.SmsDefaultSubscriptionController; @@ -91,8 +92,9 @@ public class NetworkProviderCallsSmsFragment extends DashboardFragment { @Override protected boolean isPageSearchEnabled(Context context) { - return SubscriptionUtil.isSimHardwareVisible(context) && - context.getSystemService(UserManager.class).isAdminUser(); + return !Flags.isDualSimOnboardingEnabled() + && SubscriptionUtil.isSimHardwareVisible(context) + && context.getSystemService(UserManager.class).isAdminUser(); } }; } diff --git a/src/com/android/settings/network/WepNetworkDialogActivity.kt b/src/com/android/settings/network/WepNetworkDialogActivity.kt index 2fa87849ef1..d69630f6826 100644 --- a/src/com/android/settings/network/WepNetworkDialogActivity.kt +++ b/src/com/android/settings/network/WepNetworkDialogActivity.kt @@ -51,23 +51,24 @@ class WepNetworkDialogActivity : SpaBaseDialogActivity() { confirmButton = AlertDialogButton( getString(R.string.wifi_settings_ssid_block_button_close) ) { finish() }, - dismissButton = AlertDialogButton( - getString(R.string.wifi_settings_wep_networks_button_allow) - ) { - SubSettingLauncher(context) - .setTitleText(context.getText(R.string.network_and_internet_preferences_title)) - .setSourceMetricsCategory(SettingsEnums.CONFIGURE_WIFI) - .setDestination(ConfigureWifiSettings::class.java.getName()) - .launch() - finish() - }, + dismissButton = if (wifiManager?.isWepSupported == true) + AlertDialogButton( + getString(R.string.wifi_settings_wep_networks_button_allow) + ) { + SubSettingLauncher(context) + .setTitleText(context.getText(R.string.network_and_internet_preferences_title)) + .setSourceMetricsCategory(SettingsEnums.CONFIGURE_WIFI) + .setDestination(ConfigureWifiSettings::class.java.getName()) + .launch() + finish() + } else null, title = String.format( getString(R.string.wifi_settings_wep_networks_blocked_title), intent.getStringExtra(SSID) ?: SSID ), text = { Text( - if (wifiManager?.isWepSupported == false) + if (wifiManager?.isWepSupported == true) getString(R.string.wifi_settings_wep_networks_summary_toggle_off) else getString(R.string.wifi_settings_wep_networks_summary_blocked_by_carrier), modifier = Modifier.fillMaxWidth(), diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index b4b40efae9b..4188f8d1ad7 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -255,6 +255,11 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme roamingPreferenceController.init(getFragmentManager(), mSubId, mMobileNetworkInfoEntity); } + final SatelliteSettingPreferenceController satelliteSettingPreferenceController = use( + SatelliteSettingPreferenceController.class); + if (satelliteSettingPreferenceController != null) { + satelliteSettingPreferenceController.init(mSubId); + } use(ApnPreferenceController.class).init(mSubId); use(CarrierPreferenceController.class).init(mSubId); use(DataUsagePreferenceController.class).init(mSubId); diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java index cce12ec3cb0..47515d8d6fe 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java +++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java @@ -358,7 +358,8 @@ public class MobileNetworkUtils { .createForSubscriptionId(subId); final SubscriptionManager subscriptionManager = context.getSystemService( SubscriptionManager.class).createForAllUserProfiles(); - telephonyManager.setDataEnabled(enabled); + telephonyManager.setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER, + enabled); if (disableOtherSubscriptions) { final List subInfoList = @@ -367,8 +368,10 @@ public class MobileNetworkUtils { for (SubscriptionInfo subInfo : subInfoList) { // We never disable mobile data for opportunistic subscriptions. if (subInfo.getSubscriptionId() != subId && !subInfo.isOpportunistic()) { - context.getSystemService(TelephonyManager.class).createForSubscriptionId( - subInfo.getSubscriptionId()).setDataEnabled(false); + context.getSystemService(TelephonyManager.class) + .createForSubscriptionId(subInfo.getSubscriptionId()) + .setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER, + false); } } } diff --git a/src/com/android/settings/network/telephony/SatelliteSetting.java b/src/com/android/settings/network/telephony/SatelliteSetting.java new file mode 100644 index 00000000000..ecfa8e4000a --- /dev/null +++ b/src/com/android/settings/network/telephony/SatelliteSetting.java @@ -0,0 +1,198 @@ +/* + * 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.Activity; +import android.app.settings.SettingsEnums; +import android.content.Intent; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Bundle; +import android.os.UserManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.telephony.satellite.SatelliteManager; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.style.StyleSpan; +import android.text.style.UnderlineSpan; +import android.util.Log; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; + +import com.android.settings.R; +import com.android.settings.dashboard.RestrictedDashboardFragment; +import com.android.settingslib.HelpUtils; +import com.android.settingslib.Utils; +import com.android.settingslib.widget.FooterPreference; + +import java.util.Set; + +/** Handle Satellite Setting Preference Layout. */ +public class SatelliteSetting extends RestrictedDashboardFragment { + private static final String TAG = "SatelliteSetting"; + public static final String PREF_KEY_ABOUT_SATELLITE_MESSAGING = "key_about_satellite_messaging"; + public static final String PREF_KEY_CATEGORY_YOUR_SATELLITE_PLAN = + "key_category_your_satellite_plan"; + public static final String PREF_KEY_YOUR_SATELLITE_PLAN = "key_your_satellite_plan"; + public static final String PREF_KEY_CATEGORY_HOW_IT_WORKS = "key_category_how_it_works"; + private static final String KEY_FOOTER_PREFERENCE = "satellite_setting_extra_info_footer_pref"; + public static final String SUB_ID = "sub_id"; + + private Activity mActivity; + private TelephonyManager mTelephonymanager; + private SatelliteManager mSatelliteManager; + private int mSubId; + + public SatelliteSetting() { + super(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS); + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.SATELLITE_SETTING; + } + + @Override + public void onCreate(@NonNull Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mActivity = getActivity(); + mTelephonymanager = mActivity.getSystemService(TelephonyManager.class); + mSatelliteManager = mActivity.getSystemService(SatelliteManager.class); + mSubId = mActivity.getIntent().getIntExtra(SUB_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + updateDynamicPreferenceViews(); + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.satellite_setting; + } + + private void updateDynamicPreferenceViews() { + String operatorName = mTelephonymanager.getSimOperatorName(mSubId); + boolean isSatelliteEligible = isSatelliteEligible(); + + // About satellite messaging + Preference preference = findPreference(PREF_KEY_ABOUT_SATELLITE_MESSAGING); + preference.setTitle( + getResources().getString(R.string.title_about_satellite_setting, operatorName)); + + // Your mobile plan + PreferenceCategory prefCategory = findPreference(PREF_KEY_CATEGORY_YOUR_SATELLITE_PLAN); + prefCategory.setTitle(getResources().getString(R.string.category_title_your_satellite_plan, + operatorName)); + + preference = findPreference(PREF_KEY_YOUR_SATELLITE_PLAN); + Drawable icon; + if (isSatelliteEligible) { + /* In case satellite is allowed by carrier's entitlement server, the page will show + the check icon with guidance that satellite is included in user's mobile plan */ + preference.setTitle(R.string.title_have_satellite_plan); + icon = getResources().getDrawable(R.drawable.ic_check_circle_24px); + } else { + /* Or, it will show the blocked icon with the guidance that satellite is not included + in user's mobile plan */ + preference.setTitle(R.string.title_no_satellite_plan); + /* And, the link url provides more information via web page will be shown */ + SpannableString spannable = new SpannableString( + getResources().getString(R.string.summary_add_satellite_setting)); + spannable.setSpan(new UnderlineSpan(), 0, spannable.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + spannable.setSpan(new StyleSpan(Typeface.BOLD), 0, spannable.length(), + Spanned.SPAN_INCLUSIVE_INCLUSIVE); + preference.setSummary(spannable); + /* The link will lead users to a guide page */ + preference.setOnPreferenceClickListener(pref -> { + String url = getResources().getString(R.string.more_info_satellite_messaging_link); + if (!url.isEmpty()) { + Uri uri = Uri.parse(url); + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + startActivity(intent); + } + return true; + }); + icon = getResources().getDrawable(R.drawable.ic_block_24px); + } + icon.setTintList(Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary)); + preference.setIcon(icon); + + /* Composes "How it works" section, which guides how users can use satellite messaging, when + satellite messaging is included in user's mobile plan, or it'll will be grey out. */ + if (!isSatelliteEligible) { + PreferenceCategory category = findPreference(PREF_KEY_CATEGORY_HOW_IT_WORKS); + category.setEnabled(false); + category.setShouldDisableView(true); + } + + // More about satellite messaging + FooterPreference footerPreference = findPreference(KEY_FOOTER_PREFERENCE); + if (footerPreference != null) { + footerPreference.setSummary( + getResources().getString(R.string.satellite_setting_summary_more_information, + operatorName)); + + final String[] link = new String[1]; + link[0] = getResources().getString(R.string.more_info_satellite_messaging_link); + footerPreference.setLearnMoreAction(view -> { + if (!link[0].isEmpty()) { + Intent helpIntent = HelpUtils.getHelpIntent(mActivity, link[0], + this.getClass().getName()); + if (helpIntent != null) { + mActivity.startActivityForResult(helpIntent, /*requestCode=*/ 0); + } + } + }); + footerPreference.setLearnMoreText( + getResources().getString(R.string.more_about_satellite_messaging)); + + // TODO : b/320467418 add rounded rectangle border line to footer preference. + } + } + + private boolean isSatelliteEligible() { + try { + Set restrictionReason = + mSatelliteManager.getSatelliteAttachRestrictionReasonsForCarrier(mSubId); + return !restrictionReason.contains( + SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT); + } catch (SecurityException | IllegalStateException | IllegalArgumentException ex) { + loge(ex.toString()); + return false; + } + } + + private static void loge(String message) { + Log.e(TAG, message); + } +} diff --git a/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java b/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java new file mode 100644 index 00000000000..7de7fcba64e --- /dev/null +++ b/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java @@ -0,0 +1,139 @@ +/* + * 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.PersistableBundle; +import android.provider.Settings; +import android.telephony.CarrierConfigManager; +import android.telephony.satellite.SatelliteManager; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.SettingsActivity; +import com.android.settings.network.CarrierConfigCache; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; + +import java.util.Set; + +/** + * Preference controller for "Satellite Setting" + */ +public class SatelliteSettingPreferenceController extends + TelephonyBasePreferenceController implements LifecycleObserver, OnStart, OnStop { + + private static final String TAG = "SatelliteSettingPreferenceController"; + + CarrierConfigCache mCarrierConfigCache; + SatelliteManager mSatelliteManager; + @Nullable private Boolean mIsSatelliteEligible = null; + + public SatelliteSettingPreferenceController(@NonNull Context context, @NonNull String key) { + super(context, key); + mCarrierConfigCache = CarrierConfigCache.getInstance(context); + mSatelliteManager = context.getSystemService(SatelliteManager.class); + } + + @Override + public int getAvailabilityStatus(int subId) { + final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(subId); + final boolean isSatelliteAttachSupported = carrierConfig.getBoolean( + CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL); + + return isSatelliteAttachSupported ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void onStart() { + } + + @Override + public void onStop() { + } + + @Override + public void displayPreference(@NonNull PreferenceScreen screen) { + super.displayPreference(screen); + } + + @Override + public void updateState(@Nullable Preference preference) { + super.updateState(preference); + if (preference != null) { + updateSummary(preference); + } + } + + @Override + public boolean handlePreferenceTreeClick(@NonNull Preference preference) { + if (getPreferenceKey().equals(preference.getKey())) { + // This activity runs in phone process, we must use intent to start + final Intent intent = new Intent(Settings.ACTION_SATELLITE_SETTING); + // This will setup the Home and Search affordance + intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, true); + intent.putExtra(SatelliteSetting.SUB_ID, mSubId); + mContext.startActivity(intent); + return true; + } + + return false; + } + + /** + * Set subId for Satellite Settings page. + * @param subId subscription ID. + */ + public void init(int subId) { + logd("init(), subId=" + subId); + mSubId = subId; + } + + private void updateSummary(Preference preference) { + try { + Set restrictionReason = + mSatelliteManager.getSatelliteAttachRestrictionReasonsForCarrier(mSubId); + boolean isSatelliteEligible = !restrictionReason.contains( + SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT); + if (mIsSatelliteEligible == null || mIsSatelliteEligible != isSatelliteEligible) { + mIsSatelliteEligible = isSatelliteEligible; + String summary = mContext.getString( + mIsSatelliteEligible ? R.string.satellite_setting_enabled_summary + : R.string.satellite_setting_disabled_summary); + preference.setSummary(summary); + } + } catch (SecurityException | IllegalStateException | IllegalArgumentException ex) { + loge(ex.toString()); + preference.setSummary(R.string.satellite_setting_disabled_summary); + } + } + + private static void logd(String message) { + Log.d(TAG, message); + } + + private static void loge(String message) { + Log.e(TAG, message); + } +} diff --git a/src/com/android/settings/privatespace/PrivateSpaceAccountLoginError.java b/src/com/android/settings/privatespace/PrivateSpaceAccountLoginError.java index b64335bdf43..fcb93b1c38e 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceAccountLoginError.java +++ b/src/com/android/settings/privatespace/PrivateSpaceAccountLoginError.java @@ -31,6 +31,7 @@ import android.view.ViewGroup; import androidx.activity.OnBackPressedCallback; import androidx.annotation.Nullable; +import androidx.navigation.fragment.NavHostFragment; import com.android.settings.R; import com.android.settings.core.InstrumentedFragment; @@ -55,11 +56,20 @@ public class PrivateSpaceAccountLoginError extends InstrumentedFragment { final FooterBarMixin mixin = rootView.getMixin(FooterBarMixin.class); mixin.setPrimaryButton( new FooterButton.Builder(getContext()) - .setText(R.string.private_space_tryagain_label) + .setText(R.string.private_space_continue_login_label) .setListener(nextScreen()) .setButtonType(FooterButton.ButtonType.NEXT) .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary) .build()); + mixin.setSecondaryButton( + new FooterButton.Builder(getContext()) + .setText(R.string.private_space_skip_login_label) + .setListener(onSkip()) + .setButtonType(FooterButton.ButtonType.CANCEL) + .setTheme( + androidx.appcompat.R.style + .Base_TextAppearance_AppCompat_Widget_Button) + .build()); OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) { @Override @@ -96,4 +106,17 @@ public class PrivateSpaceAccountLoginError extends InstrumentedFragment { } }; } + + private View.OnClickListener onSkip() { + return v -> { + mMetricsFeatureProvider.action( + getContext(), SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_SKIP_ACCOUNT_LOGIN); + mMetricsFeatureProvider.action( + getContext(), + SettingsEnums.ACTION_PRIVATE_SPACE_SETUP_ACCOUNT_LOGIN_SUCCESS, + false); + NavHostFragment.findNavController(PrivateSpaceAccountLoginError.this) + .navigate(R.id.action_success_fragment); + }; + } } diff --git a/src/com/android/settings/privatespace/onelock/FaceFingerprintUnlockController.java b/src/com/android/settings/privatespace/onelock/FaceFingerprintUnlockController.java index 271a2195d30..2e3f2840b70 100644 --- a/src/com/android/settings/privatespace/onelock/FaceFingerprintUnlockController.java +++ b/src/com/android/settings/privatespace/onelock/FaceFingerprintUnlockController.java @@ -23,6 +23,7 @@ import android.util.Log; import androidx.preference.Preference; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.biometrics.combination.CombinedBiometricStatusPreferenceController; import com.android.settings.privatespace.PrivateSpaceMaintainer; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -72,6 +73,8 @@ public class FaceFingerprintUnlockController extends CombinedBiometricStatusPref super.updateState(preference); preference.setEnabled(true); } else { + Utils.removeEnrolledFaceForUser(mContext, getUserId()); + Utils.removeEnrolledFingerprintForUser(mContext, getUserId()); preference.setSummary( mContext.getString(R.string.lock_settings_profile_unified_summary)); preference.setEnabled(false); diff --git a/src/com/android/settings/privatespace/onelock/PrivateSpaceFacePreferenceController.java b/src/com/android/settings/privatespace/onelock/PrivateSpaceFacePreferenceController.java index 2a5ff885dfd..b841d9aded5 100644 --- a/src/com/android/settings/privatespace/onelock/PrivateSpaceFacePreferenceController.java +++ b/src/com/android/settings/privatespace/onelock/PrivateSpaceFacePreferenceController.java @@ -74,6 +74,7 @@ public class PrivateSpaceFacePreferenceController extends BiometricFaceStatusPre super.updateState(preference); preference.setEnabled(true); } else { + Utils.removeEnrolledFaceForUser(mContext, getUserId()); preference.setSummary( mContext.getString(R.string.lock_settings_profile_unified_summary)); preference.setEnabled(false); diff --git a/src/com/android/settings/privatespace/onelock/PrivateSpaceFingerprintPreferenceController.java b/src/com/android/settings/privatespace/onelock/PrivateSpaceFingerprintPreferenceController.java index b6c44574fc4..d48490460b5 100644 --- a/src/com/android/settings/privatespace/onelock/PrivateSpaceFingerprintPreferenceController.java +++ b/src/com/android/settings/privatespace/onelock/PrivateSpaceFingerprintPreferenceController.java @@ -76,6 +76,7 @@ public class PrivateSpaceFingerprintPreferenceController super.updateState(preference); preference.setEnabled(true); } else { + Utils.removeEnrolledFingerprintForUser(mContext, getUserId()); preference.setSummary( mContext.getString(R.string.lock_settings_profile_unified_summary)); preference.setEnabled(false); diff --git a/src/com/android/settings/security/SimLockPreferenceController.java b/src/com/android/settings/security/SimLockPreferenceController.java index 8429a9f352c..8cc72342e0e 100644 --- a/src/com/android/settings/security/SimLockPreferenceController.java +++ b/src/com/android/settings/security/SimLockPreferenceController.java @@ -44,8 +44,9 @@ public class SimLockPreferenceController extends BasePreferenceController { mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mCarrierConfigManager = (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - mSubscriptionManager = (SubscriptionManager) context - .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); + mSubscriptionManager = ((SubscriptionManager) context + .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)) + .createForAllUserProfiles(); mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); } diff --git a/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragment.java b/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragment.java index b1b5f8e69ed..bd6a394f597 100644 --- a/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragment.java +++ b/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragment.java @@ -195,7 +195,7 @@ public class EnableAutoDataSwitchDialogFragment extends SimDialogFragment implem } private SubscriptionManager getSubscriptionManager() { - return getContext().getSystemService(SubscriptionManager.class); + return getContext().getSystemService(SubscriptionManager.class).createForAllUserProfiles(); } @VisibleForTesting diff --git a/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java b/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java index 37f5445238e..b0b65f66e2e 100644 --- a/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java +++ b/src/com/android/settings/sim/SelectSpecificDataSimDialogFragment.java @@ -194,7 +194,7 @@ public class SelectSpecificDataSimDialogFragment extends SimDialogFragment imple @VisibleForTesting protected SubscriptionManager getSubscriptionManager() { - return getContext().getSystemService(SubscriptionManager.class); + return getContext().getSystemService(SubscriptionManager.class).createForAllUserProfiles(); } @Override diff --git a/src/com/android/settings/sim/SimListDialogFragment.java b/src/com/android/settings/sim/SimListDialogFragment.java index db2c4dc224d..fd44dc74a67 100644 --- a/src/com/android/settings/sim/SimListDialogFragment.java +++ b/src/com/android/settings/sim/SimListDialogFragment.java @@ -125,7 +125,7 @@ public class SimListDialogFragment extends SimDialogFragment { protected List getCurrentSubscriptions() { final SubscriptionManager manager = getContext().getSystemService( - SubscriptionManager.class); + SubscriptionManager.class).createForAllUserProfiles(); return manager.getActiveSubscriptionInfoList(); } diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index 29d136fd9cc..d39d980f29d 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -35,6 +35,7 @@ import android.graphics.BitmapFactory; import android.graphics.BlendMode; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; +import android.multiuser.Flags; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; @@ -892,13 +893,24 @@ public class UserSettings extends SettingsPreferenceFragment UserIcons.convertToBitmapAtUserIconSize( activity.getResources(), newUserIcon))); mMePreference.setIcon(newUserIcon); + if (Flags.avatarSync()) { + final String pkg = getString(R.string.config_avatar_picker_package); + final String action = pkg + ".set.confirm"; + activity.sendBroadcast(new Intent(action).setPackage(pkg)); + } } if (!TextUtils.isEmpty(newUserName) && !newUserName.equals(user.name)) { mMePreference.setTitle(newUserName); mUserManager.setUserName(user.id, newUserName); } - }, null); + }, () -> { + if (Flags.avatarSync()) { + final String pkg = getString(R.string.config_avatar_picker_package); + final String action = pkg + ".set.cancel"; + activity.sendBroadcast(new Intent(action).setPackage(pkg)); + } + }); } private Dialog buildAddUserDialog(int userType) { diff --git a/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java index 783eebe0da1..59e656c6a39 100644 --- a/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import android.accounts.AccountManager; import android.accounts.AuthenticatorDescription; import android.app.Activity; import android.app.admin.DevicePolicyManager; @@ -35,6 +36,7 @@ import androidx.fragment.app.FragmentActivity; import androidx.preference.Preference; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; +import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; @@ -44,33 +46,38 @@ import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class, ShadowRestrictedLockUtilsInternal.class}) public class ChooseAccountPreferenceControllerTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); private Context mContext; private ChooseAccountPreferenceController mController; private Activity mActivity; private PreferenceManager mPreferenceManager; private PreferenceScreen mPreferenceScreen; + private ShadowAccountManager mAccountManager; @Before public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = ApplicationProvider.getApplicationContext(); mController = spy(new ChooseAccountPreferenceController(mContext, "controller_key")); mActivity = Robolectric.setupActivity(FragmentActivity.class); mPreferenceManager = new PreferenceManager(mContext); mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext); + mAccountManager = (ShadowAccountManager) Shadows.shadowOf(AccountManager.get(mContext)); } @After @@ -108,7 +115,7 @@ public class ChooseAccountPreferenceControllerTest { final AuthenticatorDescription authDesc = new AuthenticatorDescription("com.acct1", "com.android.settings", R.string.header_add_an_account, 0, 0, 0, false); - ShadowAccountManager.addAuthenticator(authDesc); + mAccountManager.addAuthenticator(authDesc); final SyncAdapterType[] syncAdapters = {new SyncAdapterType("authority" /* authority */, "com.acct1" /* accountType */, false /* userVisible */, @@ -133,7 +140,7 @@ public class ChooseAccountPreferenceControllerTest { final AuthenticatorDescription authDesc = new AuthenticatorDescription("com.acct1", "com.android.settings", R.string.header_add_an_account, 0, 0, 0, false); - ShadowAccountManager.addAuthenticator(authDesc); + mAccountManager.addAuthenticator(authDesc); final SyncAdapterType[] syncAdapters = {new SyncAdapterType("authority" /* authority */, "com.acct1" /* accountType */, false /* userVisible */, @@ -158,7 +165,7 @@ public class ChooseAccountPreferenceControllerTest { final AuthenticatorDescription authDesc = new AuthenticatorDescription("com.acct1", "com.android.settings", R.string.header_add_an_account, 0, 0, 0, false); - ShadowAccountManager.addAuthenticator(authDesc); + mAccountManager.addAuthenticator(authDesc); final SyncAdapterType[] syncAdapters = {new SyncAdapterType("authority" /* authority */, "com.acct1" /* accountType */, false /* userVisible */, @@ -184,8 +191,8 @@ public class ChooseAccountPreferenceControllerTest { final AuthenticatorDescription authDesc2 = new AuthenticatorDescription("com.acct2", "com.android.settings", R.string.header_add_an_account, 0, 0, 0, false); - ShadowAccountManager.addAuthenticator(authDesc); - ShadowAccountManager.addAuthenticator(authDesc2); + mAccountManager.addAuthenticator(authDesc); + mAccountManager.addAuthenticator(authDesc2); final SyncAdapterType[] syncAdapters = {new SyncAdapterType("authority" /* authority */, "com.acct1" /* accountType */, false /* userVisible */, diff --git a/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java index e351b71b3dc..005c1311747 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceControllerTest.java @@ -27,9 +27,14 @@ import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; +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.util.Pair; import androidx.preference.Preference; @@ -42,11 +47,13 @@ import com.android.settings.bluetooth.BluetoothDevicePreference; import com.android.settings.bluetooth.BluetoothDeviceUpdater; import com.android.settings.connecteddevice.dock.DockUpdater; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.flags.Flags; import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; import com.android.settings.widget.SingleTargetGearPreference; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -70,6 +77,9 @@ public class PreviouslyConnectedDevicePreferenceControllerTest { private static final String FAKE_ADDRESS_4 = "AA:AA:AA:AA:AA:04"; private static final String FAKE_ADDRESS_5 = "AA:AA:AA:AA:AA:05"; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Mock private DashboardFragment mDashboardFragment; @Mock @@ -105,6 +115,9 @@ public class PreviouslyConnectedDevicePreferenceControllerTest { @Mock private Drawable mDrawable; + @Mock private BluetoothManager mBluetoothManager; + @Mock private BluetoothAdapter mBluetoothAdapter; + private Context mContext; private PreviouslyConnectedDevicePreferenceController mPreConnectedDeviceController; private PreferenceGroup mPreferenceGroup; @@ -117,10 +130,8 @@ public class PreviouslyConnectedDevicePreferenceControllerTest { mContext = spy(RuntimeEnvironment.application); doReturn(mContext).when(mDashboardFragment).getContext(); doReturn(mPackageManager).when(mContext).getPackageManager(); - mPreConnectedDeviceController = - new PreviouslyConnectedDevicePreferenceController(mContext, KEY); - mPreConnectedDeviceController.setBluetoothDeviceUpdater(mBluetoothDeviceUpdater); - mPreConnectedDeviceController.setSavedDockUpdater(mDockUpdater); + when(mContext.getSystemService(BluetoothManager.class)).thenReturn(mBluetoothManager); + when(mBluetoothManager.getAdapter()).thenReturn(mBluetoothAdapter); mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); when(mCachedDevice1.getDevice()).thenReturn(mBluetoothDevice1); @@ -145,7 +156,13 @@ public class PreviouslyConnectedDevicePreferenceControllerTest { mMostRecentlyConnectedDevices.add(mBluetoothDevice4); mMostRecentlyConnectedDevices.add(mBluetoothDevice3); mShadowBluetoothAdapter.setMostRecentlyConnectedDevices(mMostRecentlyConnectedDevices); + when(mBluetoothAdapter.getMostRecentlyConnectedDevices()) + .thenReturn(mMostRecentlyConnectedDevices); + mPreConnectedDeviceController = + new PreviouslyConnectedDevicePreferenceController(mContext, KEY); + mPreConnectedDeviceController.setBluetoothDeviceUpdater(mBluetoothDeviceUpdater); + mPreConnectedDeviceController.setSavedDockUpdater(mDockUpdater); mPreferenceGroup = spy(new PreferenceCategory(mContext)); doReturn(mPreferenceManager).when(mPreferenceGroup).getPreferenceManager(); mPreferenceGroup.setVisible(false); @@ -249,6 +266,7 @@ public class PreviouslyConnectedDevicePreferenceControllerTest { } @Test + @RequiresFlagsDisabled(Flags.FLAG_ENABLE_SAVED_DEVICES_ORDER_BY_RECENCY) public void onDeviceAdded_addPreferenceNotExistInRecentlyDevices_noCrash() { final BluetoothDevicePreference preference = new BluetoothDevicePreference( mContext, mCachedDevice5, true, BluetoothDevicePreference.SortType.TYPE_NO_SORT); @@ -259,6 +277,18 @@ public class PreviouslyConnectedDevicePreferenceControllerTest { assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2); } + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SAVED_DEVICES_ORDER_BY_RECENCY) + public void onDeviceAdded_addPreferenceNotExistInRecentlyDevices_doNothing() { + final BluetoothDevicePreference preference = new BluetoothDevicePreference( + mContext, mCachedDevice5, true, BluetoothDevicePreference.SortType.TYPE_NO_SORT); + + mPreConnectedDeviceController.onDeviceAdded(preference); + + // 1 see all preference + assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1); + } + @Test public void onDeviceRemoved_removeLastDevice_showSeeAllPreference() { final BluetoothDevicePreference preference1 = new BluetoothDevicePreference( @@ -277,6 +307,7 @@ public class PreviouslyConnectedDevicePreferenceControllerTest { @Test public void updatePreferenceVisibility_bluetoothIsEnable_shouldShowCorrectText() { mShadowBluetoothAdapter.setEnabled(true); + when(mBluetoothAdapter.isEnabled()).thenReturn(true); mPreConnectedDeviceController.updatePreferenceVisibility(); verify(mSeeAllPreference).setSummary(""); @@ -285,9 +316,78 @@ public class PreviouslyConnectedDevicePreferenceControllerTest { @Test public void updatePreferenceVisibility_bluetoothIsDisable_shouldShowCorrectText() { mShadowBluetoothAdapter.setEnabled(false); + when(mBluetoothAdapter.isEnabled()).thenReturn(false); mPreConnectedDeviceController.updatePreferenceVisibility(); verify(mSeeAllPreference).setSummary( mContext.getString(R.string.connected_device_see_all_summary)); } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SAVED_DEVICES_ORDER_BY_RECENCY) + public void updatePreferenceGroup_bluetoothIsEnable_shouldOrderByMostRecentlyConnected() { + when(mBluetoothAdapter.isEnabled()).thenReturn(true); + final BluetoothDevicePreference preference4 = + new BluetoothDevicePreference( + mContext, + mCachedDevice4, + true, + BluetoothDevicePreference.SortType.TYPE_NO_SORT); + final BluetoothDevicePreference preference3 = + new BluetoothDevicePreference( + mContext, + mCachedDevice3, + true, + BluetoothDevicePreference.SortType.TYPE_NO_SORT); + final BluetoothDevicePreference preference2 = + new BluetoothDevicePreference( + mContext, + mCachedDevice2, + true, + BluetoothDevicePreference.SortType.TYPE_NO_SORT); + mPreConnectedDeviceController.onDeviceAdded(preference4); + mPreConnectedDeviceController.onDeviceAdded(preference3); + mPreConnectedDeviceController.onDeviceAdded(preference2); + + mPreConnectedDeviceController.updatePreferenceGroup(); + + // Refer to the order of {@link #mMostRecentlyConnectedDevices}, the first one is see all + // preference + assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(4); + assertThat(preference2.getOrder()).isEqualTo(0); + assertThat(preference4.getOrder()).isEqualTo(1); + assertThat(preference3.getOrder()).isEqualTo(2); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SAVED_DEVICES_ORDER_BY_RECENCY) + public void updatePreferenceGroup_bluetoothIsDisable_shouldShowOnlySeeAllPreference() { + when(mBluetoothAdapter.isEnabled()).thenReturn(false); + final BluetoothDevicePreference preference4 = + new BluetoothDevicePreference( + mContext, + mCachedDevice4, + true, + BluetoothDevicePreference.SortType.TYPE_NO_SORT); + final BluetoothDevicePreference preference3 = + new BluetoothDevicePreference( + mContext, + mCachedDevice3, + true, + BluetoothDevicePreference.SortType.TYPE_NO_SORT); + final BluetoothDevicePreference preference2 = + new BluetoothDevicePreference( + mContext, + mCachedDevice2, + true, + BluetoothDevicePreference.SortType.TYPE_NO_SORT); + mPreConnectedDeviceController.onDeviceAdded(preference4); + mPreConnectedDeviceController.onDeviceAdded(preference3); + mPreConnectedDeviceController.onDeviceAdded(preference2); + + mPreConnectedDeviceController.updatePreferenceGroup(); + + // 1 see all preference + assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1); + } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/SavedDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/SavedDeviceGroupControllerTest.java index d2c44f938e4..81c0c35ccd6 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/SavedDeviceGroupControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/SavedDeviceGroupControllerTest.java @@ -25,29 +25,52 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; import android.content.Context; import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.util.Pair; import androidx.lifecycle.LifecycleOwner; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceManager; +import com.android.settings.bluetooth.BluetoothDevicePreference; import com.android.settings.bluetooth.BluetoothDeviceUpdater; import com.android.settings.connecteddevice.dock.DockUpdater; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.flags.Flags; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import java.util.ArrayList; +import java.util.List; + @RunWith(RobolectricTestRunner.class) public class SavedDeviceGroupControllerTest { + private static final String FAKE_ADDRESS_1 = "AA:AA:AA:AA:AA:01"; + private static final String FAKE_ADDRESS_2 = "AA:AA:AA:AA:AA:02"; + private static final String FAKE_ADDRESS_3 = "AA:AA:AA:AA:AA:03"; + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Mock private DashboardFragment mDashboardFragment; @Mock @@ -56,23 +79,57 @@ public class SavedDeviceGroupControllerTest { private DockUpdater mSavedDockUpdater; @Mock private PackageManager mPackageManager; + @Mock private BluetoothManager mBluetoothManager; + @Mock private BluetoothAdapter mBluetoothAdapter; + @Mock private CachedBluetoothDevice mCachedDevice1; + @Mock private CachedBluetoothDevice mCachedDevice2; + @Mock private CachedBluetoothDevice mCachedDevice3; + @Mock private BluetoothDevice mBluetoothDevice1; + @Mock private BluetoothDevice mBluetoothDevice2; + @Mock private BluetoothDevice mBluetoothDevice3; + @Mock private Drawable mDrawable; + @Mock private PreferenceManager mPreferenceManager; private Context mContext; private SavedDeviceGroupController mSavedDeviceGroupController; private LifecycleOwner mLifecycleOwner; private Lifecycle mLifecycle; + private PreferenceGroup mPreferenceGroup; @Before public void setUp() { MockitoAnnotations.initMocks(this); + Pair pairs = new Pair<>(mDrawable, "fake_device"); mContext = spy(RuntimeEnvironment.application); mLifecycleOwner = () -> mLifecycle; mLifecycle = new Lifecycle(mLifecycleOwner); doReturn(mContext).when(mDashboardFragment).getContext(); doReturn(mPackageManager).when(mContext).getPackageManager(); + + when(mCachedDevice1.getDevice()).thenReturn(mBluetoothDevice1); + when(mCachedDevice1.getAddress()).thenReturn(FAKE_ADDRESS_1); + when(mCachedDevice1.getDrawableWithDescription()).thenReturn(pairs); + when(mCachedDevice2.getDevice()).thenReturn(mBluetoothDevice2); + when(mCachedDevice2.getAddress()).thenReturn(FAKE_ADDRESS_2); + when(mCachedDevice2.getDrawableWithDescription()).thenReturn(pairs); + when(mCachedDevice3.getDevice()).thenReturn(mBluetoothDevice3); + when(mCachedDevice3.getAddress()).thenReturn(FAKE_ADDRESS_3); + when(mCachedDevice3.getDrawableWithDescription()).thenReturn(pairs); + final List mMostRecentlyConnectedDevices = new ArrayList<>(); + mMostRecentlyConnectedDevices.add(mBluetoothDevice1); + mMostRecentlyConnectedDevices.add(mBluetoothDevice2); + mMostRecentlyConnectedDevices.add(mBluetoothDevice3); + when(mContext.getSystemService(BluetoothManager.class)).thenReturn(mBluetoothManager); + when(mBluetoothManager.getAdapter()).thenReturn(mBluetoothAdapter); + when(mBluetoothAdapter.getMostRecentlyConnectedDevices()) + .thenReturn(mMostRecentlyConnectedDevices); + + mPreferenceGroup = spy(new PreferenceCategory(mContext)); + when(mPreferenceGroup.getPreferenceManager()).thenReturn(mPreferenceManager); mSavedDeviceGroupController = new SavedDeviceGroupController(mContext); mSavedDeviceGroupController.setBluetoothDeviceUpdater(mBluetoothDeviceUpdater); mSavedDeviceGroupController.setSavedDockUpdater(mSavedDockUpdater); + mSavedDeviceGroupController.setPreferenceGroup(mPreferenceGroup); } @Test @@ -118,4 +175,71 @@ public class SavedDeviceGroupControllerTest { assertThat(mSavedDeviceGroupController.getAvailabilityStatus()).isEqualTo( AVAILABLE); } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SAVED_DEVICES_ORDER_BY_RECENCY) + public void updatePreferenceGroup_bluetoothIsEnable_shouldOrderByMostRecentlyConnected() { + when(mBluetoothAdapter.isEnabled()).thenReturn(true); + final BluetoothDevicePreference preference3 = + new BluetoothDevicePreference( + mContext, + mCachedDevice3, + true, + BluetoothDevicePreference.SortType.TYPE_NO_SORT); + final BluetoothDevicePreference preference2 = + new BluetoothDevicePreference( + mContext, + mCachedDevice2, + true, + BluetoothDevicePreference.SortType.TYPE_NO_SORT); + final BluetoothDevicePreference preference1 = + new BluetoothDevicePreference( + mContext, + mCachedDevice1, + true, + BluetoothDevicePreference.SortType.TYPE_NO_SORT); + mSavedDeviceGroupController.onDeviceAdded(preference3); + mSavedDeviceGroupController.onDeviceAdded(preference2); + mSavedDeviceGroupController.onDeviceAdded(preference1); + + mSavedDeviceGroupController.updatePreferenceGroup(); + + // Refer to the order of {@link #mMostRecentlyConnectedDevices} + assertThat(mPreferenceGroup.isVisible()).isTrue(); + assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(3); + assertThat(preference1.getOrder()).isEqualTo(0); + assertThat(preference2.getOrder()).isEqualTo(1); + assertThat(preference3.getOrder()).isEqualTo(2); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SAVED_DEVICES_ORDER_BY_RECENCY) + public void updatePreferenceGroup_bluetoothIsDisable_shouldShowNoPreference() { + when(mBluetoothAdapter.isEnabled()).thenReturn(false); + final BluetoothDevicePreference preference3 = + new BluetoothDevicePreference( + mContext, + mCachedDevice3, + true, + BluetoothDevicePreference.SortType.TYPE_NO_SORT); + final BluetoothDevicePreference preference2 = + new BluetoothDevicePreference( + mContext, + mCachedDevice2, + true, + BluetoothDevicePreference.SortType.TYPE_NO_SORT); + final BluetoothDevicePreference preference1 = + new BluetoothDevicePreference( + mContext, + mCachedDevice2, + true, + BluetoothDevicePreference.SortType.TYPE_NO_SORT); + mSavedDeviceGroupController.onDeviceAdded(preference3); + mSavedDeviceGroupController.onDeviceAdded(preference2); + mSavedDeviceGroupController.onDeviceAdded(preference1); + + mSavedDeviceGroupController.updatePreferenceGroup(); + + assertThat(mPreferenceGroup.isVisible()).isFalse(); + } } diff --git a/tests/robotests/src/com/android/settings/development/compat/PlatformCompatDashboardTest.java b/tests/robotests/src/com/android/settings/development/compat/PlatformCompatDashboardTest.java index 5a679ad56d7..86ceadc0811 100644 --- a/tests/robotests/src/com/android/settings/development/compat/PlatformCompatDashboardTest.java +++ b/tests/robotests/src/com/android/settings/development/compat/PlatformCompatDashboardTest.java @@ -41,7 +41,8 @@ import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; -import androidx.preference.SwitchPreference; +import androidx.preference.SwitchPreferenceCompat; +import androidx.test.core.app.ApplicationProvider; import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.compat.CompatibilityChangeInfo; @@ -51,13 +52,13 @@ import com.android.internal.compat.OverrideAllowedState; import com.android.settings.R; import org.junit.Before; -import org.junit.Ignore; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import java.util.ArrayList; import java.util.Arrays; @@ -67,6 +68,8 @@ import java.util.Set; @RunWith(RobolectricTestRunner.class) public class PlatformCompatDashboardTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); private PlatformCompatDashboard mDashboard; @Mock @@ -87,7 +90,6 @@ public class PlatformCompatDashboardTest { @Before public void setUp() throws RemoteException, NameNotFoundException { - MockitoAnnotations.initMocks(this); mChanges = new CompatibilityChangeInfo[5]; mChanges[0] = new CompatibilityChangeInfo( 1L, "Default_Enabled", 0, 0, false, false, "", false); @@ -104,7 +106,7 @@ public class PlatformCompatDashboardTest { // By default, allow any change when(mOverrideValidator.getOverrideAllowedState(anyLong(),anyString())) .thenReturn(new OverrideAllowedState(ALLOWED, -1, -1)); - mContext = spy(RuntimeEnvironment.application); + mContext = spy(ApplicationProvider.getApplicationContext()); mPreferenceManager = new PreferenceManager(mContext); mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext); mApplicationInfo.packageName = APP_NAME; @@ -141,7 +143,6 @@ public class PlatformCompatDashboardTest { R.string.platform_compat_selected_app_summary, APP_NAME, 1)); } - @Ignore("b/313591873") @Test public void createPreferenceForChange_defaultEnabledChange_createCheckedEntry() { CompatibilityChangeInfo enabledChange = mChanges[0]; @@ -152,15 +153,14 @@ public class PlatformCompatDashboardTest { Preference enabledPreference = mDashboard.createPreferenceForChange(mContext, enabledChange, config); - SwitchPreference enabledSwitchPreference = (SwitchPreference) enabledPreference; + SwitchPreferenceCompat enabledSwitchPreference = (SwitchPreferenceCompat) enabledPreference; assertThat(enabledPreference.getSummary()).isEqualTo(mChanges[0].getName()); - assertThat(enabledPreference instanceof SwitchPreference).isTrue(); + assertThat(enabledPreference instanceof SwitchPreferenceCompat).isTrue(); assertThat(enabledSwitchPreference.isChecked()).isTrue(); assertThat(enabledSwitchPreference.isEnabled()).isTrue(); } - @Ignore("b/313591873") @Test public void createPreferenceForChange_defaultDisabledChange_createUncheckedEntry() { CompatibilityChangeInfo disabledChange = mChanges[1]; @@ -172,12 +172,12 @@ public class PlatformCompatDashboardTest { disabledChange, config); assertThat(disabledPreference.getSummary()).isEqualTo(mChanges[1].getName()); - SwitchPreference disabledSwitchPreference = (SwitchPreference) disabledPreference; + SwitchPreferenceCompat disabledSwitchPreference = + (SwitchPreferenceCompat) disabledPreference; assertThat(disabledSwitchPreference.isChecked()).isFalse(); assertThat(disabledSwitchPreference.isEnabled()).isTrue(); } - @Ignore("b/313591873") @Test public void createPreferenceForChange_cannotOverride_createDisabledEntry() throws RemoteException { @@ -191,15 +191,14 @@ public class PlatformCompatDashboardTest { Preference preference = mDashboard.createPreferenceForChange(mContext, enabledChange, config); - SwitchPreference switchPreference = (SwitchPreference) preference; + SwitchPreferenceCompat switchPreference = (SwitchPreferenceCompat) preference; assertThat(preference.getSummary()).isEqualTo(mChanges[0].getName()); - assertThat(preference instanceof SwitchPreference).isTrue(); + assertThat(preference instanceof SwitchPreferenceCompat).isTrue(); assertThat(switchPreference.isChecked()).isTrue(); assertThat(switchPreference.isEnabled()).isFalse(); } - @Ignore("b/313591873") @Test public void createChangeCategoryPreference_enabledAndDisabled_hasTitleAndEntries() { Set enabledChanges = new HashSet<>(); @@ -226,7 +225,7 @@ public class PlatformCompatDashboardTest { assertThat(category.getPreferenceCount()).isEqualTo(mChanges.length); for (int i = 0; i < mChanges.length; ++i) { Preference childPreference = category.getPreference(i); - assertThat(childPreference instanceof SwitchPreference).isTrue(); + assertThat(childPreference instanceof SwitchPreferenceCompat).isTrue(); } } } diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java index ba37c30389a..8445fe22c9f 100644 --- a/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java +++ b/tests/robotests/src/com/android/settings/network/telephony/MobileDataSliceTest.java @@ -114,7 +114,8 @@ public class MobileDataSliceTest { mMobileDataSlice.onNotifyChange(intent); - verify(mTelephonyManager).setDataEnabled(true); + verify(mTelephonyManager) + .setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER, true); } @Test @@ -126,7 +127,8 @@ public class MobileDataSliceTest { mMobileDataSlice.onNotifyChange(intent); - verify(mTelephonyManager).setDataEnabled(false); + verify(mTelephonyManager) + .setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER, false); } @Test @@ -138,7 +140,8 @@ public class MobileDataSliceTest { mMobileDataSlice.onNotifyChange(intent); - verify(mTelephonyManager, times(0)).setDataEnabled(true); + verify(mTelephonyManager, times(0)) + .setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER, true); } @Test diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModeBackendTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModeBackendTest.java index 247d68e4bfe..32bf9af3010 100644 --- a/tests/robotests/src/com/android/settings/notification/zen/ZenModeBackendTest.java +++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModeBackendTest.java @@ -16,9 +16,9 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -30,8 +30,6 @@ import android.database.Cursor; import android.provider.Settings; import android.service.notification.ZenModeConfig; -import com.android.settings.R; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -204,7 +202,11 @@ public class ZenModeBackendTest { mBackend.saveConversationSenders(CONVERSATION_SENDERS_NONE); ArgumentCaptor captor = ArgumentCaptor.forClass(Policy.class); - verify(mNotificationManager, times(1)).setNotificationPolicy(captor.capture()); + if (android.app.Flags.modesApi()) { + verify(mNotificationManager).setNotificationPolicy(captor.capture(), eq(true)); + } else { + verify(mNotificationManager).setNotificationPolicy(captor.capture()); + } Policy expected = new Policy( PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_ALARMS, @@ -228,7 +230,11 @@ public class ZenModeBackendTest { mBackend.saveConversationSenders(CONVERSATION_SENDERS_ANYONE); ArgumentCaptor captor = ArgumentCaptor.forClass(Policy.class); - verify(mNotificationManager, times(1)).setNotificationPolicy(captor.capture()); + if (android.app.Flags.modesApi()) { + verify(mNotificationManager).setNotificationPolicy(captor.capture(), eq(true)); + } else { + verify(mNotificationManager).setNotificationPolicy(captor.capture()); + } Policy expected = new Policy(PRIORITY_CATEGORY_CONVERSATIONS | PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_ALARMS, @@ -253,7 +259,11 @@ public class ZenModeBackendTest { mBackend.saveSenders(PRIORITY_CATEGORY_CALLS, PRIORITY_SENDERS_ANY); ArgumentCaptor captor = ArgumentCaptor.forClass(Policy.class); - verify(mNotificationManager, times(1)).setNotificationPolicy(captor.capture()); + if (android.app.Flags.modesApi()) { + verify(mNotificationManager).setNotificationPolicy(captor.capture(), eq(true)); + } else { + verify(mNotificationManager).setNotificationPolicy(captor.capture()); + } Policy expected = new Policy(PRIORITY_CATEGORY_CONVERSATIONS | PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_MESSAGES | PRIORITY_CATEGORY_ALARMS, diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModeSliceBuilderTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModeSliceBuilderTest.java index 71f896df7c9..3f9e4864a0c 100644 --- a/tests/robotests/src/com/android/settings/notification/zen/ZenModeSliceBuilderTest.java +++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModeSliceBuilderTest.java @@ -17,13 +17,18 @@ package com.android.settings.notification.zen; import static android.app.slice.Slice.EXTRA_TOGGLE_STATE; +import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; +import static android.provider.Settings.Global.ZEN_MODE_OFF; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + import android.app.NotificationManager; import android.content.Context; import android.content.Intent; -import android.provider.Settings; import androidx.slice.Slice; import androidx.slice.SliceMetadata; @@ -39,9 +44,12 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowApplication; import java.util.List; @@ -51,10 +59,17 @@ public class ZenModeSliceBuilderTest { private Context mContext; + @Mock + private NotificationManager mNm; + @Before public void setUp() { mContext = RuntimeEnvironment.application; + MockitoAnnotations.initMocks(this); + ShadowApplication shadowApplication = ShadowApplication.getInstance(); + shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm); + // Set-up specs for SliceMetadata. SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); } @@ -99,24 +114,27 @@ public class ZenModeSliceBuilderTest { public void handleUriChange_turnOn_zenModeTurnsOn() { final Intent intent = new Intent(); intent.putExtra(EXTRA_TOGGLE_STATE, true); - NotificationManager.from(mContext).setZenMode(Settings.Global.ZEN_MODE_OFF, null, ""); ZenModeSliceBuilder.handleUriChange(mContext, intent); - final int zenMode = NotificationManager.from(mContext).getZenMode(); - assertThat(zenMode).isEqualTo(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); + if (android.app.Flags.modesApi()) { + verify(mNm).setZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), any(), any(), eq(true)); + } else { + verify(mNm).setZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), any(), any()); + } } @Test public void handleUriChange_turnOff_zenModeTurnsOff() { final Intent intent = new Intent(); intent.putExtra(EXTRA_TOGGLE_STATE, false); - NotificationManager.from(mContext).setZenMode( - Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, ""); ZenModeSliceBuilder.handleUriChange(mContext, intent); - final int zenMode = NotificationManager.from(mContext).getZenMode(); - assertThat(zenMode).isEqualTo(Settings.Global.ZEN_MODE_OFF); + if (android.app.Flags.modesApi()) { + verify(mNm).setZenMode(eq(ZEN_MODE_OFF), any(), any(), eq(true)); + } else { + verify(mNm).setZenMode(eq(ZEN_MODE_OFF), any(), any()); + } } } diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenOnboardingActivityTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenOnboardingActivityTest.java index 257eaaf3a8e..01360fdd414 100644 --- a/tests/robotests/src/com/android/settings/notification/zen/ZenOnboardingActivityTest.java +++ b/tests/robotests/src/com/android/settings/notification/zen/ZenOnboardingActivityTest.java @@ -21,17 +21,19 @@ import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CA import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; import static com.android.settings.notification.zen.ZenOnboardingActivity.ALWAYS_SHOW_THRESHOLD; -import static com.android.settings.notification.zen.ZenOnboardingActivity - .PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME; +import static com.android.settings.notification.zen.ZenOnboardingActivity.PREF_KEY_SUGGESTION_FIRST_DISPLAY_TIME; import static com.android.settings.notification.zen.ZenOnboardingActivity.isSuggestionComplete; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.Flags; import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.content.Context; @@ -40,7 +42,6 @@ import android.provider.Settings; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.notification.zen.ZenOnboardingActivity; import com.android.settings.testutils.FakeFeatureFactory; import org.junit.Before; @@ -103,7 +104,11 @@ public class ZenOnboardingActivityTest { verify(mMetricsLogger).action(MetricsEvent.ACTION_ZEN_ONBOARDING_OK); ArgumentCaptor captor = ArgumentCaptor.forClass(Policy.class); - verify(mNm).setNotificationPolicy(captor.capture()); + if (android.app.Flags.modesApi()) { + verify(mNm).setNotificationPolicy(captor.capture(), eq(true)); + } else { + verify(mNm).setNotificationPolicy(captor.capture()); + } Policy actual = captor.getValue(); assertThat(actual.priorityCategories).isEqualTo(PRIORITY_CATEGORY_ALARMS @@ -123,7 +128,11 @@ public class ZenOnboardingActivityTest { mActivity.save(null); verify(mMetricsLogger).action(MetricsEvent.ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS); - verify(mNm, never()).setNotificationPolicy(any()); + if (Flags.modesApi()) { + verify(mNm, never()).setNotificationPolicy(any(), anyBoolean()); + } else { + verify(mNm, never()).setNotificationPolicy(any()); + } } @Test diff --git a/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java b/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java index f177c199cc6..87a798a2197 100644 --- a/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java +++ b/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java @@ -43,6 +43,7 @@ import android.widget.LinearLayout; import androidx.lifecycle.LiveData; import androidx.slice.Slice; +import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; import com.android.settings.panel.PanelSlicesAdapter.SliceRowViewHolder; @@ -50,14 +51,14 @@ import com.android.settings.testutils.FakeFeatureFactory; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; @@ -69,6 +70,8 @@ import java.util.Map; @RunWith(RobolectricTestRunner.class) @Config(shadows = PanelSlicesAdapterTest.ShadowLayoutInflater.class) public class PanelSlicesAdapterTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); private static LayoutInflater sLayoutInflater; @@ -81,8 +84,7 @@ public class PanelSlicesAdapterTest { @Before public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = ApplicationProvider.getApplicationContext(); mPanelFeatureProvider = spy(new PanelFeatureProviderImpl()); mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); @@ -104,8 +106,7 @@ public class PanelSlicesAdapterTest { private void addTestLiveData(Uri uri) { // Create a slice to return for the LiveData - final Slice slice = spy(new Slice()); - doReturn(uri).when(slice).getUri(); + final Slice slice = new Slice(); final LiveData liveData = mock(LiveData.class); when(liveData.getValue()).thenReturn(slice); mData.put(uri, liveData); @@ -126,7 +127,6 @@ public class PanelSlicesAdapterTest { /** * ViewHolder should load and set the action label correctly. */ - @Ignore("b/313576125") @Test public void setActionLabel_loadsActionLabel() { addTestLiveData(VOLUME_NOTIFICATION_URI); @@ -167,7 +167,6 @@ public class PanelSlicesAdapterTest { return foundLabel; } - @Ignore("b/313576125") @Test public void sizeOfAdapter_shouldNotExceedMaxNum() { for (int i = 0; i < MAX_NUM_OF_SLICES + 2; i++) { @@ -186,7 +185,6 @@ public class PanelSlicesAdapterTest { assertThat(adapter.getData().size()).isEqualTo(MAX_NUM_OF_SLICES); } - @Ignore("b/313576125") @Test public void mediaOutputIndicatorSlice_notSliderPanel_noSliderLayout() { addTestLiveData(MEDIA_OUTPUT_INDICATOR_SLICE_URI); @@ -203,7 +201,6 @@ public class PanelSlicesAdapterTest { assertThat(viewHolder.mSliceSliderLayout).isNull(); } - @Ignore("b/313576125") @Test public void onBindViewHolder_viewTypeSlider_verifyActionLabelSet() { addTestLiveData(VOLUME_NOTIFICATION_URI); diff --git a/tests/robotests/src/com/android/settings/security/SimLockPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/SimLockPreferenceControllerTest.java index f38cc4948d4..10e397c1b14 100644 --- a/tests/robotests/src/com/android/settings/security/SimLockPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/security/SimLockPreferenceControllerTest.java @@ -77,6 +77,7 @@ public class SimLockPreferenceControllerTest { ShadowApplication shadowApplication = ShadowApplication.getInstance(); shadowApplication.setSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE, mSubscriptionManager); + when(mSubscriptionManager.createForAllUserProfiles()).thenReturn(mSubscriptionManager); shadowApplication.setSystemService(Context.CARRIER_CONFIG_SERVICE, mCarrierManager); shadowApplication.setSystemService(Context.USER_SERVICE, mUserManager); shadowApplication.setSystemService(Context.TELEPHONY_SERVICE, mTelephonyManager); diff --git a/tests/robotests/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragmentTest.java b/tests/robotests/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragmentTest.java index ad60d06dc04..24b82b2fffb 100644 --- a/tests/robotests/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragmentTest.java +++ b/tests/robotests/src/com/android/settings/sim/EnableAutoDataSwitchDialogFragmentTest.java @@ -68,6 +68,7 @@ public class EnableAutoDataSwitchDialogFragmentTest doReturn(mContext).when(mFragment).getContext(); doReturn(mSubscriptionManager).when(mContext).getSystemService(SubscriptionManager.class); + doReturn(mSubscriptionManager).when(mSubscriptionManager).createForAllUserProfiles(); doReturn(mTelephonyManager).when(mContext).getSystemService(TelephonyManager.class); doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt()); doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java index dae17bc41e3..aa2961ce98b 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java @@ -31,7 +31,7 @@ import java.util.List; import java.util.Map; @Implements(AccountManager.class) -public class ShadowAccountManager { +public class ShadowAccountManager extends org.robolectric.shadows.ShadowAccountManager { private static final Map sAuthenticators = new HashMap<>(); private static final Map> sAccountsByUserId = new HashMap<>(); @@ -41,7 +41,8 @@ public class ShadowAccountManager { return sAuthenticators.values().toArray(new AuthenticatorDescription[sAuthenticators.size()]); } - public static void addAuthenticator(AuthenticatorDescription authenticator) { + @Override + public void addAuthenticator(AuthenticatorDescription authenticator) { sAuthenticators.put(authenticator.type, authenticator); } diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSecureSettings.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSecureSettings.java index f2099420d63..d7731484658 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSecureSettings.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSecureSettings.java @@ -16,6 +16,8 @@ package com.android.settings.testutils.shadow; +import static android.provider.Settings.DEFAULT_OVERRIDEABLE_BY_RESTORE; + import android.content.ContentResolver; import android.provider.Settings; @@ -24,12 +26,13 @@ import com.google.common.collect.Table; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import org.robolectric.shadows.ShadowSettings; import java.util.Map; import java.util.WeakHashMap; @Implements(Settings.Secure.class) -public class ShadowSecureSettings { +public class ShadowSecureSettings extends ShadowSettings.ShadowSecure { private static final Map> sUserDataMap = new WeakHashMap<>(); @@ -48,6 +51,16 @@ public class ShadowSecureSettings { } } + /** + * Same implementation as Settings.Secure because robolectric.ShadowSettings.ShadowSecure + * overrides this API. + */ + @Implementation + public static boolean putString(ContentResolver resolver, String name, String value) { + return putStringForUser(resolver, name, value, null, false, + resolver.getUserId(), DEFAULT_OVERRIDEABLE_BY_RESTORE); + } + @Implementation public static String getStringForUser(ContentResolver resolver, String name, int userHandle) { final Table userTable = getUserTable(resolver); @@ -56,6 +69,15 @@ public class ShadowSecureSettings { } } + /** + * Same implementation as Settings.Secure because robolectric.ShadowSettings.ShadowSecure + * overrides this API. + */ + @Implementation + public static boolean putInt(ContentResolver resolver, String name, int value) { + return putIntForUser(resolver, name, value, resolver.getUserId()); + } + @Implementation public static boolean putIntForUser(ContentResolver resolver, String name, int value, int userHandle) { @@ -66,6 +88,15 @@ public class ShadowSecureSettings { } } + /** + * Same implementation as Settings.Secure because robolectric.ShadowSettings.ShadowSecure + * overrides this API. + */ + @Implementation + public static int getInt(ContentResolver resolver, String name, int def) { + return getIntForUser(resolver, name, def, resolver.getUserId()); + } + @Implementation public static int getIntForUser(ContentResolver resolver, String name, int def, int userHandle) { diff --git a/tests/spa_unit/src/com/android/settings/spa/app/ResetAppPreferencesTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/ResetAppPreferencesTest.kt index ffd58313f1b..b63c28184c8 100644 --- a/tests/spa_unit/src/com/android/settings/spa/app/ResetAppPreferencesTest.kt +++ b/tests/spa_unit/src/com/android/settings/spa/app/ResetAppPreferencesTest.kt @@ -45,7 +45,7 @@ class ResetAppPreferencesTest { } private fun setResetAppPreferences() { - val fakeMoreOptionsScope = object : MoreOptionsScope { + val fakeMoreOptionsScope = object : MoreOptionsScope() { override fun dismiss() {} } composeTestRule.setContent { diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp index 327b6aad1c4..9d2d6865d07 100644 --- a/tests/unit/Android.bp +++ b/tests/unit/Android.bp @@ -32,6 +32,7 @@ android_test { "kotlinx_coroutines_test", "flag-junit", "Settings-testutils2", + "MediaDrmSettingsFlagsLib", // Don't add SettingsLib libraries here - you can use them directly as they are in the // instrumented Settings app. ], diff --git a/tests/unit/src/com/android/settings/development/widevine/ForceL3FallbackPreferenceControllerTest.java b/tests/unit/src/com/android/settings/development/widevine/ForceL3FallbackPreferenceControllerTest.java new file mode 100644 index 00000000000..f67a4af84fb --- /dev/null +++ b/tests/unit/src/com/android/settings/development/widevine/ForceL3FallbackPreferenceControllerTest.java @@ -0,0 +1,136 @@ +/* +* Copyright (C) 2023 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.development.widevine; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assume.assumeTrue; +import static org.junit.Assume.assumeNoException; + +import android.content.Context; +import android.media.MediaDrm; +import android.media.UnsupportedSchemeException; +import android.media.NotProvisionedException; +import android.sysprop.WidevineProperties; +import android.util.Log; +import android.content.Context; + +import com.android.settings.media_drm.Flags; +import android.platform.test.flag.junit.SetFlagsRule; + +import androidx.preference.SwitchPreference; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.UUID; + +@RunWith(AndroidJUnit4.class) +public class ForceL3FallbackPreferenceControllerTest { + + private static final String PREF_KEY = "force_l3_fallback"; + private static final UUID WIDEVINE_UUID = + new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL); + private static final String TAG = "ForceL3FallbackPreferenceControllerTest"; + + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private Context mContext; + private ForceL3FallbackPreferenceController mController; + private SwitchPreference mPreference; + + @Before + public void setUp() { + mContext = ApplicationProvider.getApplicationContext(); + mController = new ForceL3FallbackPreferenceController(mContext, PREF_KEY); + mPreference = new SwitchPreference(mContext); + WidevineProperties.forcel3_enabled(false); + } + + @Test + public void updateState_flagEnabled_checkPreference() { + mSetFlagsRule.enableFlags(Flags.FLAG_FORCE_L3_ENABLED); + mController.updateState(mPreference); + assertThat(mPreference.isEnabled()).isTrue(); + assertThat(mPreference.isChecked()).isFalse(); + assertThat(WidevineProperties.forcel3_enabled().orElse(false)).isFalse(); + + // Toggle to true + mController.setChecked(true); + mController.updateState(mPreference); + assertThat(WidevineProperties.forcel3_enabled().orElse(false)).isTrue(); + assertThat(mPreference.isEnabled()).isTrue(); + assertThat(mPreference.isChecked()).isTrue(); + + // Toggle to false + mController.setChecked(false); + mController.updateState(mPreference); + assertThat(WidevineProperties.forcel3_enabled().orElse(false)).isFalse(); + assertThat(mPreference.isEnabled()).isTrue(); + assertThat(mPreference.isChecked()).isFalse(); + + // Test flag rollback + mController.setChecked(true); + mController.updateState(mPreference); + assertThat(mPreference.isChecked()).isTrue(); + assertThat(WidevineProperties.forcel3_enabled().orElse(false)).isTrue(); + mSetFlagsRule.disableFlags(Flags.FLAG_FORCE_L3_ENABLED); + mController.updateState(mPreference); + assertThat(mPreference.isEnabled()).isFalse(); + assertThat(mPreference.isChecked()).isFalse(); + assertThat(WidevineProperties.forcel3_enabled().orElse(false)).isFalse(); + } + + @Test + public void updateState_flagDisabled_checkPreference() { + mSetFlagsRule.disableFlags(Flags.FLAG_FORCE_L3_ENABLED); + mController.updateState(mPreference); + assertThat(mPreference.isEnabled()).isFalse(); + } + + @Test + public void updateState_checkWidevine() throws Exception { + MediaDrm drm; + try { + drm = new MediaDrm(WIDEVINE_UUID); + assumeTrue(drm.getPropertyString("securityLevel").equals("L1")); + mSetFlagsRule.enableFlags(Flags.FLAG_FORCE_L3_ENABLED); + drm.close(); + } catch (UnsupportedSchemeException ex) { + assumeNoException(ex); + } + + // L3 enforced + mController.setChecked(true); + mController.updateState(mPreference); + assertThat(WidevineProperties.forcel3_enabled().orElse(false)).isTrue(); + assertThat(mPreference.isEnabled()).isTrue(); + assertThat(mPreference.isChecked()).isTrue(); + drm = new MediaDrm(WIDEVINE_UUID); + assertThat(drm.getPropertyString("securityLevel")).isEqualTo("L3"); + + // Switch back to L1 + mController.setChecked(false); + mController.updateState(mPreference); + drm.close(); + drm = new MediaDrm(WIDEVINE_UUID); + assertThat(drm.getPropertyString("securityLevel")).isEqualTo("L1"); + } +} diff --git a/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java b/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java index c23b53ed35a..947ba75db66 100644 --- a/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java @@ -148,24 +148,30 @@ public class MobileNetworkUtilsTest { public void setMobileDataEnabled_setEnabled_enabled() { MobileNetworkUtils.setMobileDataEnabled(mContext, SUB_ID_1, true, false); - verify(mTelephonyManager).setDataEnabled(true); - verify(mTelephonyManager2, never()).setDataEnabled(anyBoolean()); + verify(mTelephonyManager) + .setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER, true); + verify(mTelephonyManager2, never()) + .setDataEnabledForReason(anyInt(), anyBoolean()); } @Test public void setMobileDataEnabled_setDisabled_disabled() { MobileNetworkUtils.setMobileDataEnabled(mContext, SUB_ID_2, true, false); - verify(mTelephonyManager2).setDataEnabled(true); - verify(mTelephonyManager, never()).setDataEnabled(anyBoolean()); + verify(mTelephonyManager2) + .setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER, true); + verify(mTelephonyManager, never()) + .setDataEnabledForReason(anyInt(), anyBoolean()); } @Test public void setMobileDataEnabled_disableOtherSubscriptions() { MobileNetworkUtils.setMobileDataEnabled(mContext, SUB_ID_1, true, true); - verify(mTelephonyManager).setDataEnabled(true); - verify(mTelephonyManager2).setDataEnabled(false); + verify(mTelephonyManager) + .setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER, true); + verify(mTelephonyManager2) + .setDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER, false); } @Test